Программы для Solana в основном разрабатываются с использованием языка программирования Rust. На этой странице рассматривается написание программ для Solana на Rust без использования фреймворка Anchor, что часто называют написанием программ на "чистом Rust".
Разработка на чистом Rust предоставляет разработчикам прямой контроль над их программами для Solana. Однако этот подход требует больше ручной настройки и шаблонного кода по сравнению с использованием фреймворка Anchor. Этот метод рекомендуется для разработчиков, которые:
- Стремятся к детальному контролю над логикой программы и оптимизациями
- Хотят изучить базовые концепции перед переходом к более высокоуровневым фреймворкам
Для начинающих мы рекомендуем начать с фреймворка Anchor. Подробнее см. в разделе Anchor.
Предварительные требования
Для получения подробных инструкций по установке посетите страницу установки.
Перед началом убедитесь, что у вас установлены следующие компоненты:
- Rust: Язык программирования для создания программ для Solana.
- Solana CLI: Инструмент командной строки для разработки на Solana.
Начало работы
Пример ниже охватывает основные шаги для создания вашей первой программы для Solana, написанной на Rust. Мы создадим минимальную программу, которая выводит "Hello, world!" в журнал программы.
Создание новой программы
Сначала создайте новый проект на Rust с помощью стандартной команды cargo new
с флагом --lib.
$cargo new hello_world --lib
Перейдите в каталог проекта. Вы должны увидеть файлы по умолчанию src/lib.rs и
Cargo.toml
$cd hello_world
Обновите поле edition в Cargo.toml на 2021. В противном случае при
сборке программы может возникнуть ошибка.
Добавьте зависимость solana-program
Далее добавьте зависимость solana-program. Это минимальная зависимость,
необходимая для сборки программы Solana.
$cargo add solana-program@2.2.0
Добавьте crate-type
Далее добавьте следующий фрагмент в Cargo.toml.
[lib]crate-type = ["cdylib", "lib"]
Если не включить эту конфигурацию, каталог target/deploy не будет создан при
сборке программы.
Ваш файл Cargo.toml должен выглядеть следующим образом:
[package]name = "hello_world"version = "0.1.0"edition = "2021"[lib]crate-type = ["cdylib", "lib"][dependencies]solana-program = "2.2.0"
Добавьте код программы
Далее замените содержимое 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 используется как идентификатор программы при её развертывании.
Чтобы увидеть ID программы, выполните следующую команду в терминале. Эта команда выводит публичный ключ пары ключей по указанному пути к файлу:
$solana address -k ./target/deploy/hello_world-keypair.json
Пример вывода:
4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz
Добавьте зависимости для тестирования
Далее протестируйте программу с помощью крейта litesvm. Добавьте следующие
зависимости в Cargo.toml.
$cargo add litesvm@0.6.1 --dev$cargo add solana-sdk@2.2.0 --dev
Протестируйте программу
Добавьте следующий тест в src/lib.rs под кодом программы. Это тестовый модуль,
который вызывает программу hello world.
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(())}#[cfg(test)]mod test {use litesvm::LiteSVM;use solana_sdk::{instruction::Instruction,message::Message,signature::{Keypair, Signer},transaction::Transaction,};#[test]fn test_hello_world() {// Create a new LiteSVM instancelet mut svm = LiteSVM::new();// Create a keypair for the transaction payerlet payer = Keypair::new();// Airdrop some lamports to the payersvm.airdrop(&payer.pubkey(), 1_000_000_000).unwrap();// Load our programlet program_keypair = Keypair::new();let program_id = program_keypair.pubkey();svm.add_program_from_file(program_id, "target/deploy/hello_world.so").unwrap();// Create instruction with no accounts and no datalet instruction = Instruction {program_id,accounts: vec![],data: vec![],};// Create transactionlet message = Message::new(&[instruction], Some(&payer.pubkey()));let transaction = Transaction::new(&[&payer], message, svm.latest_blockhash());// Send transaction and verify it succeedslet result = svm.send_transaction(transaction);assert!(result.is_ok(), "Transaction should succeed");let logs = result.unwrap().logs;println!("Logs: {logs:#?}");}}
Запустите тест с помощью команды cargo test. В журнале программы будет
отображаться "Hello, world!".
$cargo test -- --no-capture
Пример вывода:
running 1 testLogs: ["Program 9528phXNvdWp5kkR4rgpoeZvR8ZWT5THVywK95YRprkk invoke [1]","Program log: Hello, world!","Program 9528phXNvdWp5kkR4rgpoeZvR8ZWT5THVywK95YRprkk consumed 211 of 200000 compute units","Program 9528phXNvdWp5kkR4rgpoeZvR8ZWT5THVywK95YRprkk success",]test test::test_hello_world ... oktest result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.05s
Разверните программу
Далее разверните программу. При локальной разработке можно использовать
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
Вы можете проверить ID программы и подпись транзакции на Solana Explorer.
Обратите внимание, что кластер в Solana Explorer также должен быть localhost.
Опция "Custom RPC URL" в Solana Explorer по умолчанию установлена на
http://localhost:8899.
Создайте пример клиента
Далее мы покажем, как вызвать программу с помощью клиента на Rust.
Сначала создайте каталог examples и файл client.rs.
$mkdir -p examples && touch examples/client.rs
Добавьте следующее в Cargo.toml.
[[example]]name = "client"path = "examples/client.rs"
Добавьте зависимости solana-client и tokio.
$cargo add solana-client@2.2.0 --dev$cargo add tokio --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://localhost: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),}}
Замените ID программы
Перед запуском клиентского кода замените ID программы в коде на ID вашей программы.
Вы можете получить ID вашей программы, выполнив следующую команду.
$solana address -k ./target/deploy/hello_world-keypair.json
Вызовите программу
Запустите клиентский скрипт с помощью следующей команды.
$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 build-sbf, чтобы сгенерировать обновлённый файл .so.
$cargo build-sbf
Протестируйте обновлённую программу, выполнив команду cargo test.
$cargo test -- --no-capture
Вы должны увидеть "Hello, Solana!" в журнале программы.
running 1 testLogs: ["Program 5y8bHrnwfq2dLDgLn3WoTHb9dDuyorj9gyapW6aeyrpV invoke [1]","Program log: Hello, Solana!","Program 5y8bHrnwfq2dLDgLn3WoTHb9dDuyorj9gyapW6aeyrpV consumed 211 of 200000 compute units","Program 5y8bHrnwfq2dLDgLn3WoTHb9dDuyorj9gyapW6aeyrpV success",]test test::test_hello_world ... oktest result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.08s
Повторно разверните программу
Повторно разверните программу, используя ту же команду 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
Обратите внимание, что после закрытия программы её идентификатор программы (program ID) не может быть повторно использован. Попытка развернуть программу с ранее закрытым идентификатором программы приведёт к ошибке.
Error: Program 4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz has been closed, usea new Program Id
Повторное развертывание закрытой программы
Если вам нужно повторно развернуть программу с тем же исходным кодом после её закрытия, необходимо сгенерировать новый идентификатор программы. Чтобы сгенерировать новую пару ключей (keypair) для программы, выполните следующую команду:
$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?