Additional Cratesanchor-litesvm
Quick Start
Learn how to use anchor-litesvm for testing Anchor programs with simplified syntax
Installation
Make sure you have all the needed dependencies:
cargo add --dev anchor-litesvm litesvm solana-sdkWhat is anchor-litesvm?
The anchor-litesvm crate provides a simplified syntax similar to anchor-client but without RPC overhead. It achieves 78% code reduction compared to raw LiteSVM while maintaining type safety with Anchor types.
AnchorContext
- Production-compatible test context
- Same API patterns as anchor-client
- Manages LiteSVM instance, payer, and program
- Execute instructions without RPC overhead
Program API
- Fluent instruction building
- Type-safe account and argument handling
- Familiar anchor-client syntax
Account Deserialization
- Fetch and deserialize Anchor accounts
- Automatic discriminator handling
- Support for PDAs and custom layouts
Event Parsing
- Parse events from transaction logs
- Assert event emission
- Type-safe event deserialization
Quick Example
Here's a complete example showing the power of anchor-litesvm:
use anchor_litesvm::{AnchorLiteSVM, AnchorContext};
use anchor_lang::prelude::*;
use solana_sdk::{
native_token::LAMPORTS_PER_SOL,
signature::Signer,
};
// Your Anchor program's ID
declare_id!("YourProgramId11111111111111111111111111111");
#[test]
fn test_anchor_program() {
// Build test context with your program
let ctx: AnchorContext = AnchorLiteSVM::new()
.deploy_program(id(), include_bytes!("../target/deploy/your_program.so"))
.build();
// Create a funded account
let user = ctx.create_funded_account(10 * LAMPORTS_PER_SOL);
// Build and execute an instruction using familiar anchor-client syntax
let ix = ctx.program()
.accounts(Initialize {
user: user.pubkey(),
system_program: solana_sdk::system_program::id(),
})
.args(instruction::Initialize {
name: "test".to_string()
})
.instruction()
.unwrap();
// Execute the instruction
ctx.execute_instruction(ix, &[&user]).unwrap();
// Fetch and deserialize the account
let account: UserAccount = ctx.get_account(&user_pda).unwrap();
assert_eq!(account.name, "test");
}Comparison: Raw LiteSVM vs anchor-litesvm
Before (Raw LiteSVM)
use litesvm::LiteSVM;
use solana_sdk::{
instruction::{AccountMeta, Instruction},
message::Message,
transaction::Transaction,
};
let mut svm = LiteSVM::new();
svm.add_program(program_id, program_bytes);
let payer = Keypair::new();
svm.airdrop(&payer.pubkey(), 10 * LAMPORTS_PER_SOL).unwrap();
// Manually build instruction data with discriminator
let mut data = Vec::new();
data.extend_from_slice(&anchor_lang::idl::DISCRIMINATOR);
data.extend_from_slice(&args.try_to_vec().unwrap());
let accounts = vec![
AccountMeta::new(user, true),
AccountMeta::new_readonly(system_program::id(), false),
];
let ix = Instruction::new_with_bytes(program_id, &data, accounts);
let message = Message::new(&[ix], Some(&payer.pubkey()));
let tx = Transaction::new(&[&payer], message, svm.latest_blockhash());
svm.send_transaction(tx).unwrap();
// Manually deserialize with discriminator handling
let account_data = svm.get_account(&pda).unwrap().data;
let account: UserAccount = UserAccount::try_deserialize(&mut &account_data[8..]).unwrap();After (anchor-litesvm)
use anchor_litesvm::{AnchorLiteSVM, AnchorContext};
let ctx = AnchorLiteSVM::build_with_program(program_id, program_bytes);
let user = ctx.create_funded_account(10 * LAMPORTS_PER_SOL);
let ix = ctx.program()
.accounts(Initialize { user: user.pubkey(), system_program: system_program::id() })
.args(instruction::Initialize { name: "test".to_string() })
.instruction()
.unwrap();
ctx.execute_instruction(ix, &[&user]).unwrap();
let account: UserAccount = ctx.get_account(&pda).unwrap();Key Components
AnchorLiteSVM Builder
| Method | Description |
|---|---|
new() | Creates a new builder instance |
with_payer(keypair) | Sets a custom payer keypair |
deploy_program(id, bytes) | Adds a program to deploy |
build() | Builds the AnchorContext |
build_with_program(id, bytes) | Convenience for single program |
build_with_programs(programs) | Deploy multiple programs |
AnchorContext
| Method | Description |
|---|---|
program() | Returns Program for instruction building |
execute_instruction(ix, signers) | Execute a single instruction |
execute_instructions(ixs, signers) | Execute multiple instructions |
get_account<T>(pubkey) | Fetch and deserialize account |
create_funded_account(lamports) | Create a funded keypair |
payer() | Get the payer keypair |
airdrop(pubkey, lamports) | Airdrop SOL to an address |
Program
| Method | Description |
|---|---|
accounts(accounts) | Set instruction accounts |
args(args) | Set instruction arguments |
instruction() | Build the final instruction |
id() | Get the program ID |
Troubleshooting
Common Errors
| Error | Cause | Solution |
|---|---|---|
AccountNotFound | Account doesn't exist | Ensure account is created before fetching |
DiscriminatorMismatch | Wrong account type | Verify you're using the correct account struct |
DeserializationError | Invalid account data | Check account was initialized correctly |
| No programs added | Called build() without deploy_program() | Add at least one program before building |