インストール
必要な依存関係を追加します:
cargo add --dev anchor-litesvm litesvm litesvm-utils
anchor-litesvm とは?
anchor-litesvm クレートは、RPCのオーバーヘッドなしに
anchor-client に似た簡略化された構文を提供します。Anchor の型で型安全性を維持しながら、生の LiteSVM と比較して
コードを78%削減します。
AnchorContext
- 本番環境対応のテストコンテキスト
- anchor-client と同じ API パターン
- LiteSVM インスタンス、ペイヤー、プログラムを管理
- RPC オーバーヘッドなしで instructions を実行
プログラム API - 流れるようなインストラクション構築 - 型安全なアカウントと引数の処理 - 使い慣れた anchor-client の構文
アカウントのデシリアライズ - Anchor アカウントの取得とデシリアライズ - ディスクリミネーターの自動処理 - PDA およびカスタムレイアウトのサポート
イベントのパース
- トランザクションログからイベントをパース
- イベント発行のアサート
- 型安全なイベントのデシリアライズ
クイックサンプル
Anchor 1.0 では、declare_program!
を使用してプログラムの IDL からクライアント型を生成します。このマクロは、型安全な instructions 構築のための
client::accounts::* および client::args::* モジュールを作成します:
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) はコンパイル時に target/idl/my_program.json
から IDL を読み込み、client::accounts::* および client::args::*
モジュールを生成します。これにはプログラムを事前にビルドする必要があります。
比較:Raw LiteSVM と anchor-litesvm
変更前(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();
変更後(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();
主要コンポーネント
AnchorLiteSVM ビルダー
| メソッド | 説明 |
|---|---|
new() | 新しいビルダーインスタンスを作成 |
with_payer(keypair) | カスタムペイヤー keypair を設定 |
deploy_program(id, bytes) | デプロイするプログラムを追加 |
build() | AnchorContext をビルド |
build_with_program(id, bytes) | 単一プログラム向けの便利メソッド |
build_with_programs(programs) | 複数プログラムをデプロイ |
AnchorContext
| メソッド | 説明 |
|---|---|
svm | 基盤となる LiteSVM インスタンスへの直接アクセス(パブリックフィールド) |
program_id | プログラム ID(パブリックフィールド) |
program() | instructions ビルド用の Program を返す |
payer() | ペイヤー Keypair を取得 |
execute_instruction(ix, signers) | 単一の instruction を実行 |
execute_instructions(ixs, signers) | 1 つのトランザクションで複数の instructions を実行 |
send_and_confirm_transaction(&tx) | 生のトランザクションを送信 |
get_account<T>(pubkey) | Anchor アカウントをフェッチしてデシリアライズ |
get_account_unchecked<T>(pubkey) | ディスクリミネーターチェックなしでフェッチ |
create_funded_account(lamports) | 新しい keypair を作成してSOLをエアドロップ |
airdrop(pubkey, lamports) | アドレスに SOL をエアドロップ |
latest_blockhash() | 現在のブロックハッシュを取得 |
account_exists(pubkey) | アカウントの存在を確認 |
deploy_program(id, bytes) | 追加プログラムをデプロイ(ProgramTestExt 経由) |
Program
| メソッド | 説明 |
|---|---|
accounts(accounts) | instruction アカウントを設定(任意の ToAccountMetas 型) |
args(args) | instruction 引数を設定(任意の InstructionData 型) |
instruction() | 最終的な Instruction をビルド |
id() | プログラム ID を取得 |
ctx.svm — TestHelpers と AssertionHelpers
ctx.svm は、LiteSVM の public フィールドであり、litesvm-utils を通じて
TestHelpers および AssertionHelpers トレイトが利用可能です:
| メソッド | 説明 |
|---|---|
ctx.svm.create_funded_account(lamports) | keypair を作成して資金を追加 |
ctx.svm.create_token_mint(authority, decimals) | SPL トークンミントを作成 |
ctx.svm.create_associated_token_account(mint, owner) | ATA を作成 |
ctx.svm.mint_to(mint, token_account, authority, amount) | トークンをミント |
ctx.svm.get_pda(seeds, program_id) | PDA アドレスを導出 |
ctx.svm.get_pda_with_bump(seeds, program_id) | bump seed を使用して PDA を導出 |
ctx.svm.assert_token_balance(token_account, expected) | トークン残高をアサート |
ctx.svm.assert_account_closed(pubkey) | アカウントがクローズされたことをアサート |
ctx.svm.assert_sol_balance(pubkey, expected) | SOL 残高をアサート |
トラブルシューティング
よくあるエラー
| エラー | 原因 | 解決策 |
|---|---|---|
AccountNotFound | アカウントが存在しない | フェッチ前にアカウントが作成されていることを確認してください |
DiscriminatorMismatch | アカウントの種類が異なる | 正しいアカウント構造体を使用しているか確認してください |
DeserializationError | アカウントデータが無効 | アカウントが正しく初期化されているか確認してください |
| No programs added | deploy_program() なしで build() を呼び出した | ビルド前に少なくとも1つのプログラムを追加してください |
| Missing client types | declare_program! が呼び出されていない | まず anchor build を実行して IDL を生成し、その後 declare_program! を呼び出してください |
Is this page helpful?