Installation
Fügen Sie die benötigten Abhängigkeiten hinzu:
cargo add --dev anchor-litesvm litesvm litesvm-utils
Was ist anchor-litesvm?
Das anchor-litesvm-Crate bietet eine vereinfachte Syntax ähnlich wie
anchor-client, jedoch ohne RPC-Overhead. Es erreicht eine 78%ige
Code-Reduzierung im Vergleich zu rohem LiteSVM und gewährleistet dabei
Typsicherheit mit Anchor-Typen.
AnchorContext
- Produktionskompatible Testumgebung
- Gleiche API-Muster wie anchor-client
- Verwaltet LiteSVM-Instanz, Zahler und Programm
- Anweisungen ohne RPC-Overhead ausführen
Programm-API – Flüssiges Erstellen von Anweisungen – Typsichere Konten- und Argumentverarbeitung – Vertraute anchor-client-Syntax
Konten-Deserialisierung – Anchor-Konten abrufen und deserialisieren – Automatische Diskriminator-Verarbeitung – Unterstützung für PDAs und benutzerdefinierte Layouts
Ereignis-Parsing
- Ereignisse aus Transaktionsprotokollen parsen
- Ereignisausgabe prüfen
- Typsichere Ereignis-Deserialisierung
Schnellbeispiel
Mit Anchor 1.0 verwenden Sie declare_program!, um Client-Typen aus der IDL
Ihres Programms zu generieren. Dieses Makro erstellt die Module
client::accounts::* und client::args::* für typsicheres Erstellen von
Anweisungen:
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) liest die IDL zur Kompilierzeit aus
target/idl/my_program.json und generiert die Module client::accounts::*
und client::args::*. Hierfür muss Ihr Programm zuerst gebaut werden.
Vergleich: Raw LiteSVM vs anchor-litesvm
Vorher (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();
Nachher (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();
Hauptkomponenten
AnchorLiteSVM Builder
| Methode | Beschreibung |
|---|---|
new() | Erstellt eine neue Builder-Instanz |
with_payer(keypair) | Setzt ein benutzerdefiniertes Payer-keypair |
deploy_program(id, bytes) | Fügt ein Programm zum Deployment hinzu |
build() | Erstellt den AnchorContext |
build_with_program(id, bytes) | Komfortmethode für ein einzelnes Programm |
build_with_programs(programs) | Mehrere Programme deployen |
AnchorContext
| Methode | Beschreibung |
|---|---|
svm | Direktzugriff auf die zugrunde liegende LiteSVM-Instanz (öffentliches Feld) |
program_id | Die Programm-ID (öffentliches Feld) |
program() | Gibt Program für den Aufbau von Anweisungen zurück |
payer() | Payer-keypair abrufen |
execute_instruction(ix, signers) | Eine einzelne Anweisung ausführen |
execute_instructions(ixs, signers) | Mehrere Anweisungen in einer Transaktion ausführen |
send_and_confirm_transaction(&tx) | Eine rohe Transaktion senden |
get_account<T>(pubkey) | Ein Anchor-Konten abrufen und deserialisieren |
get_account_unchecked<T>(pubkey) | Abrufen ohne Diskriminatorprüfung |
create_funded_account(lamports) | Ein neues keypair erstellen und finanzieren |
airdrop(pubkey, lamports) | SOL an eine Adresse airdroppen |
latest_blockhash() | Den aktuellen Blockhash abrufen |
account_exists(pubkey) | Prüfen, ob ein Konten existiert |
deploy_program(id, bytes) | Ein zusätzliches Programm deployen (über ProgramTestExt) |
Programm
| Methode | Beschreibung |
|---|---|
accounts(accounts) | Anweisungs-Konten setzen (beliebiger ToAccountMetas-Typ) |
args(args) | Anweisungs-Argumente setzen (beliebiger InstructionData-Typ) |
instruction() | Die finale Instruction erstellen |
id() | Die Programm-ID abrufen |
ctx.svm — TestHelpers & AssertionHelpers
ctx.svm ist ein öffentliches LiteSVM-Feld mit den Traits TestHelpers und
AssertionHelpers, die über litesvm-utils verfügbar sind:
| Methode | Beschreibung |
|---|---|
ctx.svm.create_funded_account(lamports) | Ein keypair erstellen und finanzieren |
ctx.svm.create_token_mint(authority, decimals) | Eine SPL-Token-Mint erstellen |
ctx.svm.create_associated_token_account(mint, owner) | Eine ATA erstellen |
ctx.svm.mint_to(mint, token_account, authority, amount) | Token prägen |
ctx.svm.get_pda(seeds, program_id) | Eine PDA-Adresse ableiten |
ctx.svm.get_pda_with_bump(seeds, program_id) | PDA mit bump seed ableiten |
ctx.svm.assert_token_balance(token_account, expected) | Token-Guthaben prüfen |
ctx.svm.assert_account_closed(pubkey) | Prüfen, ob Konten geschlossen wurde |
ctx.svm.assert_sol_balance(pubkey, expected) | SOL-Guthaben prüfen |
Fehlerbehebung
Häufige Fehler
| Fehler | Ursache | Lösung |
|---|---|---|
AccountNotFound | Konten existiert nicht | Sicherstellen, dass Konten vor dem Abrufen erstellt wurde |
DiscriminatorMismatch | Falscher Kontentyp | Überprüfen, ob der korrekte Konten-Struct verwendet wird |
DeserializationError | Ungültige Kontendaten | Prüfen, ob Konten korrekt initialisiert wurde |
| Keine Programme hinzugefügt | build() ohne deploy_program() aufgerufen | Mindestens ein Programm vor dem Build hinzufügen |
| Fehlende Client-Typen | declare_program! nicht aufgerufen | Zuerst anchor build ausführen, um IDL zu generieren, dann declare_program! aufrufen |
Is this page helpful?