وثائق سولاناتطوير البرامج

تطوير البرامج بلغة Rust

يتم تطوير برامج Solana بشكل أساسي باستخدام لغة البرمجة Rust. تركز هذه الصفحة على كتابة برامج Solana بلغة Rust دون استخدام إطار Anchor، وهو نهج يُشار إليه غالبًا باسم كتابة برامج "Rust الأصلية".

يوفر تطوير Rust الأصلي للمطورين تحكمًا مباشرًا في برامج Solana الخاصة بهم. ومع ذلك، يتطلب هذا النهج المزيد من الإعداد اليدوي والكود المتكرر مقارنة باستخدام إطار Anchor. يُوصى بهذه الطريقة للمطورين الذين:

  • يسعون للتحكم الدقيق في منطق البرنامج والتحسينات
  • يرغبون في تعلم المفاهيم الأساسية قبل الانتقال إلى أطر عمل ذات مستوى أعلى

بالنسبة للمبتدئين، نوصي بالبدء باستخدام إطار Anchor. راجع قسم Anchor لمزيد من المعلومات.

المتطلبات الأساسية

للحصول على تعليمات التثبيت المفصلة، قم بزيارة صفحة التثبيت.

قبل أن تبدأ، تأكد من تثبيت ما يلي:

  • Rust: لغة البرمجة لبناء برامج Solana.
  • Solana CLI: أداة سطر الأوامر لتطوير Solana.

البدء

يغطي المثال أدناه الخطوات الأساسية لإنشاء برنامج Solana الأول الخاص بك المكتوب بلغة Rust. سننشئ برنامجًا بسيطًا يطبع "Hello, world!" في سجل البرنامج.

إنشاء برنامج جديد

أولاً، قم بإنشاء مشروع Rust جديد باستخدام الأمر القياسي cargo init مع الخيار --lib.

Terminal
cargo init hello_world --lib

انتقل إلى دليل المشروع. يجب أن ترى ملفات src/lib.rs و Cargo.toml الافتراضية

Terminal
cd hello_world

بعد ذلك، أضف تبعية solana-program. هذه هي الحد الأدنى من التبعيات المطلوبة لبناء برنامج Solana.

Terminal
cargo add solana-program@1.18.26

بعد ذلك، أضف المقطع التالي إلى Cargo.toml. إذا لم تقم بتضمين هذا الإعداد، فلن يتم إنشاء دليل target/deploy عند بناء البرنامج.

Cargo.toml
[lib]
crate-type = ["cdylib", "lib"]

يجب أن يبدو ملف Cargo.toml الخاص بك كما يلي:

Cargo.toml
[package]
name = "hello_world"
version = "0.1.0"
edition = "2021"
[lib]
crate-type = ["cdylib", "lib"]
[dependencies]
solana-program = "1.18.26"

بعد ذلك، استبدل محتويات src/lib.rs بالكود التالي. هذا برنامج Solana بسيط يطبع "Hello, world!" في سجل البرنامج عند استدعاء البرنامج.

يتم استخدام وحدة الماكرو msg! في برامج Solana لطباعة رسالة في سجل البرنامج.

lib.rs
use solana_program::{
account_info::AccountInfo, entrypoint, entrypoint::ProgramResult, msg, pubkey::Pubkey,
};
entrypoint!(process_instruction);
pub fn process_instruction(
_program_id: &Pubkey,
_accounts: &[AccountInfo],
_instruction_data: &[u8],
) -> ProgramResult {
msg!("Hello, world!");
Ok(())
}

بناء البرنامج

بعد ذلك، قم ببناء البرنامج باستخدام أمر cargo build-sbf.

Terminal
cargo build-sbf

ينشئ هذا الأمر دليل target/deploy يحتوي على ملفين مهمين:

  1. ملف .so (مثل hello_world.so): هذا هو برنامج Solana المُجمّع الذي سيتم نشره على الشبكة كـ "عقد ذكي".
  2. ملف keypair (مثل hello_world-keypair.json): يتم استخدام المفتاح العام لهذا الـ keypair كمعرف للبرنامج عند نشر البرنامج.

