Dokumentacja SolanaLiteSVMRustDodatkowe skrzynieanchor-litesvm

Szybki start

Instalacja

Dodaj wymagane zależności:

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

Czym jest anchor-litesvm?

Crate anchor-litesvm zapewnia uproszczoną składnię podobną do anchor-client, ale bez narzutu RPC. Osiąga redukcję kodu o 78% w porównaniu do surowego LiteSVM, zachowując przy tym bezpieczeństwo typów z typami Anchor.

AnchorContext

  • Kontekst testowy zgodny z produkcją
  • Te same wzorce API co anchor-client
  • Zarządza instancją LiteSVM, płatnikiem i programem
  • Wykonuje instrukcje bez narzutu RPC

API programu — Płynne budowanie instrukcji — Obsługa kont i argumentów z bezpieczeństwem typów — Znana składnia anchor-client

Deserializacja kont — Pobieranie i deserializacja kont Anchor — Automatyczna obsługa dyskryminatorów — Obsługa PDA i niestandardowych układów

Parsowanie zdarzeń

  • Parsowanie zdarzeń z logów transakcji
  • Asercja emisji zdarzeń
  • Deserializacja zdarzeń z bezpieczeństwem typów

Szybki przykład

W Anchor 1.0 użyj declare_program!, aby wygenerować typy klienta z IDL swojego programu. To makro tworzy moduły client::accounts::* i client::args::* do bezpiecznego typowo budowania instrukcji:

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) odczytuje IDL z target/idl/my_program.json w czasie kompilacji i generuje moduły client::accounts::* i client::args::*. Wymaga to wcześniejszego zbudowania programu.

Porównanie: Raw LiteSVM vs anchor-litesvm

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

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

Kluczowe komponenty

AnchorLiteSVM Builder

MetodaOpis
new()Tworzy nową instancję buildera
with_payer(keypair)Ustawia niestandardowy keypair płatnika
deploy_program(id, bytes)Dodaje program do wdrożenia
build()Buduje AnchorContext
build_with_program(id, bytes)Wygoda dla pojedynczego programu
build_with_programs(programs)Wdraża wiele programów

AnchorContext

MetodaOpis
svmBezpośredni dostęp do instancji LiteSVM (pole publiczne)
program_idIdentyfikator programu (pole publiczne)
program()Zwraca Program do budowania instrukcji
payer()Pobiera keypair płatnika
execute_instruction(ix, signers)Wykonuje pojedynczą instrukcję
execute_instructions(ixs, signers)Wykonuje wiele instrukcji w jednej transakcji
send_and_confirm_transaction(&tx)Wysyła surową transakcję
get_account<T>(pubkey)Pobiera i deserializuje konto Anchor
get_account_unchecked<T>(pubkey)Pobiera bez sprawdzania dyskryminatora
create_funded_account(lamports)Tworzy i zasila nowy keypair
airdrop(pubkey, lamports)Airdrop SOL na adres
latest_blockhash()Pobiera bieżący blockhash
account_exists(pubkey)Sprawdza, czy konto istnieje
deploy_program(id, bytes)Wdraża dodatkowy program (przez ProgramTestExt)

Program

MetodaOpis
accounts(accounts)Ustawia konta instrukcji (dowolny typ ToAccountMetas)
args(args)Ustawia argumenty instrukcji (dowolny typ InstructionData)
instruction()Buduje końcowy Instruction
id()Pobiera identyfikator programu

ctx.svm — TestHelpers i AssertionHelpers

ctx.svm to publiczne pole LiteSVM z cechami TestHelpers i AssertionHelpers dostępnymi przez litesvm-utils:

MetodaOpis
ctx.svm.create_funded_account(lamports)Utwórz i doładuj keypair
ctx.svm.create_token_mint(authority, decimals)Utwórz mint tokena SPL
ctx.svm.create_associated_token_account(mint, owner)Utwórz ATA
ctx.svm.mint_to(mint, token_account, authority, amount)Mintuj tokeny
ctx.svm.get_pda(seeds, program_id)Wyznacz adres PDA
ctx.svm.get_pda_with_bump(seeds, program_id)Wyznacz PDA z bump seed
ctx.svm.assert_token_balance(token_account, expected)Sprawdź saldo tokena
ctx.svm.assert_account_closed(pubkey)Sprawdź, czy konto zostało zamknięte
ctx.svm.assert_sol_balance(pubkey, expected)Sprawdź saldo SOL

Rozwiązywanie problemów

Typowe błędy

BłądPrzyczynaRozwiązanie
AccountNotFoundKonto nie istniejeUpewnij się, że konto zostało utworzone przed jego pobraniem
DiscriminatorMismatchNieprawidłowy typ kontaSprawdź, czy używasz właściwej struktury konta
DeserializationErrorNieprawidłowe dane kontaSprawdź, czy konto zostało poprawnie zainicjalizowane
Brak dodanych programówWywołano build() bez deploy_program()Dodaj co najmniej jeden program przed budowaniem
Brak typów klientadeclare_program! nie zostało wywołaneUruchom najpierw anchor build, aby wygenerować IDL, a następnie wywołaj declare_program!

Is this page helpful?

Spis treści

Edytuj stronę