Du Hành Thời Gian

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úpMục tiêuTrả về
time_travel_to_slot / timeTravelToSlotSố slot tuyệt đốiEpochInfo với absolute_slot mới
time_travel_to_epoch / timeTravelToEpochSố epoch tuyệt đốiEpochInfo với epoch mới
time_travel_to_timestamp / timeTravelToTimestampUnix timestamp tính bằng mili giâyEpochInfo 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:00Z
let 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. EpochInfo không có trường thời gian. Hãy đọc thời gian Unix được mô phỏng từ sysvar Clock thay thế: dùng getAccountInfo trên SysvarC1ock11111111111111111111111111111111 với encoding jsonParsed — 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 theo clockCommand bấ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 — assertWithdrawFailsassertWithdrawSucceeds 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ườngRustJS
Slot tuyệt đốiabsolute_slot: u64absoluteSlot: number
Slot trong epochslot_index: u64slotIndex: number
Số slot mỗi epochslots_in_epoch: u64slotsInEpoch: number
Số epochepoch: u64epoch: number
Chiều cao khốiblock_height: u64blockHeight: number
Số lượng giao dịchtransaction_count: Option<u64>transactionCount?: number

Is this page helpful?

Mục lục

Chỉnh sửa trang