لعرض معرف البرنامج، قم بتشغيل الأمر التالي في الطرفية الخاصة بك. يقوم هذا الأمر بطباعة المفتاح العام للـ keypair في مسار الملف المحدد:

Terminal
solana address -k ./target/deploy/hello_world-keypair.json

مثال للمخرجات:

4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz

اختبار البرنامج

بعد ذلك، اختبر البرنامج باستخدام حزمة solana-program-test. أضف التبعيات التالية إلى Cargo.toml.

Terminal
cargo add solana-program-test@1.18.26 --dev
cargo add solana-sdk@1.18.26 --dev
cargo add tokio --dev

أضف الاختبار التالي إلى src/lib.rs، أسفل كود البرنامج. هذه وحدة اختبار تستدعي برنامج hello world.

lib.rs
#[cfg(test)]
mod test {
use solana_program_test::*;
use solana_sdk::{
instruction::Instruction, pubkey::Pubkey, signature::Signer, transaction::Transaction,
};
#[tokio::test]
async fn test_hello_world() {
let program_id = Pubkey::new_unique();
let mut program_test = ProgramTest::default();
program_test.add_program("hello_world", program_id, None);
let (mut banks_client, payer, recent_blockhash) = program_test.start().await;
// Create instruction
let instruction = Instruction {
program_id,
accounts: vec![],
data: vec![],
};
// Create transaction with instruction
let mut transaction = Transaction::new_with_payer(&[instruction], Some(&payer.pubkey()));
// Sign transaction
transaction.sign(&[&payer], recent_blockhash);
let transaction_result = banks_client.process_transaction(transaction).await;
assert!(transaction_result.is_ok());
}
}

قم بتشغيل الاختبار باستخدام أمر cargo test-sbf. سيعرض سجل البرنامج "Hello, world!".

Terminal
cargo test-sbf

مثال على المخرجات:

Terminal
running 1 test
[2024-10-18T21:24:54.889570000Z INFO solana_program_test] "hello_world" SBF program from /hello_world/target/deploy/hello_world.so, modified 35 seconds, 828 ms, 268 µs and 398 ns ago
[2024-10-18T21:24:54.974294000Z DEBUG solana_runtime::message_processor::stable_log] Program 1111111QLbz7JHiBTspS962RLKV8GndWFwiEaqKM invoke [1]
[2024-10-18T21:24:54.974814000Z DEBUG solana_runtime::message_processor::stable_log] Program log: Hello, world!
[2024-10-18T21:24:54.976848000Z DEBUG solana_runtime::message_processor::stable_log] Program 1111111QLbz7JHiBTspS962RLKV8GndWFwiEaqKM consumed 140 of 200000 compute units
[2024-10-18T21:24:54.976868000Z DEBUG solana_runtime::message_processor::stable_log] Program 1111111QLbz7JHiBTspS962RLKV8GndWFwiEaqKM success
test test::test_hello_world ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.13s

نشر البرنامج

بعد ذلك، قم بنشر البرنامج. عند التطوير محليًا، يمكننا استخدام solana-test-validator.

أولاً، قم بتكوين واجهة سطر أوامر Solana لاستخدام مجموعة Solana المحلية.

Terminal
solana config set -ul

مثال على المخرجات:

Config File: /.config/solana/cli/config.yml
RPC URL: http://localhost:8899
WebSocket URL: ws://localhost:8900/ (computed)
Keypair Path: /.config/solana/id.json
Commitment: confirmed

افتح نافذة طرفية جديدة وقم بتشغيل الأمر solana-test-validators لبدء المصادق المحلي.

Terminal
solana-test-validator

أثناء تشغيل المصادق الاختباري، قم بتشغيل الأمر solana program deploy في نافذة طرفية منفصلة لنشر البرنامج على المصادق المحلي.

