وثائق سولاناLiteSVMRustاختبار برنامجك

نشر البرامج

البدء

let mut svm = LiteSVM::new();

يقوم هذا بإنشاء نسخة اختبار litesvm الأساسية، والتي تتضمن جميع ميزات وقت التشغيل المُفعَّلة، والمتغيرات النظامية الافتراضية، والتجميعات المسبقة، وبرامج spl، والتحقق من التوقيعات، وجميع البرامج المدمجة مثل System Program.

للتفاعل مع أي برنامج آخر في اختباراتك، يجب عليك نشر ذلك البرنامج في بيئة الاختبار الخاصة بك.

  1. قم ببناء ونشر البرنامج الذي تريد اختباره

  2. ابحث عن جميع البرامج التي يُجري البرنامج المذكور أعلاه استدعاءات CPI إليها وانشرها

مثال: إذا كان برنامجك يستخدم تغذيات البيانات من Pyth، فستحتاج إلى نشر برنامج Pyth على نسخة الاختبار الخاصة بك.

نشر البرامج الأساسي

الطريقة 1: النشر من بايتات

انشر البرامج مباشرةً من مصفوفات البايت لأسرع تنفيذ للاختبارات:

use litesvm::LiteSVM;
use solana_sdk::signature::{read_keypair_file, Signer};
let mut svm = LiteSVM::new();
// Read the program's keypair to get correct ID
let program_keypair = read_keypair_file("target/deploy/my_program-keypair.json")
.expect("Program keypair file not found");
let program_id = program_keypair.pubkey();
// Include bytes at compile time
let program_bytes = include_bytes!("../target/deploy/my_program.so");
// Deploy from bytes
svm.add_program(program_id, program_bytes)
.expect("Failed to deploy program");
// Verify deployment
assert!(svm.get_account(&program_id).is_some(), "Program account not created");
assert!(svm.get_account(&program_id).unwrap().executable, "Program not executable");

include_bytes! يُضمِّن الملف الثنائي مباشرةً في الملف التنفيذي للاختبار أثناء التحويل البرمجي، مما يُلغي عمليات الإدخال/الإخراج أثناء تنفيذ الاختبارات.

المزايا

  • أسرع في وقت التشغيل (بدون قراءات من القرص)
  • ملف اختبار ثنائي مكتفٍ بذاته
  • يعمل حتى لو تم حذف ملف .so بعد التحويل البرمجي

العيوب

  • حجم ملف الاختبار الثنائي أكبر
  • يجب إعادة تحويل الاختبارات برمجيًا عند تغيير ملف .so

الطريقة الثانية: النشر من ملف (.so)

قم بتحميل البرامج من نظام الملفات عندما تتغير بشكل متكرر:

use litesvm::LiteSVM;
use solana_sdk::signature::{read_keypair_file, Signer};
let mut svm = LiteSVM::new();
// Read keypair for correct program ID
let program_keypair = read_keypair_file("target/deploy/program-keypair.json").unwrap();
let program_id = program_keypair.pubkey();
// Deploy from file
svm.add_program_from_file(program_id, "target/deploy/program.so")
.expect("Failed to deploy program from file");
// Always verify
assert!(svm.get_account(&program_id).unwrap().executable);

المزايا

  • ملف ثنائي أصغر حجمًا للاختبار
  • يمكن استيعاب تغييرات .so دون إعادة تجميع الاختبارات
  • أكثر مرونة لخطوط أنابيب CI/CD

العيوب

  • أبطأ (إدخال/إخراج القرص أثناء التشغيل)
  • يتطلب وجود ملف .so في وقت تنفيذ الاختبار
  • يجب أن يكون مسار الملف صحيحًا نسبةً إلى دليل تنفيذ الاختبار

سحب البرامج من Mainnet/Devnet

عندما تحتاج إلى برنامج لا تملك كوده المصدري، استخدم واجهة سطر أوامر سولانا لاستخراج البرامج من الشبكات الحية واستخدامها في الاختبارات:

# Dump a program from mainnet
solana program dump gSbePebfvPy7tRqimPoVecS2UsBvYv46ynrzWocc92s pyth.so --url mainnet-beta
# Dump from devnet
solana program dump YourProgramID program.so --url devnet

ثم قم بتحميله في اختباراتك:

svm.add_program_from_file(
pubkey!("gSbePebfvPy7tRqimPoVecS2UsBvYv46ynrzWocc92s"),
"pyth.so"
).unwrap();

أفضل الممارسات

