Documentazione SolanaLiteSVMRustCrate Aggiuntivianchor-litesvm

Guida Rapida

Installazione

Aggiungi le dipendenze necessarie:

cargo add --dev anchor-litesvm litesvm litesvm-utils

Cos'è anchor-litesvm?

Il crate anchor-litesvm fornisce una sintassi semplificata simile ad anchor-client ma senza il sovraccarico RPC. Ottiene una riduzione del codice del 78% rispetto a LiteSVM grezzo, mantenendo la sicurezza dei tipi con i tipi di Anchor.

AnchorContext

  • Contesto di test compatibile con la produzione
  • Stessi pattern API di anchor-client
  • Gestisce l'istanza LiteSVM, il pagante e il programma
  • Esegui istruzioni senza sovraccarico RPC

API del Programma - Costruzione fluente delle istruzioni - Gestione type-safe di account e argomenti - Sintassi familiare di anchor-client

Deserializzazione degli Account - Recupera e deserializza gli account Anchor - Gestione automatica del discriminatore - Supporto per PDA e layout personalizzati

Analisi degli Eventi

  • Analizza gli eventi dai log delle transazioni
  • Verifica l'emissione degli eventi
  • Deserializzazione degli eventi type-safe

Esempio Rapido

Con Anchor 1.0, usa declare_program! per generare i tipi client dall'IDL del tuo programma. Questa macro crea i moduli client::accounts::* e client::args::* per la costruzione type-safe delle istruzioni:

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 IDL
anchor_lang::declare_program!(my_program);
#[test]
fn test_anchor_program() {
// One-line setup — reads program keypair for the correct ID
let 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.svm
let user = ctx.svm.create_funded_account(10_000_000_000).unwrap();
// Derive PDA
let 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 types
let 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 chain
ctx.execute_instruction(ix, &[&user])
.unwrap()
.assert_success();
// Fetch and deserialize the account
let account: my_program::MyAccount = ctx.get_account(&pda).unwrap();
assert_eq!(account.name, "test");
}

declare_program!(my_program) legge l'IDL da target/idl/my_program.json al momento della compilazione e genera i moduli client::accounts::* e client::args::*. Ciò richiede la compilazione preliminare del programma.

Confronto: Raw LiteSVM vs anchor-litesvm

Prima (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 discriminator
let 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 instruction
let 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 skip
let account_data = svm.get_account(&pda).unwrap().data;
let account: UserAccount = UserAccount::try_deserialize(
&mut &account_data[8..]
).unwrap();

Dopo (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();

Componenti Principali

AnchorLiteSVM Builder

MetodoDescrizione
new()Crea una nuova istanza del builder
with_payer(keypair)Imposta un keypair personalizzato per il pagante
deploy_program(id, bytes)Aggiunge un programma da distribuire
build()Costruisce l'AnchorContext
build_with_program(id, bytes)Metodo pratico per un singolo programma
build_with_programs(programs)Distribuisce più programmi

AnchorContext

MetodoDescrizione
svmAccesso diretto all'istanza sottostante LiteSVM (campo pubblico)
program_idL'ID del programma (campo pubblico)
program()Restituisce Program per la costruzione delle istruzioni
payer()Ottieni il keypair del pagante
execute_instruction(ix, signers)Esegue una singola istruzione
execute_instructions(ixs, signers)Esegue più istruzioni in un'unica transazione
send_and_confirm_transaction(&tx)Invia una transazione grezza
get_account<T>(pubkey)Recupera e deserializza un account Anchor
get_account_unchecked<T>(pubkey)Recupera senza verifica del discriminatore
create_funded_account(lamports)Crea e finanzia un nuovo keypair
airdrop(pubkey, lamports)Invia SOL tramite airdrop a un indirizzo
latest_blockhash()Ottieni il blockhash corrente
account_exists(pubkey)Verifica se un account esiste
deploy_program(id, bytes)Distribuisce un programma aggiuntivo (tramite ProgramTestExt)

Program

MetodoDescrizione
accounts(accounts)Imposta gli account dell'istruzione (qualsiasi tipo ToAccountMetas)
args(args)Imposta gli argomenti dell'istruzione (qualsiasi tipo InstructionData)
instruction()Costruisce l'Instruction finale
id()Ottieni l'ID del programma

ctx.svm — TestHelpers & AssertionHelpers

ctx.svm è un campo pubblico LiteSVM con i trait TestHelpers e AssertionHelpers disponibili tramite litesvm-utils:

MetodoDescrizione
ctx.svm.create_funded_account(lamports)Crea e finanzia un keypair
ctx.svm.create_token_mint(authority, decimals)Crea un mint di token SPL
ctx.svm.create_associated_token_account(mint, owner)Crea un ATA
ctx.svm.mint_to(mint, token_account, authority, amount)Conia token
ctx.svm.get_pda(seeds, program_id)Deriva un indirizzo PDA
ctx.svm.get_pda_with_bump(seeds, program_id)Deriva un PDA con bump seed
ctx.svm.assert_token_balance(token_account, expected)Verifica il saldo dei token
ctx.svm.assert_account_closed(pubkey)Verifica che l'account sia stato chiuso
ctx.svm.assert_sol_balance(pubkey, expected)Verifica il saldo SOL

Risoluzione dei problemi

Errori comuni

ErroreCausaSoluzione
AccountNotFoundL'account non esisteAssicurarsi che l'account sia creato prima del recupero
DiscriminatorMismatchTipo di account erratoVerificare di utilizzare la struct dell'account corretta
DeserializationErrorDati dell'account non validiVerificare che l'account sia stato inizializzato correttamente
Nessun programma aggiuntobuild() chiamato senza deploy_program()Aggiungere almeno un programma prima della compilazione
Tipi client mancantideclare_program! non chiamatoEseguire prima anchor build per generare l'IDL, poi chiamare declare_program!

Is this page helpful?

Indice dei contenuti

Modifica pagina
© 2026 Solana Foundation. Tutti i diritti riservati.