Terminal
solana program deploy ./target/deploy/hello_world.so

مثال على المخرجات:

Program Id: 4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz
Signature:
5osMiNMiDZGM7L1e2tPHxU8wdB8gwG8fDnXLg5G7SbhwFz4dHshYgAijk4wSQL5cXiu8z1MMou5kLadAQuHp7ybH

يمكنك فحص معرّف البرنامج وتوقيع المعاملة على مستكشف Solana. لاحظ أن المجموعة على مستكشف Solana يجب أن تكون أيضًا localhost. خيار "عنوان URL مخصص لـ RPC" في مستكشف Solana يكون افتراضيًا http://localhost:8899.

استدعاء البرنامج

بعد ذلك، سنوضح كيفية استدعاء البرنامج باستخدام عميل Rust.

أولاً قم بإنشاء دليل examples وملف client.rs.

Terminal
mkdir -p examples
touch examples/client.rs

أضف ما يلي إلى Cargo.toml.

Cargo.toml
[[example]]
name = "client"
path = "examples/client.rs"

أضف التبعية solana-client.

Terminal
cargo add solana-client@1.18.26 --dev

أضف الكود التالي إلى examples/client.rs. هذا نص برمجي لعميل Rust يقوم بتمويل keypair جديد لدفع رسوم المعاملات ثم يستدعي برنامج مرحبا بالعالم.

example/client.rs
use solana_client::rpc_client::RpcClient;
use solana_sdk::{
commitment_config::CommitmentConfig,
instruction::Instruction,
pubkey::Pubkey,
signature::{Keypair, Signer},
transaction::Transaction,
};
use std::str::FromStr;
#[tokio::main]
async fn main() {
// Program ID (replace with your actual program ID)
let program_id = Pubkey::from_str("4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz").unwrap();
// Connect to the Solana devnet
let rpc_url = String::from("http://127.0.0.1:8899");
let client = RpcClient::new_with_commitment(rpc_url, CommitmentConfig::confirmed());
// Generate a new keypair for the payer
let payer = Keypair::new();
// Request airdrop
let airdrop_amount = 1_000_000_000; // 1 SOL
let signature = client
.request_airdrop(&payer.pubkey(), airdrop_amount)
.expect("Failed to request airdrop");
// Wait for airdrop confirmation
loop {
let confirmed = client.confirm_transaction(&signature).unwrap();
if confirmed {
break;
}
}
// Create the instruction
let instruction = Instruction::new_with_borsh(
program_id,
&(), // Empty instruction data
vec![], // No accounts needed
);
// Add the instruction to new transaction
let mut transaction = Transaction::new_with_payer(&[instruction], Some(&payer.pubkey()));
transaction.sign(&[&payer], client.get_latest_blockhash().unwrap());
// Send and confirm the transaction
match client.send_and_confirm_transaction(&transaction) {
Ok(signature) => println!("Transaction Signature: {}", signature),
Err(err) => eprintln!("Error sending transaction: {}", err),
}
}

قبل تشغيل النص البرمجي، استبدل معرف البرنامج في مقتطف الكود أعلاه بالمعرف الخاص ببرنامجك.

يمكنك الحصول على معرف برنامجك عن طريق تشغيل الأمر التالي.

Terminal
solana address -k ./target/deploy/hello_world-keypair.json
#[tokio::main]
async fn main() {
- let program_id = Pubkey::from_str("4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz").unwrap();
+ let program_id = Pubkey::from_str("YOUR_PROGRAM_ID).unwrap();
}
}

قم بتشغيل النص البرمجي للعميل باستخدام الأمر التالي.

Terminal
cargo run --example client

مثال على المخرجات:

Transaction Signature: 54TWxKi3Jsi3UTeZbhLGUFX6JQH7TspRJjRRFZ8NFnwG5BXM9udxiX77bAACjKAS9fGnVeEazrXL4SfKrW7xZFYV