1. اختر طريقة النشر المناسبة

  • استخدم add_program() عندما:

    • تكون البرامج مضمّنة في الملف الثنائي للاختبار وقت التجميع
    • تريد تنفيذًا أسرع للاختبارات (بدون إدخال/إخراج أثناء التشغيل)
    • تريد اختبارات مكتفية بذاتها
  • استخدم add_program_from_file() عندما:

    • يتم بناء البرامج بشكل منفصل (أي السحب من devnet)
    • يتغير البرنامج بشكل متكرر أثناء التطوير (يمكن إعادة تشغيل الاختبارات دون إعادة التحويل البرمجي)
    • لديك بيئات CI/CD حيث تكون ملفات .so عبارة عن قطع أثرية للبناء

فهم keypair البرنامج

عند بناء برنامج سولانا:

  1. ينشئ Anchor target/deploy/program-keypair.json
  2. تنشئ عمليات بناء Native ملف keypair إلى جانب ملف .so
  3. عنوان البرنامج على السلسلة هو المفتاح العام لهذا keypair، والمعروف أيضاً بمعرّف البرنامج.
  4. بالنسبة لـ PDAs، يتطلب find_program_address() معرّف البرنامج كـ seed
  5. بالنسبة لـ CPIs، يُستخدم معرّف البرنامج لاستدعاء البرامج الأخرى

المشكلات الشائعة وحلولها

إخفاقات النشر الصامتة

المشكلة: يبدو أن البرنامج يتم نشره، لكن المعاملات تفشل بـ "InvalidProgramForExecution".

السبب: معرّف البرنامج لا يتطابق مع keypair.

الحل:

// Always use the keypair-derived ID
let keypair = read_keypair_file("target/deploy/program-keypair.json").unwrap();
let program_id = keypair.pubkey();
svm.add_program(program_id, &program_bytes).unwrap();
// Verify with detailed checks
let account = svm.get_account(&program_id)
.expect("Program account doesn't exist");
assert!(account.executable, "Program not executable");
assert_eq!(account.owner, solana_sdk::bpf_loader::id(), "Wrong owner");
assert!(!account.data.is_empty(), "Program data is empty");
println!("✅ Program verified at {}", program_id);

خطأ عدم العثور على البرنامج

الخطأ: TransactionError::InvalidProgramForExecution

الأسباب الشائعة:

  1. البرنامج غير منشور
  2. تم استخدام معرّف برنامج خاطئ في التعليمات
  3. عدم تطابق معرّف البرنامج مع keypair

خطوات التصحيح:

// Step 1: Check if program exists
if let Some(account) = svm.get_account(&program_id) {
println!("Program exists");
println!(" Executable: {}", account.executable);
println!(" Owner: {}", account.owner);
println!(" Data length: {}", account.data.len());
} else {
println!("Program does not exist at {}", program_id);
}
// Step 2: Verify the ID matches keypair
let expected_keypair = read_keypair_file("target/deploy/program-keypair.json").unwrap();
let expected_id = expected_keypair.pubkey();
if program_id != expected_id {
println!(" ID mismatch!");
println!(" Used: {}", program_id);
println!(" Expected: {}", expected_id);
}
// Step 3: Check instruction program ID
println!("Instruction program_id: {}", instruction.program_id);
assert_eq!(instruction.program_id, program_id, "Instruction uses wrong program ID");

CPI إلى برامج غير منشورة

المشكلة: يُجري برنامجك استدعاء CPI إلى برنامج غير منشور.

الحل: انشر جميع برامج التبعيات:

// Find all dependency programs and make sure they are deployed
svm.add_program_from_file(
pubkey!("gSbePebfvPy7tRqimPoVecS2UsBvYv46ynrzWocc92s"),
"pyth.so"
).unwrap();

إذا كنت بحاجة إلى سحب البرنامج من مجموعة، راجع هذا القسم.

lamport غير كافية للنشر

ملاحظة: يتعامل LiteSVM تلقائياً مع رصيد الإعفاء من الإيجار للبرامج.

// No need to manually fund - LiteSVM handles this
svm.add_program(program_id, &program_bytes).unwrap();
// But you can check the rent if needed
let program_len = program_bytes.len();
let required_lamports = svm.minimum_balance_for_rent_exemption(program_len);
println!("Program requires {} lamports for rent exemption", required_lamports);

قائمة التحقق من النشر

اقرأ keypair الخاص بالبرنامج

let keypair = read_keypair_file("target/deploy/program-keypair.json").unwrap();
let program_id = keypair.pubkey();

انشر مع المعرّف المطابق

svm.add_program(program_id, &program_bytes).unwrap();

تحقق من النشر

assert!(svm.get_account(&program_id).unwrap().executable);

انشر أي برامج يستدعيها برنامجك عبر CPI إلى نموذج اختبار litesvm

الخطوات التالية

في القسم التالي، سنتعلم كيفية تنفيذ تعليمات البرنامج والتعامل مع أنماط المعاملات المعقدة.

Is this page helpful?