Tijdgebaseerd Testen

Demonstreert het gebruik van WarpToSlot en SetClock om tijdafhankelijke programmalogica te testen.

Basis Klokmanipulatie

package mytest
import (
"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)
}

Tijdvergrendelde Logica Testen

package mytest
import (
"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] = 0x01
binary.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
}

Het Epoch-schema Uitlezen

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 zet het Slot-veld van de klok vooruit, maar werkt niet automatisch Epoch of UnixTimestamp bij. Gebruik SetClock voor volledige controle over de klokvelden.

Handmatige Klokmanipulatie

Wanneer uw programma Epoch of UnixTimestamp uit de Clock-sysvar leest, stelt u die velden rechtstreeks in met 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_000
c.Epoch = 5
c.UnixTimestamp = 1_700_000_000
if 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) // 50000
t.Logf("epoch: %d", after.Epoch) // 5
t.Logf("unix: %d", after.UnixTimestamp) // 1700000000
}

Dit weerspiegelt het Rust-patroon set_sysvar(&clock). Gebruik WarpToSlot voor eenvoudige slot-vooruitgang, en SetClock wanneer u epoch- of tijdstempelcontrole nodig heeft.

Toepassingen

Tijdmanipulatie is nuttig voor het testen van:

ScenarioAanpak
Token vestingSpring voorbij de vesting-grens / mijlpalen
VeilingafsluitingenSpring voorbij het eind-slot van de veiling
StakingrewardsGebruik SetClock om epoch in te stellen
Tijdvergrendelde opnamesSpring voorbij het ontgrendel-slot
SnelheidsbeperkingSpring tussen toegestane intervallen
Verlopen ordersSpring voorbij de vervaldatum van de order

WarpToSlot wijzigt alleen de slot. De unix-tijdstempel wordt mogelijk niet proportioneel bijgewerkt — gebruik SetClock als uw programma UnixTimestamp uitleest.

Kernpunten

  1. Standaard sysvars zijn actief - litesvm.New() geeft een handle terug met geïnitialiseerde sysvars; roep SetSysvars() aan om naar de standaardwaarden te resetten als u ze hebt gewijzigd.
  2. Vooruitspoelen - WarpToSlot(slot) zet uitsluitend het slot-veld vooruit.
  3. Volledige controle - SetClock(Clock{...}) stelt u in staat Epoch, UnixTimestamp en de overige velden in te stellen.
  4. Uitlezen - svm.Clock() leest de huidige waarden uit.
  5. Testpatroon - test vóór en na de tijdsgrens; verwacht een fout aan de ene kant en succes aan de andere kant.

Is this page helpful?

Inhoudsopgave

Pagina Bewerken
© 2026 Solana Foundation. Alle rechten voorbehouden.