يمكنك فحص توقيع المعاملة على مستكشف Solana (المجموعة المحلية) لرؤية "Hello, world!" في سجل البرنامج.

تحديث البرنامج

يمكن تحديث برامج Solana عن طريق إعادة النشر إلى نفس معرف البرنامج. قم بتحديث البرنامج في src/lib.rs لطباعة "Hello, Solana!" بدلاً من "Hello, world!".

lib.rs
pub fn process_instruction(
_program_id: &Pubkey,
_accounts: &[AccountInfo],
_instruction_data: &[u8],
) -> ProgramResult {
- msg!("Hello, world!");
+ msg!("Hello, Solana!");
Ok(())
}

اختبر البرنامج المحدث عن طريق تشغيل أمر cargo test-sbf.

Terminal
cargo test-sbf

يجب أن ترى "Hello, Solana!" في سجل البرنامج.

Terminal
running 1 test
[2024-10-23T19:28:28.842639000Z INFO solana_program_test] "hello_world" SBF program from /code/misc/delete/hello_world/target/deploy/hello_world.so, modified 4 minutes, 31 seconds, 435 ms, 566 µs and 766 ns ago
[2024-10-23T19:28:28.934854000Z DEBUG solana_runtime::message_processor::stable_log] Program 1111111QLbz7JHiBTspS962RLKV8GndWFwiEaqKM invoke [1]
[2024-10-23T19:28:28.936735000Z DEBUG solana_runtime::message_processor::stable_log] Program log: Hello, Solana!
[2024-10-23T19:28:28.938774000Z DEBUG solana_runtime::message_processor::stable_log] Program 1111111QLbz7JHiBTspS962RLKV8GndWFwiEaqKM consumed 140 of 200000 compute units
[2024-10-23T19:28:28.938793000Z DEBUG solana_runtime::message_processor::stable_log] Program 1111111QLbz7JHiBTspS962RLKV8GndWFwiEaqKM success
test test::test_hello_world ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.14s

قم بتشغيل أمر cargo build-sbf لإنشاء ملف .so محدث.

Terminal
cargo build-sbf

أعد نشر البرنامج باستخدام أمر solana program deploy.

Terminal
solana program deploy ./target/deploy/hello_world.so

قم بتشغيل كود العميل مرة أخرى وافحص توقيع المعاملة على مستكشف Solana لرؤية "Hello, Solana!" في سجل البرنامج.

Terminal
cargo run --example client

إغلاق البرنامج

يمكنك إغلاق برنامج Solana الخاص بك لاسترداد عملة SOL المخصصة للحساب. إغلاق البرنامج هو إجراء لا رجعة فيه، لذا يجب القيام به بحذر.

لإغلاق البرنامج، استخدم الأمر solana program close <PROGRAM_ID>. على سبيل المثال:

Terminal
solana program close 4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz
--bypass-warning

مثال للنتيجة:

Closed Program Id 4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz, 0.1350588 SOL
reclaimed

لاحظ أنه بمجرد إغلاق البرنامج، لا يمكن إعادة استخدام معرف البرنامج الخاص به. محاولة نشر برنامج بمعرف برنامج تم إغلاقه مسبقًا ستؤدي إلى خطأ.

Error: Program 4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz has been closed, use
a new Program Id

إذا كنت بحاجة إلى إعادة نشر برنامج بنفس الشفرة المصدرية بعد إغلاق البرنامج، يجب عليك إنشاء معرف برنامج جديد. لإنشاء زوج مفاتيح جديد للبرنامج، قم بتشغيل الأمر التالي:

Terminal
solana-keygen new -o ./target/deploy/hello_world-keypair.json --force

بدلاً من ذلك، يمكنك حذف ملف زوج المفاتيح الموجود (مثل ./target/deploy/hello_world-keypair.json) وتشغيل cargo build-sbf مرة أخرى، مما سيؤدي إلى إنشاء ملف زوج مفاتيح جديد.

Is this page helpful?

جدول المحتويات

تعديل الصفحة