Разработка программ на 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
.
cargo init hello_world --lib
Перейдите в директорию проекта. Вы должны увидеть файлы по умолчанию
src/lib.rs
и Cargo.toml
cd hello_world
Далее добавьте зависимость solana-program
. Это минимальная зависимость,
необходимая для создания программы Solana.
cargo add solana-program@1.18.26
Далее, добавьте следующий фрагмент в Cargo.toml
. Если вы не включите эту
конфигурацию, директория target/deploy
не будет создана при сборке программы.
[lib]crate-type = ["cdylib", "lib"]
Ваш файл 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 для вывода сообщения в лог
программы.
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
.
cargo build-sbf
Эта команда создаёт директорию target/deploy
, содержащую два важных файла:
- Файл
.so
(например,hello_world.so
): Это скомпилированная программа Solana, которая будет развёрнута в сети как "смарт- контракт". - Файл keypair (например,
hello_world-keypair.json
): Публичный ключ этого keypair используется как идентификатор программы при её развёртывании.
Чтобы просмотреть идентификатор программы, выполните следующую команду в терминале. Эта команда выводит публичный ключ keypair по указанному пути к файлу:
solana address -k ./target/deploy/hello_world-keypair.json
Пример вывода:
4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz
Тестирование программы
Далее, протестируйте программу, используя крейт solana-program-test
. Добавьте
следующие зависимости в Cargo.toml
.
cargo add solana-program-test@1.18.26 --devcargo add solana-sdk@1.18.26 --devcargo add tokio --dev
Добавьте следующий тест в src/lib.rs
, под кодом программы. Это тестовый
модуль, который вызывает программу hello world.
#[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 instructionlet instruction = Instruction {program_id,accounts: vec![],data: vec![],};// Create transaction with instructionlet mut transaction = Transaction::new_with_payer(&[instruction], Some(&payer.pubkey()));// Sign transactiontransaction.sign(&[&payer], recent_blockhash);let transaction_result = banks_client.process_transaction(transaction).await;assert!(transaction_result.is_ok());}}
Запустите тест, используя команду cargo test-sbf
. В логе программы отобразится
"Hello, world!".
cargo test-sbf
Пример вывода:
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 successtest test::test_hello_world ... oktest result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.13s
Развертывание программы
Далее, разверните программу. При локальной разработке мы можем использовать
solana-test-validator
.
Сначала настройте Solana CLI для использования локального кластера Solana.
solana config set -ul
Пример вывода:
Config File: /.config/solana/cli/config.ymlRPC URL: http://localhost:8899WebSocket URL: ws://localhost:8900/ (computed)Keypair Path: /.config/solana/id.jsonCommitment: confirmed
Откройте новый терминал и выполните команду solana-test-validators
для запуска
локального validator.
solana-test-validator
Пока тестовый validator работает, выполните команду solana program deploy
в
отдельном терминале, чтобы развернуть программу на локальном validator.
solana program deploy ./target/deploy/hello_world.so
Пример вывода:
Program Id: 4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMzSignature:5osMiNMiDZGM7L1e2tPHxU8wdB8gwG8fDnXLg5G7SbhwFz4dHshYgAijk4wSQL5cXiu8z1MMou5kLadAQuHp7ybH
Вы можете проверить идентификатор программы и подпись транзакции на
Solana Explorer.
Обратите внимание, что кластер в Solana Explorer также должен быть localhost.
Опция "Custom RPC URL" в Solana Explorer по умолчанию установлена на
http://localhost:8899
.
Вызов программы
Далее мы покажем, как вызвать программу с помощью клиента на Rust.
Сначала создайте директорию examples
и файл client.rs
.
mkdir -p examplestouch examples/client.rs
Добавьте следующее в Cargo.toml
.
[[example]]name = "client"path = "examples/client.rs"
Добавьте зависимость solana-client
.
cargo add solana-client@1.18.26 --dev
Добавьте следующий код в examples/client.rs
. Это клиентский скрипт на Rust,
который пополняет новый keypair для оплаты комиссий за транзакции, а затем
вызывает программу hello world.
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 devnetlet 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 payerlet payer = Keypair::new();// Request airdroplet airdrop_amount = 1_000_000_000; // 1 SOLlet signature = client.request_airdrop(&payer.pubkey(), airdrop_amount).expect("Failed to request airdrop");// Wait for airdrop confirmationloop {let confirmed = client.confirm_transaction(&signature).unwrap();if confirmed {break;}}// Create the instructionlet instruction = Instruction::new_with_borsh(program_id,&(), // Empty instruction datavec![], // No accounts needed);// Add the instruction to new transactionlet mut transaction = Transaction::new_with_payer(&[instruction], Some(&payer.pubkey()));transaction.sign(&[&payer], client.get_latest_blockhash().unwrap());// Send and confirm the transactionmatch client.send_and_confirm_transaction(&transaction) {Ok(signature) => println!("Transaction Signature: {}", signature),Err(err) => eprintln!("Error sending transaction: {}", err),}}
Перед запуском скрипта замените идентификатор программы в приведенном выше фрагменте кода на тот, который соответствует вашей программе.
Вы можете получить идентификатор вашей программы, выполнив следующую команду.
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();}}
Запустите клиентский скрипт с помощью следующей команды.
cargo run --example client
Пример вывода:
Transaction Signature: 54TWxKi3Jsi3UTeZbhLGUFX6JQH7TspRJjRRFZ8NFnwG5BXM9udxiX77bAACjKAS9fGnVeEazrXL4SfKrW7xZFYV
Вы можете проверить подпись транзакции в Solana Explorer (локальный кластер), чтобы увидеть "Hello, world!" в логе программы.
Обновление программы
Программы Solana можно обновлять, повторно развертывая их с тем же
идентификатором программы. Обновите программу в src/lib.rs
, чтобы она выводила
"Hello, Solana!" вместо "Hello, world!".
pub fn process_instruction(_program_id: &Pubkey,_accounts: &[AccountInfo],_instruction_data: &[u8],) -> ProgramResult {- msg!("Hello, world!");+ msg!("Hello, Solana!");Ok(())}
Протестируйте обновленную программу, выполнив команду cargo test-sbf
.
cargo test-sbf
Вы должны увидеть "Hello, Solana!" в логе программы.
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 successtest test::test_hello_world ... oktest result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.14s
Выполните команду cargo build-sbf
для создания обновленного файла .so
.
cargo build-sbf
Повторно разверните программу, используя команду solana program deploy
.
solana program deploy ./target/deploy/hello_world.so
Запустите клиентский код снова и проверьте подпись транзакции в Solana Explorer, чтобы увидеть "Hello, Solana!" в логе программы.
cargo run --example client
Закрытие программы
Вы можете закрыть вашу программу Solana, чтобы вернуть SOL, выделенный для аккаунта. Закрытие программы необратимо, поэтому следует делать это с осторожностью.
Для закрытия программы используйте команду solana program close <PROGRAM_ID>
.
Например:
solana program close 4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz--bypass-warning
Пример вывода:
Closed Program Id 4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz, 0.1350588 SOLreclaimed
Обратите внимание, что после закрытия программы ее идентификатор программы не может быть использован повторно. Попытка развернуть программу с ранее закрытым идентификатором программы приведет к ошибке.
Error: Program 4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz has been closed, usea new Program Id
Если вам нужно повторно развернуть программу с тем же исходным кодом после закрытия программы, вы должны сгенерировать новый идентификатор программы. Чтобы сгенерировать новую пару ключей для программы, выполните следующую команду:
solana-keygen new -o ./target/deploy/hello_world-keypair.json --force
В качестве альтернативы вы можете удалить существующий файл пары ключей
(например, ./target/deploy/hello_world-keypair.json
) и снова запустить
cargo build-sbf
, что сгенерирует новый файл пары ключей.
Is this page helpful?