安装
请确保您已安装所有必要的依赖项:
cargo add --dev litesvm litesvm-loader solana-keypair solana-signer
如果您的测试直接调用已部署的程序,请同时添加测试所使用的 Solana 指令和交易 crate:
cargo add --dev solana-instruction solana-message solana-transaction
什么是 litesvm-loader?
litesvm-loader
crate 提供了一系列辅助工具,用于在 LiteSVM 中通过 BPF 可升级加载器部署程序。当您的测试需要加载器所有的 program
account、program data account 或升级权限行为,而非直接通过
svm.add_program(...) 插入程序时,请使用该 crate。
可升级部署
- 创建加载器缓冲账户
- 分块写入程序字节
- 使用 BPF 可升级加载器部署最终的 program account
- 使用提供的程序 keypair 作为程序 ID
升级权限管理 - 更改已部署程序的升级权限 - 支持分配新的权限方 - 支持传入
None 以使程序不可变
真实加载器状态
- 模拟程序在链上所见的相同加载器账户模型
- 允许测试检查 program account 和 program data account
- 有助于发现直接插入程序时所隐藏的错误
对于大多数测试,svm.add_program(program_id, program_bytes) 仍然是
加载程序最快、最简单的方式。当
加载器账户布局或升级权限是您需要测试的内容时,请使用 litesvm-loader。
快速示例
以下是一个完整示例,通过可升级加载器部署程序然后轮换其权限:
use litesvm::LiteSVM;use litesvm_loader::{deploy_upgradeable_program, set_upgrade_authority};use solana_keypair::Keypair;use solana_signer::Signer;#[test]fn test_upgradeable_deployment() {let mut svm = LiteSVM::new();let payer = Keypair::new();svm.airdrop(&payer.pubkey(), 10_000_000_000).unwrap();// Use the keypair that should own the program ID.// For Anchor programs, this is usually target/deploy/<program>-keypair.json.let program = Keypair::new();let program_bytes = include_bytes!("../target/deploy/my_program.so");deploy_upgradeable_program(&mut svm, &payer, &program, program_bytes).unwrap();let program_account = svm.get_account(&program.pubkey()).unwrap();assert!(program_account.executable);let new_authority = Keypair::new();set_upgrade_authority(&mut svm,&payer,&program.pubkey(),&payer,Some(&new_authority.pubkey()),).unwrap();}
选择程序 keypair
deploy_upgradeable_program 使用 program_kp
参数作为程序地址。如果您的程序声明了固定 ID,请加载生成的部署 keypair 而不是创建随机 keypair:
use solana_keypair::read_keypair_file;let program = read_keypair_file("target/deploy/my_program-keypair.json").unwrap();deploy_upgradeable_program(&mut svm, &payer, &program, program_bytes).unwrap();
调用已部署的程序
部署后,以与调用任何 LiteSVM 加载程序相同的方式调用该程序。为您的程序构建指令,签署交易,并通过同一个
LiteSVM 实例发送:
use solana_instruction::Instruction;use solana_message::Message;use solana_transaction::Transaction;let instruction = Instruction::new_with_bytes(program.pubkey(),&[], // instruction data for your programvec![], // account metas for your program);let message = Message::new(&[instruction], Some(&payer.pubkey()));let tx = Transaction::new(&[&payer], message, svm.latest_blockhash());svm.send_transaction(tx).unwrap();
关键组件
deploy_upgradeable_program
| 参数 | 描述 |
|---|---|
svm | 接收已部署程序的可变 LiteSVM 实例 |
payer_kp | 手续费支付方及初始升级权限 |
program_kp | 公钥作为程序 ID 的 keypair |
program_bytes | 已编译的 SBF 程序字节,通常来自 target/deploy/*.so |
deploy_upgradeable_program
创建一个加载器缓冲区,以 512 字节块写入程序字节,并部署程序,为未来升级预留空间。
set_upgrade_authority
| 参数 | 描述 |
|---|---|
svm | 包含已部署程序的可变 LiteSVM 实例 |
from_keypair | 交易的手续费支付方及签名权限 |
program_address | 需要更改权限的程序 ID |
current_authority_keypair | 当前升级权限 keypair |
new_authority_address | 新权限地址,或 None 以使程序不可变 |
在当前的辅助函数实现中,生成的交易由 from_keypair
签名。在更改升级权限时,请将当前权限作为 from_keypair
传入,或保持付款方与当前权限使用同一 keypair。
常见工作流
使用已声明的程序 ID 部署
use solana_keypair::read_keypair_file;let program = read_keypair_file("target/deploy/my_program-keypair.json").unwrap();let program_bytes = include_bytes!("../target/deploy/my_program.so");deploy_upgradeable_program(&mut svm, &payer, &program, program_bytes).unwrap();
使程序不可变
set_upgrade_authority(&mut svm,&payer,&program.pubkey(),&payer,None,).unwrap();
故障排查
常见错误
| 错误 | 原因 | 解决方案 |
|---|---|---|
ProgramAccountNotFound 或针对错误 ID 的指令失败 | 部署时使用了随机的 Keypair,而程序期望使用已声明的 ID | 读取 target/deploy/<program>-keypair.json 并将该 keypair 传入 deploy_upgradeable_program |
InsufficientFunds | 付款方没有足够的 lamport 用于加载器缓冲区和 program account | 在部署前空投更多 lamport |
更改权限时出现 MissingRequiredSignature | 当前权限未对交易进行签名 | 将当前权限作为 from_keypair 传入,或将付款方与当前权限保持为同一 keypair |
| 程序部署速度低于预期 | 加载器部署通过真实的加载器指令逐字节写入 | 当不需要加载器状态或升级权限行为时,请使用 svm.add_program(...) |
Is this page helpful?