Demonstruje użycie warpToSlot do testowania logiki programu zależnej od czasu.
Podstawowa manipulacja zegarem
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 accessclient.svm.withSysvars();// Check initial clockconst 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 1000client.svm.warpToSlot(1000n);const afterWarp = client.svm.getClock();console.log("\nAfter warpToSlot(1000):");console.log(" Slot:", afterWarp.slot);console.log(" Epoch:", afterWarp.epoch);// Warp furtherclient.svm.warpToSlot(100000n);const afterWarp2 = client.svm.getClock();console.log("\nAfter warpToSlot(100000):");console.log(" Slot:", afterWarp2.slot);console.log(" Epoch:", afterWarp2.epoch);
Testowanie logiki zablokowanej czasowo
Przykładowy wzorzec testowania funkcjonalności zablokowanej czasowo:
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 payerclient.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; // discriminatorview.setBigUint64(1, unlockSlot, true); // unlock_slotview.setBigUint64(9, lockedAmount, true); // amountconst 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 failconsole.log("Withdrawal attempt: EXPECTED TO FAIL (too early)");// Test 2: Warp to after unlock slotconsole.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 succeedconsole.log("Withdrawal attempt: EXPECTED TO SUCCEED (after unlock)");// Verify vault stateconst updatedVault = client.svm.getAccount(vaultAddress);if (updatedVault.exists) {console.log("\nVault balance:", updatedVault.lamports);}
Odczytywanie harmonogramu epoch
Możesz odczytać harmonogram epoch, aby zrozumieć relację slot/epoch w klastrze:
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 przesuwa pole slot zegara, ale nie aktualizuje automatycznie
pola epoch ani unixTimestamp. Użyj setClock, aby mieć pełną kontrolę nad
polami zegara.
Ręczna manipulacja zegarem
Gdy Twój program odczytuje epoch lub unix_timestamp z sysvaru Clock, użyj
setClock, aby ustawić te pola bezpośrednio:
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 backconst 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); // 50000nconsole.log("Epoch:", after.epoch); // 5nconsole.log("Timestamp:", after.unixTimestamp); // 1700000000n
To odzwierciedla wzorzec Rust set_sysvar(&clock). Używaj warpToSlot do prostego
przesuwania slot, a setClock gdy potrzebujesz kontroli nad epoch lub znacznikiem czasu.
Przypadki użycia
Manipulacja czasem jest przydatna do testowania:
| Scenariusz | Podejście |
|---|---|
| Nabywanie tokenów (vesting) | Przesuń poza próg/kamienie milowe vestingu |
| Zakończenia aukcji | Przesuń poza slot zakończenia aukcji |
| Nagrody za stakowanie | Użyj setClock, aby ustawić epoch |
| Wypłaty zablokowane czasowo | Przesuń poza slot odblokowania |
| Ograniczanie częstotliwości | Przesuń między dozwolonymi interwałami |
| Wygasające zlecenia | Przesuń poza datę wygaśnięcia zlecenia |
Pamiętaj, że warpToSlot zmienia tylko slot. Znacznik czasu unix może nie
aktualizować się proporcjonalnie w zależności od implementacji SVM.
Kluczowe informacje
- Włącz Sysvary: Wywołaj
withSysvars()przed użyciem metod zegara - Przesuwanie do przodu: Użyj
warpToSlot(slot), aby przesunąć slot - Pełna kontrola: Użyj
setClock, gdy chcesz ustawićepoch,unixTimestamplub inne pola zegara - Odczyt zegara: Użyj
getClock(), aby odczytać bieżący slot, epoch i znacznik czasu - Wzorzec testowania: Testuj przed i po granicach czasowych
Is this page helpful?