Pruebas Basadas en el Tiempo

Demuestra el uso de warpToSlot para probar lógica de programas dependiente del tiempo.

Manipulación Básica del Reloj

import { createClient, generateKeyPairSigner } from "@solana/kit";
import { litesvm } from "@solana/kit-plugin-litesvm";
import { signer } from "@solana/kit-plugin-signer";
const mySigner = await generateKeyPairSigner();
const client = createClient().use(signer(mySigner)).use(litesvm());
// Enable sysvars for clock access
client.svm.withSysvars();
// Check initial clock
const initialClock = client.svm.getClock();
console.log("Initial state:");
console.log(" Slot:", initialClock.slot);
console.log(" Epoch:", initialClock.epoch);
console.log(" Unix timestamp:", initialClock.unixTimestamp);
// Warp to slot 1000
client.svm.warpToSlot(1000n);
const afterWarp = client.svm.getClock();
console.log("\nAfter warpToSlot(1000):");
console.log(" Slot:", afterWarp.slot);
console.log(" Epoch:", afterWarp.epoch);
// Warp further
client.svm.warpToSlot(100000n);
const afterWarp2 = client.svm.getClock();
console.log("\nAfter warpToSlot(100000):");
console.log(" Slot:", afterWarp2.slot);
console.log(" Epoch:", afterWarp2.epoch);

Prueba de Lógica Bloqueada por Tiempo

Patrón de ejemplo para probar funcionalidades bloqueadas por tiempo:

import {
createClient,
address,
generateKeyPairSigner,
lamports
} from "@solana/kit";
import { litesvm } from "@solana/kit-plugin-litesvm";
import { signer } from "@solana/kit-plugin-signer";
const mySigner = await generateKeyPairSigner();
const client = createClient().use(signer(mySigner)).use(litesvm());
client.svm.withSigverify(false).withBlockhashCheck(false).withSysvars();
// Fund payer
client.svm.airdrop(client.payer.address, lamports(10_000_000_000n));
// Set up a time-locked vault account
// Structure: [u8 discriminator, u64 unlock_slot, u64 amount]
const unlockSlot = 10000n;
const lockedAmount = 5_000_000_000n;
const vaultData = new Uint8Array(1 + 8 + 8);
const view = new DataView(vaultData.buffer);
vaultData[0] = 0x01; // discriminator
view.setBigUint64(1, unlockSlot, true); // unlock_slot
view.setBigUint64(9, lockedAmount, true); // amount
const programId = address("TimeLockedVault11111111111111111111111"); // replace or generateKeyPairSigner()
const vaultAddress = address("Vault111111111111111111111111111"); // replace or generateKeyPairSigner()
const minBalance = client.svm.minimumBalanceForRentExemption(
BigInt(vaultData.length)
);
client.svm.setAccount({
address: vaultAddress,
data: vaultData,
executable: false,
lamports: lamports(minBalance + lockedAmount),
programAddress: programId,
space: BigInt(vaultData.length)
});
console.log("Vault created with unlock slot:", unlockSlot);
console.log("Locked amount:", Number(lockedAmount) / 1e9, "SOL");
// Test 1: Try to withdraw before unlock (should fail)
console.log("\n--- Test 1: Before unlock ---");
const currentClock = client.svm.getClock();
console.log("Current slot:", currentClock.slot);
// In a real test, you would:
// 1. Build a withdraw instruction
// 2. Send it and expect it to fail
console.log("Withdrawal attempt: EXPECTED TO FAIL (too early)");
// Test 2: Warp to after unlock slot
console.log("\n--- Test 2: After unlock ---");
client.svm.warpToSlot(unlockSlot + 100n);
const newClock = client.svm.getClock();
console.log("Current slot:", newClock.slot);
// In a real test:
// 1. Build a withdraw instruction
// 2. Send it and expect it to succeed
console.log("Withdrawal attempt: EXPECTED TO SUCCEED (after unlock)");
// Verify vault state
const updatedVault = client.svm.getAccount(vaultAddress);
if (updatedVault.exists) {
console.log("\nVault balance:", updatedVault.lamports);
}

Lectura del Calendario de epoch

Puedes leer el calendario de epoch para entender la relación slot/epoch en el clúster:

import { createClient, generateKeyPairSigner } from "@solana/kit";
import { litesvm } from "@solana/kit-plugin-litesvm";
import { signer } from "@solana/kit-plugin-signer";
const mySigner = await generateKeyPairSigner();
const client = createClient().use(signer(mySigner)).use(litesvm());
client.svm.withSysvars();
const epochSchedule = client.svm.getEpochSchedule();
console.log("Slots per epoch:", epochSchedule.slotsPerEpoch);
console.log("First normal epoch:", epochSchedule.firstNormalEpoch);
console.log("First normal slot:", epochSchedule.firstNormalSlot);

warpToSlot avanza el campo slot del reloj, pero no actualiza automáticamente epoch ni unixTimestamp. Usa setClock para tener control total sobre los campos del reloj.

Manipulación Manual del Reloj

Cuando tu programa lee epoch o unix_timestamp del sysvar Clock, usa setClock para establecer esos campos directamente:

import { createClient, generateKeyPairSigner } from "@solana/kit";
import { litesvm } from "@solana/kit-plugin-litesvm";
import { signer } from "@solana/kit-plugin-signer";
const mySigner = await generateKeyPairSigner();
const client = createClient().use(signer(mySigner)).use(litesvm());
client.svm.withSysvars();
// Get clock, mutate, write back
const clock = client.svm.getClock();
clock.slot = 50000n;
clock.epoch = 5n;
clock.unixTimestamp = 1700000000n;
client.svm.setClock(clock);
const after = client.svm.getClock();
console.log("Slot:", after.slot); // 50000n
console.log("Epoch:", after.epoch); // 5n
console.log("Timestamp:", after.unixTimestamp); // 1700000000n

Esto refleja el patrón set_sysvar(&clock) de Rust. Usa warpToSlot para el avance simple de slot, y setClock cuando necesites controlar el epoch o la marca de tiempo.

Casos de Uso

La manipulación del tiempo es útil para probar:

EscenarioEnfoque
Vesting de tokensAvanzar más allá del umbral/hitos de vesting
Fin de subastasAvanzar más allá del slot de fin de subasta
Recompensas de stakingUsar setClock para establecer el epoch
Retiros bloqueados por tiempoAvanzar más allá del slot de desbloqueo
Limitación de velocidadAvanzar entre intervalos permitidos
Órdenes con vencimientoAvanzar más allá de la expiración de la orden

Ten en cuenta que warpToSlot solo cambia el slot. La marca de tiempo unix puede no actualizarse proporcionalmente según la implementación del SVM.

Puntos Clave

  1. Habilitar Sysvars: Llama a withSysvars() antes de usar los métodos del reloj
  2. Avanzar: Usa warpToSlot(slot) para adelantar el slot
  3. Control Total: Usa setClock cuando necesites establecer epoch, unixTimestamp u otros campos del reloj
  4. Leer el Reloj: Usa getClock() para leer el slot, epoch y marca de tiempo actuales
  5. Patrón de Prueba: Prueba antes y después de los límites de tiempo

Is this page helpful?

Tabla de Contenidos

Editar Página