Cài Đặt
Thêm các phụ thuộc cần thiết:
cargo add --dev anchor-litesvm litesvm litesvm-utils
anchor-litesvm là gì?
Crate anchor-litesvm cung cấp cú pháp đơn giản hóa tương tự anchor-client
nhưng không có chi phí RPC. Nó đạt được giảm 78% mã nguồn so với LiteSVM
thuần túy trong khi vẫn duy trì tính an toàn kiểu với các kiểu Anchor.
AnchorContext
- Ngữ cảnh kiểm thử tương thích với môi trường production
- Các mẫu API giống với anchor-client
- Quản lý instance LiteSVM, payer và chương trình
- Thực thi các lệnh không cần chi phí RPC
Program API - Xây dựng lệnh theo kiểu fluent - Xử lý tài khoản và tham số an toàn kiểu - Cú pháp anchor-client quen thuộc
Giải Tuần Tự Tài Khoản - Lấy và giải tuần tự các tài khoản Anchor - Xử lý discriminator tự động - Hỗ trợ PDA và các bố cục tùy chỉnh
Phân Tích Sự Kiện
- Phân tích sự kiện từ nhật ký giao dịch
- Xác nhận phát ra sự kiện
- Giải tuần tự sự kiện an toàn kiểu
Ví Dụ Nhanh
Với Anchor 1.0, sử dụng declare_program! để tạo các kiểu client từ IDL của
chương trình. Macro này tạo ra các module client::accounts::* và
client::args::* để xây dựng lệnh an toàn kiểu:
use anchor_litesvm::AnchorLiteSVM;use anchor_litesvm::{AssertionHelpers, TestHelpers};use anchor_lang::system_program;use solana_sdk::signature::{read_keypair_file, Signer};// Generate client types from your program's IDLanchor_lang::declare_program!(my_program);#[test]fn test_anchor_program() {// One-line setup — reads program keypair for the correct IDlet program_keypair = read_keypair_file("target/deploy/my_program-keypair.json").unwrap();let mut ctx = AnchorLiteSVM::build_with_program(program_keypair.pubkey(),include_bytes!("../target/deploy/my_program.so"),);// Create a funded account via TestHelpers on ctx.svmlet user = ctx.svm.create_funded_account(10_000_000_000).unwrap();// Derive PDAlet seed: u64 = 42;let pda = ctx.svm.get_pda(&[b"user", user.pubkey().as_ref(), &seed.to_le_bytes()],&program_keypair.pubkey(),);// Build instruction using generated client typeslet ix = ctx.program().accounts(my_program::client::accounts::Initialize {user: user.pubkey(),user_account: pda,system_program: system_program::ID,}).args(my_program::client::args::Initialize {seed,name: "test".to_string(),}).instruction().unwrap();// Execute and assert in one chainctx.execute_instruction(ix, &[&user]).unwrap().assert_success();// Fetch and deserialize the accountlet account: my_program::MyAccount = ctx.get_account(&pda).unwrap();assert_eq!(account.name, "test");}
declare_program!(my_program) đọc IDL từ target/idl/my_program.json tại
thời điểm biên dịch và tạo ra các module client::accounts::* và
client::args::*. Điều này yêu cầu phải build chương trình của bạn trước.
So sánh: Raw LiteSVM và anchor-litesvm
Trước (Raw LiteSVM)
use litesvm::LiteSVM;use solana_keypair::Keypair;use solana_signer::Signer;use solana_program::instruction::{AccountMeta, Instruction};use solana_message::Message;use solana_transaction::Transaction;let mut svm = LiteSVM::new();svm.add_program(program_id, program_bytes).unwrap();let payer = Keypair::new();svm.airdrop(&payer.pubkey(), 10_000_000_000).unwrap();// Manually compute 8-byte discriminatorlet discriminator = {let mut hasher = sha2::Sha256::new();hasher.update(b"global:initialize");let result = hasher.finalize();result[..8].to_vec()};// Manually serialize args and build instructionlet mut data = discriminator;data.extend_from_slice(&borsh::to_vec(&args).unwrap());let accounts = vec![AccountMeta::new(user.pubkey(), true),AccountMeta::new(user_pda, false),AccountMeta::new_readonly(system_program::id(), false),];let ix = Instruction::new_with_bytes(program_id, &data, accounts);let tx = Transaction::new_signed_with_payer(&[ix],Some(&payer.pubkey()),&[&payer],svm.latest_blockhash(),);svm.send_transaction(tx).unwrap();// Manually deserialize with discriminator skiplet account_data = svm.get_account(&pda).unwrap().data;let account: UserAccount = UserAccount::try_deserialize(&mut &account_data[8..]).unwrap();
Sau (anchor-litesvm)
use anchor_litesvm::AnchorLiteSVM;anchor_lang::declare_program!(my_program);let mut ctx = AnchorLiteSVM::build_with_program(program_id, program_bytes);let user = ctx.svm.create_funded_account(10_000_000_000).unwrap();let ix = ctx.program().accounts(my_program::client::accounts::Initialize {user: user.pubkey(),user_account: user_pda,system_program: anchor_lang::system_program::ID,}).args(my_program::client::args::Initialize { name: "test".to_string() }).instruction().unwrap();ctx.execute_instruction(ix, &[&user]).unwrap().assert_success();let account: my_program::UserAccount = ctx.get_account(&user_pda).unwrap();
Các thành phần chính
AnchorLiteSVM Builder
| Phương thức | Mô tả |
|---|---|
new() | Tạo một builder instance mới |
with_payer(keypair) | Đặt keypair người thanh toán tùy chỉnh |
deploy_program(id, bytes) | Thêm một chương trình để triển khai |
build() | Xây dựng AnchorContext |
build_with_program(id, bytes) | Tiện ích cho chương trình đơn lẻ |
build_with_programs(programs) | Triển khai nhiều chương trình |
AnchorContext
| Phương thức | Mô tả |
|---|---|
svm | Truy cập trực tiếp vào instance LiteSVM bên dưới (trường public) |
program_id | ID của chương trình (trường public) |
program() | Trả về Program để xây dựng lệnh |
payer() | Lấy keypair người thanh toán |
execute_instruction(ix, signers) | Thực thi một lệnh đơn lẻ |
execute_instructions(ixs, signers) | Thực thi nhiều lệnh trong một giao dịch |
send_and_confirm_transaction(&tx) | Gửi một giao dịch thô |
get_account<T>(pubkey) | Tìm nạp và giải tuần tự hóa một tài khoản Anchor |
get_account_unchecked<T>(pubkey) | Tìm nạp mà không kiểm tra discriminator |
create_funded_account(lamports) | Tạo và nạp tiền cho một keypair mới |
airdrop(pubkey, lamports) | Airdrop SOL vào một địa chỉ |
latest_blockhash() | Lấy blockhash hiện tại |
account_exists(pubkey) | Kiểm tra xem một tài khoản có tồn tại không |
deploy_program(id, bytes) | Triển khai thêm một chương trình (qua ProgramTestExt) |
Program
| Phương thức | Mô tả |
|---|---|
accounts(accounts) | Đặt các tài khoản lệnh (bất kỳ kiểu ToAccountMetas nào) |
args(args) | Đặt các đối số lệnh (bất kỳ kiểu InstructionData nào) |
instruction() | Xây dựng Instruction cuối cùng |
id() | Lấy ID của chương trình |
ctx.svm — TestHelpers & AssertionHelpers
ctx.svm là một trường LiteSVM công khai với các trait TestHelpers và
AssertionHelpers có sẵn thông qua litesvm-utils:
| Phương thức | Mô tả |
|---|---|
ctx.svm.create_funded_account(lamports) | Tạo và nạp tiền cho một keypair |
ctx.svm.create_token_mint(authority, decimals) | Tạo một token mint SPL |
ctx.svm.create_associated_token_account(mint, owner) | Tạo một ATA |
ctx.svm.mint_to(mint, token_account, authority, amount) | Mint token |
ctx.svm.get_pda(seeds, program_id) | Lấy địa chỉ PDA |
ctx.svm.get_pda_with_bump(seeds, program_id) | Lấy PDA kèm bump seed |
ctx.svm.assert_token_balance(token_account, expected) | Kiểm tra số dư token |
ctx.svm.assert_account_closed(pubkey) | Kiểm tra tài khoản đã bị đóng |
ctx.svm.assert_sol_balance(pubkey, expected) | Kiểm tra số dư SOL |
Khắc phục sự cố
Lỗi thường gặp
| Lỗi | Nguyên nhân | Giải pháp |
|---|---|---|
AccountNotFound | Tài khoản không tồn tại | Đảm bảo tài khoản đã được tạo trước khi truy xuất |
DiscriminatorMismatch | Sai loại tài khoản | Xác minh bạn đang sử dụng đúng struct tài khoản |
DeserializationError | Dữ liệu tài khoản không hợp lệ | Kiểm tra tài khoản đã được khởi tạo đúng cách |
| No programs added | Đã gọi build() mà không có deploy_program() | Thêm ít nhất một chương trình trước khi build |
| Missing client types | declare_program! chưa được gọi | Chạy anchor build trước để tạo IDL, sau đó gọi declare_program! |
Is this page helpful?