Demonstriert die Verwendung von WarpToSlot und SetClock zum Testen zeitabhängiger Programmlogik.
Grundlegende Uhrzeitmanipulation
package mytestimport ("testing"litesvm "github.com/LiteSVM/litesvm-go")func TestClockWarp(t *testing.T) {svm, err := litesvm.New()if err != nil {t.Fatal(err)}defer svm.Close()// Read the initial clock.initial, err := svm.Clock()if err != nil {t.Fatal(err)}t.Logf("initial state:")t.Logf(" slot: %d", initial.Slot)t.Logf(" epoch: %d", initial.Epoch)t.Logf(" unix timestamp: %d", initial.UnixTimestamp)// Warp to slot 1_000.if err := svm.WarpToSlot(1_000); err != nil {t.Fatal(err)}after, err := svm.Clock()if err != nil {t.Fatal(err)}t.Logf("after warpToSlot(1000):")t.Logf(" slot: %d", after.Slot)t.Logf(" epoch: %d", after.Epoch)// Warp further.if err := svm.WarpToSlot(100_000); err != nil {t.Fatal(err)}after2, err := svm.Clock()if err != nil {t.Fatal(err)}t.Logf("after warpToSlot(100000):")t.Logf(" slot: %d", after2.Slot)t.Logf(" epoch: %d", after2.Epoch)}
Testen zeitgesperrter Logik
package mytestimport ("encoding/binary""testing"litesvm "github.com/LiteSVM/litesvm-go"solana "github.com/gagliardetto/solana-go")func TestTimeLockedVault(t *testing.T) {svm, err := litesvm.New()if err != nil {t.Fatal(err)}defer svm.Close()// Setters are infallible in practice; discarding the return keeps the// example readable._ = svm.SetSigverify(false)_ = svm.SetBlockhashCheck(false)_ = svm.SetSysvars()// Fund a payer.priv, err := solana.NewRandomPrivateKey()if err != nil {t.Fatal(err)}payer := priv.PublicKey()if err := svm.Airdrop(payer, 10_000_000_000); err != nil {t.Fatal(err)}// Set up a time-locked vault account.// Layout: [u8 discriminator, u64 unlock_slot, u64 amount]const unlockSlot = uint64(10_000)const lockedAmount = uint64(5_000_000_000)vaultData := make([]byte, 1+8+8)vaultData[0] = 0x01binary.LittleEndian.PutUint64(vaultData[1:9], unlockSlot)binary.LittleEndian.PutUint64(vaultData[9:17], lockedAmount)programID := solana.NewWallet().PublicKey()vaultAddr := solana.NewWallet().PublicKey()minBalance, err := svm.MinimumBalanceForRentExemption(len(vaultData))if err != nil {t.Fatal(err)}acct, err := litesvm.NewAccount(minBalance+lockedAmount, vaultData, programID, false, 0)if err != nil {t.Fatal(err)}defer acct.Close()if err := svm.SetAccount(vaultAddr, acct); err != nil {t.Fatal(err)}t.Logf("vault created: unlock slot=%d, locked=%.3f SOL",unlockSlot, float64(lockedAmount)/1e9)// --- Test 1: Before unlock ---cBefore, err := svm.Clock()if err != nil {t.Fatal(err)}t.Logf("current slot: %d", cBefore.Slot)// In a real test you would build a withdraw instruction here and assert// it fails because the current slot < unlock_slot.t.Log("withdrawal attempt: EXPECTED TO FAIL (too early)")// --- Test 2: After unlock ---if err := svm.WarpToSlot(unlockSlot + 100); err != nil {t.Fatal(err)}cAfter, err := svm.Clock()if err != nil {t.Fatal(err)}t.Logf("current slot: %d", cAfter.Slot)// Build and submit the withdraw instruction; assert it succeeds.t.Log("withdrawal attempt: EXPECTED TO SUCCEED (after unlock)")// Verify vault state.updated := svm.GetAccount(vaultAddr)if updated == nil {t.Fatal("vault missing")}defer updated.Close()t.Logf("vault balance: %d lamports", updated.Lamports())_ = payer // payer would be referenced when building the withdraw ix}
Den epoch-Zeitplan auslesen
func TestReadEpochSchedule(t *testing.T) {svm, err := litesvm.New()if err != nil {t.Fatal(err)}defer svm.Close()es, err := svm.EpochSchedule()if err != nil {t.Fatal(err)}t.Logf("slots per epoch: %d", es.SlotsPerEpoch)t.Logf("first normal epoch: %d", es.FirstNormalEpoch)t.Logf("first normal slot: %d", es.FirstNormalSlot)}
WarpToSlot setzt das Slot-Feld der Uhr vor, aktualisiert jedoch nicht automatisch Epoch oder UnixTimestamp. Verwenden Sie SetClock für die vollständige Kontrolle über die Uhrfelder.
Manuelle Uhrzeitmanipulation
Wenn Ihr Programm Epoch oder UnixTimestamp aus dem Clock-Sysvar liest, setzen Sie
diese Felder direkt mit SetClock:
func TestSetClock(t *testing.T) {svm, err := litesvm.New()if err != nil {t.Fatal(err)}defer svm.Close()c, err := svm.Clock()if err != nil {t.Fatal(err)}c.Slot = 50_000c.Epoch = 5c.UnixTimestamp = 1_700_000_000if err := svm.SetClock(c); err != nil {t.Fatal(err)}after, err := svm.Clock()if err != nil {t.Fatal(err)}t.Logf("slot: %d", after.Slot) // 50000t.Logf("epoch: %d", after.Epoch) // 5t.Logf("unix: %d", after.UnixTimestamp) // 1700000000}
Dies spiegelt das Rust-Muster set_sysvar(&clock) wider. Verwenden Sie WarpToSlot für einfaches
slot-Vorspulen und SetClock, wenn Sie epoch- oder Zeitstempelkontrolle benötigen.
Anwendungsfälle
Zeitmanipulation ist nützlich zum Testen von:
| Szenario | Vorgehensweise |
|---|---|
| Token-Vesting | Über Vesting-Cliff / Meilensteine hinaus vorspulen |
| Auktionsenden | Über den Auktions-End-slot hinaus vorspulen |
| Staking-Belohnungen | SetClock verwenden, um epoch zu setzen |
| Zeitgesperrte Auszahlungen | Über den Entsperr-slot hinaus vorspulen |
| Ratenbegrenzung | Zwischen erlaubten Intervallen vorspulen |
| Ablaufende Aufträge | Über den Auftragsablauf hinaus vorspulen |
WarpToSlot ändert nur den slot. Der Unix-Zeitstempel wird möglicherweise nicht proportional aktualisiert – verwenden Sie SetClock, wenn Ihr Programm UnixTimestamp liest.
Wichtige Punkte
- Standard-Sysvars sind aktiv –
litesvm.New()gibt ein Handle mit initialisierten Sysvars zurück; rufen SieSetSysvars()auf, um auf die Standardwerte zurückzusetzen, falls Sie diese geändert haben. - Vorwärts spulen –
WarpToSlot(slot)setzt nur das slot-Feld vor. - Volle Kontrolle –
SetClock(Clock{...})ermöglicht das Setzen vonEpoch,UnixTimestampund den anderen Feldern. - Auslesen –
svm.Clock()liest die aktuellen Werte. - Testmuster – Testen Sie vor und nach der Zeitgrenze; erwarten Sie einen Fehler auf einer Seite und Erfolg auf der anderen.
Is this page helpful?