Документація SolanaРозробка програм

Розробка програм на 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 CLI для використання локального кластера 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 для запуску локального validator.

Terminal
solana-test-validator

Поки тестовий validator працює, виконайте команду solana program deploy в окремому терміналі, щоб розгорнути програму на локальному validator.

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

Приклад виводу:

Program Id: 4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz
Signature:
5osMiNMiDZGM7L1e2tPHxU8wdB8gwG8fDnXLg5G7SbhwFz4dHshYgAijk4wSQL5cXiu8z1MMou5kLadAQuHp7ybH

Ви можете переглянути ідентифікатор програми та підпис транзакції на Solana Explorer. Зауважте, що кластер у Solana Explorer також має бути localhost. Опція "Custom RPC URL" у Solana Explorer за замовчуванням встановлена на 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 для оплати комісій за транзакції, а потім викликає програму hello world.

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 Explorer (локальний кластер), щоб побачити "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 Explorer, щоб побачити "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

Якщо вам потрібно повторно розгорнути програму з тим самим вихідним кодом після закриття програми, ви повинні згенерувати новий ідентифікатор програми. Щоб згенерувати нову keypair для програми, виконайте таку команду:

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

Альтернативно, ви можете видалити наявний файл keypair (наприклад, ./target/deploy/hello_world-keypair.json) і знову запустити cargo build-sbf, що згенерує новий файл keypair.

Is this page helpful?