وثائق سولاناLiteSVMRustصناديق إضافيةanchor-litesvm

البدء السريع

التثبيت

أضف التبعيات المطلوبة:

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

ما هو anchor-litesvm?

توفّر حزمة anchor-litesvm صيغةً مبسّطةً مشابهةً لـ anchor-client دون أيّ عبء ناجم عن استدعاءات RPC. وتحقّق تقليصاً بنسبة 78% في حجم الكود مقارنةً بـ LiteSVM الخام، مع الحفاظ على سلامة الأنواع باستخدام أنواع Anchor.

AnchorContext

  • سياق اختبار متوافق مع بيئة الإنتاج
  • نفس أنماط الواجهة البرمجية لـ anchor-client
  • يدير نسخة LiteSVM والدافع والبرنامج
  • تنفيذ التعليمات دون عبء RPC

واجهة البرنامج - بناء تعليمات سلس - معالجة آمنة للحسابات والوسائط من حيث الأنواع - صيغة anchor-client المألوفة

إلغاء تسلسل الحسابات - جلب حسابات Anchor وإلغاء تسلسلها - معالجة تلقائية للمُميِّزات - دعم لـ PDAs والتخطيطات المخصصة

تحليل الأحداث

  • تحليل الأحداث من سجلات المعاملات
  • التحقق من إطلاق الأحداث
  • إلغاء تسلسل الأحداث بأمان من حيث الأنواع

مثال سريع

مع 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)إسقاط 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 token mint
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 typesلم يتم استدعاء declare_program!شغّل anchor build أولاً لتوليد IDL، ثم استدعِ declare_program!

Is this page helpful?