Solana Rust合约获取Unix时间戳BpfClock单元测试报错问询
报错原因
UnsupportedSysvar错误来源于Solana本地单元测试运行时的限制:BpfClock::get()依赖链上BPF运行时的sysvar全局接口,默认单元测试环境没有实现该能力,只有实际链上执行环境或者带模拟链的集成测试环境支持该调用。
解决方案
方案1:官方推荐低消耗实现(兼容单元测试)
Solana官方更推荐将Clock sysvar作为指令的传入账户使用,相比内部调用BpfClock::get()计算单元消耗还要低10%左右,同时方便单元测试时手动注入模拟时间。
- 合约逻辑调整
// 指令处理函数参数新增clock账户 pub fn process_withdraw(accounts: &[AccountInfo], amount: u64) -> ProgramResult { let clock_account = next_account_info(accounts)?; // 校验账户为Clock sysvar合法地址 assert_eq!(clock_account.key, &sysvar::clock::id()); let clock = Clock::from_account_info(clock_account)?; let current_timestamp: i64 = clock.unix_timestamp; // 后续业务逻辑 }
- 单元测试模拟时间
use solana_program::clock::Clock; use solana_program::sysvar::Sysvar; use solana_program_test::AccountSharedData; #[test] fn test_withdraw() { // 构造自定义时间的Clock实例 let mut mock_clock = Clock::default(); mock_clock.unix_timestamp = 1620000000; // 按需设置测试用时间戳 // 生成模拟Clock账户传入指令账户列表即可 let clock_account = AccountSharedData::new_data( 1, &mock_clock, &solana_program::sysvar::id(), ).unwrap(); // 剩余测试逻辑 }
方案2:最小改动兼容实现
如果不想调整现有指令的账户结构,可通过特性开关区分运行环境,链上走低消耗的BpfClock调用,测试环境走模拟时间:
let current_timestamp: i64 = { #[cfg(not(test))] { let clock = BpfClock::get()?; clock.unix_timestamp } #[cfg(test)] { // 测试环境返回固定模拟时间,也可通过全局变量动态调整测试时间 1620000000 } };
链上环境下BpfClock方案的计算单元消耗仅为SystemTime方案的1/3左右,完全满足低消耗要求。
内容的提问来源于stack exchange,提问作者Gnoose
相关产品推荐
相关产品推荐

