Runtime Surfpool cung cấp ba hàm trợ giúp du hành thời gian. Mỗi hàm di chuyển
đồng hồ cục bộ đến một mục tiêu tuyệt đối (không phải độ lệch tương đối) và trả
về EpochInfo đã được cập nhật để các bài kiểm thử có thể xác nhận rằng runtime
đã thực sự đến thời điểm được yêu cầu.
| Hàm trợ giúp | Mục tiêu | Trả về |
|---|---|---|
time_travel_to_slot / timeTravelToSlot | Số slot tuyệt đối | EpochInfo với absolute_slot mới |
time_travel_to_epoch / timeTravelToEpoch | Số epoch tuyệt đối | EpochInfo với epoch mới |
time_travel_to_timestamp / timeTravelToTimestamp | Unix timestamp tính bằng mili giây | EpochInfo phản ánh slot tương ứng |
Chỉ tiến về phía trước
Du hành thời gian chỉ có thể di chuyển đồng hồ về phía trước. Mục tiêu trong quá khứ sẽ bị
từ chối thay vì bị bỏ qua — các hàm trợ giúp Rust trả về Err và các hàm trợ giúp JS
sẽ throw. Thông báo lỗi sẽ nêu rõ đơn vị nào bị lùi về quá khứ, ví dụ
Cannot travel to past slot: target=1000, current=2000.
Nhảy Đến Một 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);
Nhảy Đến Một Epoch
let info = cheats.time_travel_to_epoch(420)?;assert_eq!(info.epoch, 420);
Nhảy Đến Một Unix Timestamp
Truyền dấu thời gian theo mili giây kể từ Unix epoch — cùng đơn vị với
Date.now() của JavaScript — không phải giây. Runtime sẽ tính toán slot gần nhất
tại dấu thời gian đó.
// 2030-01-01T00:00:00Zlet info = cheats.time_travel_to_timestamp(1_893_456_000_000)?;
Đồng hồ báo cáo theo giây, không phải mili giây
Mọi dấu thời gian bạn đọc lại từ runtime đều tính bằng giây — bao gồm
unix_timestamp của sysvar Clock on-chain, và
ClockValue được mang theo bởi
sự kiện systemClockUpdated. Nếu truyền trực tiếp một trong các giá trị đó vào
hàm trợ giúp du hành thời gian sẽ dẫn đến một thời điểm vào đầu năm 1970, khiến lệnh gọi bị
từ chối do là mục tiêu trong quá khứ. Hãy nhân với 1000 trước.
// 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);
Tạm Dừng Và Tiếp Tục Đồng Hồ
Du hành thời gian nhảy đến một mục tiêu; tạm dừng sẽ ngăn đồng hồ tiến lên hoàn toàn.
surfnet_pauseClock dừng việc tạo slot và tiến trình thời gian cho đến khi
surfnet_resumeClock chạy — hãy dùng khi bài kiểm thử cần slot và
dấu thời gian giữ nguyên trong suốt nhiều lệnh kiểm tra.
Cả Rust SDK lẫn lớp Surfnet trong @solana/surfpool đều không bọc hai
cheatcode này. Hãy gọi chúng thông qua
Kit plugin, hoặc trực tiếp qua 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();
Cả hai cheatcode đều trả về một EpochInfo — trạng thái đồng hồ tại thời điểm
tạm dừng, và sau khi tiếp tục. Lưu ý hai điều mà cấu trúc đó không mang theo:
- Không có dấu thời gian.
EpochInfokhông có trường thời gian. Hãy đọc thời gian Unix được mô phỏng từ sysvarClockthay thế: dùnggetAccountInfotrênSysvarC1ock11111111111111111111111111111111với encodingjsonParsed— một lần nữa, tính bằng giây. - Không có cờ tạm dừng. Không có phương thức RPC nào báo cáo liệu đồng hồ có đang
tạm dừng hay không. Từ các SDK, hãy theo dõi
sự kiện
clockUpdate, sự kiện này kích hoạt kèm theoclockCommandbất cứ khi nào lệnh tạm dừng, tiếp tục, hoặc thay đổi khoảng thời gian chạy. Nếu không, hãy tự theo dõi trạng thái trong bài kiểm thử của bạn.
Các Mẫu Phổ Biến
Kiểm Thử Lockup Hoặc Cửa Sổ Vesting
Ví dụ dưới đây chỉ là phác thảo — assertWithdrawFails và
assertWithdrawSucceeds là các placeholder cho bất kỳ hàm trợ giúp phía client
nào mà bộ kiểm thử của bạn sử dụng để xác nhận hành vi 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();
Thực Hiện Kịch Bản Đa Epoch
Các slot trung gian bị bỏ qua
Dịch chuyển thời gian nhảy thẳng đến đích — di chuyển từ epoch 1 đến epoch 5
sẽ bỏ qua các slot ở giữa. Nếu chương trình của bạn cần mỗi ranh giới epoch
trung gian phải kích hoạt (ví dụ: để ghi nhận phần thưởng theo epoch), hãy gọi
time_travel_to_epoch mỗi epoch một lần với các giao dịch cần thiết ở giữa.
for epoch in 2..=5 {cheats.time_travel_to_epoch(epoch)?;surfnet.rpc_client().send_transaction(&claim_rewards_tx)?;}
Cấu Trúc EpochInfo
Cả hai SDK đều trả về một đối tượng có dạng EpochInfo với các trường sau:
| Trường | Rust | JS |
|---|---|---|
| Slot tuyệt đối | absolute_slot: u64 | absoluteSlot: number |
| Slot trong epoch | slot_index: u64 | slotIndex: number |
| Số slot mỗi epoch | slots_in_epoch: u64 | slotsInEpoch: number |
| Số epoch | epoch: u64 | epoch: number |
| Chiều cao khối | block_height: u64 | blockHeight: number |
| Số lượng giao dịch | transaction_count: Option<u64> | transactionCount?: number |
Is this page helpful?