Документація SolanaLiteSVMRustДодаткові контейнериanchor-litesvm

Швидкий старт

Встановлення

Додайте необхідні залежності:

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

Що таке anchor-litesvm?

Крейт anchor-litesvm надає спрощений синтаксис, схожий на anchor-client, але без накладних витрат RPC. Він забезпечує скорочення коду на 78% порівняно з використанням LiteSVM напряму, зберігаючи типобезпеку з типами Anchor.

AnchorContext

  • Контекст тестування, сумісний із production
  • Ті самі патерни API, що й у anchor-client
  • Керує екземпляром LiteSVM, платником і програмою
  • Виконання інструкцій без накладних витрат RPC

API програми — Зручна побудова інструкцій — Типобезпечна робота з акаунтами та аргументами — Знайомий синтаксис anchor-client

Десеріалізація акаунтів — Отримання та десеріалізація акаунтів Anchor — Автоматична обробка дискримінатора — Підтримка PDA та користувацьких макетів

Парсинг подій

  • Парсинг подій із журналів транзакцій
  • Перевірка генерації подій
  • Типобезпечна десеріалізація подій

Швидкий приклад

З Anchor 1.0 використовуйте declare_program! для генерації клієнтських типів із IDL вашої програми. Цей макрос створює модулі 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 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) зчитує IDL із target/idl/my_program.json під час компіляції та генерує модулі 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 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();

Після (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Ідентифікатор програми (публічне поле)
program()Повертає Program для побудови інструкцій
payer()Отримати keypair платника
execute_instruction(ix, signers)Виконати одну інструкцію
execute_instructions(ixs, signers)Виконати кілька інструкцій в одній транзакції
send_and_confirm_transaction(&tx)Надіслати необроблену транзакцію
get_account<T>(pubkey)Отримати та десеріалізувати Anchor-акаунт
get_account_unchecked<T>(pubkey)Отримати без перевірки дискримінатора
create_funded_account(lamports)Створити та поповнити новий keypair
airdrop(pubkey, lamports)Airdrop SOL на адресу
latest_blockhash()Отримати поточний blockhash
account_exists(pubkey)Перевірити існування акаунту
deploy_program(id, bytes)Розгорнути додаткову програму (через ProgramTestExt)

Програма

МетодОпис
accounts(accounts)Встановити акаунти інструкції (будь-який тип ToAccountMetas)
args(args)Встановити аргументи інструкції (будь-який тип InstructionData)
instruction()Побудувати фінальний Instruction
id()Отримати ідентифікатор програми

ctx.svm — TestHelpers & AssertionHelpers

ctx.svm є публічним полем LiteSVM з трейтами TestHelpers та AssertionHelpers, доступними через litesvm-utils:

МетодОпис
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)Отримати PDA з bump seed
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Викликано build() без deploy_program()Додайте принаймні одну програму перед збіркою
Missing client typesdeclare_program! не викликаноСпочатку запустіть anchor build для генерації IDL, потім викличте declare_program!

Is this page helpful?