Środowisko uruchomieniowe Surfpool udostępnia trzy pomocniki podróży w czasie.
Każdy z nich przesuwa lokalny zegar do bezwzględnego celu (nie względnego
przesunięcia) i zwraca zaktualizowany EpochInfo, dzięki czemu testy mogą
potwierdzić, że środowisko uruchomieniowe rzeczywiście osiągnęło żądany czas.
| Pomocnik | Cel | Zwraca |
|---|---|---|
time_travel_to_slot / timeTravelToSlot | Bezwzględny numer slot | EpochInfo z nowym absolute_slot |
time_travel_to_epoch / timeTravelToEpoch | Bezwzględny numer epoch | EpochInfo z nowym epoch |
time_travel_to_timestamp / timeTravelToTimestamp | Znacznik czasu Unix w milisekundach | EpochInfo odzwierciedlający implikowany slot |
Tylko do przodu
Podróż w czasie może przesunąć zegar tylko do przodu. Cel w przeszłości jest
odrzucany, a nie ignorowany — helpery Rust zwracają Err, a helpery JS
zgłaszają wyjątek. Komunikat wskazuje jednostkę, która cofnęła się w czasie, na przykład
Cannot travel to past slot: target=1000, current=2000.
Przeskocz do slot
use surfpool_sdk::Surfnet;let surfnet = Surfnet::start().await?;let cheats = surfnet.cheatcodes();let info = cheats.time_travel_to_slot(1_000_000)?;assert!(info.absolute_slot >= 1_000_000);
Przeskocz do epoch
let info = cheats.time_travel_to_epoch(420)?;assert_eq!(info.epoch, 420);
Przeskocz do znacznika czasu Unix
Przekaż znacznik czasu w milisekundach od epoki Unix — tej samej jednostce co
JavaScript's Date.now() — nie w sekundach. Środowisko uruchomieniowe oblicza najbliższy slot
dla tego znacznika czasu.
// 2030-01-01T00:00:00Zlet info = cheats.time_travel_to_timestamp(1_893_456_000_000)?;
Zegar podaje sekundy, nie milisekundy
Każdy znacznik czasu odczytany ze środowiska uruchomieniowego jest wyrażony w sekundach —
unix_timestamp zmiennej systemowej Clock w łańcuchu bloków oraz
ClockValue przesyłany przez
zdarzenie systemClockUpdated. Bezpośrednie przekazanie jednej z tych wartości do
helpera podróży w czasie spowoduje wskazanie momentu z początku 1970 roku, dlatego wywołanie
zostanie odrzucone jako cel w przeszłości. Najpierw pomnóż przez 1000.
// WRONG — `unixTimestamp` is in seconds, so this is a past target.surfnet.timeTravelToTimestamp(clock.unixTimestamp + 3600);// RIGHT — convert to milliseconds.surfnet.timeTravelToTimestamp((clock.unixTimestamp + 3600) * 1000);
Wstrzymaj i wznów zegar
Podróż w czasie skacze do celu; wstrzymanie całkowicie zatrzymuje zegar.
surfnet_pauseClock wstrzymuje produkcję slot i upływ czasu, dopóki
nie zostanie uruchomione surfnet_resumeClock — używaj tego, gdy test wymaga,
aby slot i znacznik czasu pozostały niezmienione przez kilka asercji.
Ani Rust SDK, ani klasa Surfnet z @solana/surfpool nie opakowują tych
dwóch cheatcode'ów. Wywołuj je przez
wtyczkę Kit lub bezpośrednio przez JSON-RPC.
const paused = await client.cheatcodes.pauseClock().send();// Nothing advances until the clock is resumed, so this is the only thing that// moves the slot.await client.cheatcodes.timeTravel({ absoluteSlot: paused.absoluteSlot + 1_000n }).send();await client.cheatcodes.resumeClock().send();
Oba cheatcode'y zwracają EpochInfo — stan zegara w momencie
wstrzymania oraz po wznowieniu. Zwróć uwagę na dwie rzeczy, których ta struktura nie zawiera:
- Brak znacznika czasu.
EpochInfonie posiada pola czasu. Odczytaj symulowany czas Unix ze zmiennej systemowejClock: użyjgetAccountInfonaSysvarC1ock11111111111111111111111111111111z kodowaniemjsonParsed— ponownie, w sekundach. - Brak flagi wstrzymania. Żadna metoda RPC nie informuje, czy zegar jest aktualnie
wstrzymany. W SDK obserwuj
zdarzenie
clockUpdate, które jest wyzwalane zclockCommandprzy każdym wstrzymaniu, wznowieniu lub zmianie interwału. W przeciwnym razie śledź stan samodzielnie w swoim teście.
Typowe wzorce
Testowanie blokady lub okna nabywania uprawnień
Poniższy przykład to szkic — assertWithdrawFails i assertWithdrawSucceeds są
symbolami zastępczymi dla dowolnych pomocników po stronie klienta używanych
przez zestaw testów do weryfikacji zachowania RPC.
import { Surfnet } from "@solana/surfpool";const surfnet = Surfnet.start();const beneficiary = Surfnet.newKeypair();// 1. Set up a vesting account that unlocks at slot 1,000,000.surfnet.setAccount(/* ...lockup program state... */);// 2. Verify withdrawal fails before unlock.await assertWithdrawFails(surfnet.rpcUrl, beneficiary);// 3. Travel past the unlock slot.surfnet.timeTravelToSlot(1_000_001);// 4. Verify withdrawal succeeds.await assertWithdrawSucceeds(surfnet.rpcUrl, beneficiary);surfnet.stop();
Symuluj Scenariusz Wielu Epoch
Pośrednie slot są pomijane
Podróż w czasie skacze bezpośrednio do celu — przejście z epoch 1 do epoch 5
pomija slot pomiędzy nimi. Jeśli Twój program wymaga, aby każda pośrednia
granica epoch została wyzwolona (na przykład w celu naliczenia nagród za
epoch), wywołaj time_travel_to_epoch raz na epoch z wymaganymi transakcjami
pomiędzy wywołaniami.
for epoch in 2..=5 {cheats.time_travel_to_epoch(epoch)?;surfnet.rpc_client().send_transaction(&claim_rewards_tx)?;}
Struktura EpochInfo
Oba SDK zwracają obiekt w kształcie EpochInfo z następującymi polami:
| Pole | Rust | JS |
|---|---|---|
| Bezwzględny slot | absolute_slot: u64 | absoluteSlot: number |
| slot w epoch | slot_index: u64 | slotIndex: number |
| slot na epoch | slots_in_epoch: u64 | slotsInEpoch: number |
| Numer epoch | epoch: u64 | epoch: number |
| Wysokość bloku | block_height: u64 | blockHeight: number |
| Liczba transakcji | transaction_count: Option<u64> | transactionCount?: number |
Is this page helpful?