Dokumentacja SolanaTworzenie programów

Tworzenie programów w Rust

Programy Solana są głównie tworzone w języku programowania Rust. Ta strona koncentruje się na pisaniu programów Solana w Rust bez użycia frameworka Anchor, co często nazywane jest pisaniem programów w "czystym Rust".

Tworzenie w czystym Rust daje programistom bezpośrednią kontrolę nad ich programami Solana. Jednak to podejście wymaga więcej ręcznej konfiguracji i szablonowego kodu w porównaniu do użycia frameworka Anchor. Ta metoda jest zalecana dla programistów, którzy:

  • Chcą mieć szczegółową kontrolę nad logiką programu i optymalizacjami
  • Chcą najpierw poznać podstawowe koncepcje, zanim przejdą do bardziej zaawansowanych frameworków

Dla początkujących zalecamy rozpoczęcie od frameworka Anchor. Zobacz sekcję Anchor po więcej informacji.

Wymagania wstępne

Szczegółowe instrukcje instalacji znajdziesz na stronie instalacja.

Przed rozpoczęciem upewnij się, że masz zainstalowane następujące elementy:

  • Rust: Język programowania do tworzenia programów Solana.
  • Solana CLI: Narzędzie wiersza poleceń do rozwoju Solana.

Pierwsze kroki

Poniższy przykład obejmuje podstawowe kroki tworzenia pierwszego programu Solana napisanego w Rust. Stworzymy minimalny program, który wypisuje "Hello, world!" do logu programu.

Utwórz nowy program

Najpierw utwórz nowy projekt w Rust, używając standardowego polecenia cargo init z flagą --lib.

Terminal
cargo init hello_world --lib

Przejdź do katalogu projektu. Powinieneś zobaczyć domyślne pliki src/lib.rs i Cargo.toml.

Terminal
cd hello_world

Następnie dodaj zależność solana-program. Jest to minimalna zależność wymagana do stworzenia programu Solana.

Terminal
cargo add solana-program@1.18.26

Następnie dodaj poniższy fragment kodu do Cargo.toml. Jeśli nie uwzględnisz tej konfiguracji, katalog target/deploy nie zostanie wygenerowany podczas budowania programu.

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

Twój plik Cargo.toml powinien wyglądać następująco:

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

Następnie zastąp zawartość src/lib.rs poniższym kodem. Jest to minimalny program Solana, który wypisuje "Hello, world!" do dziennika programu, gdy program zostanie wywołany.

Makro msg! jest używane w programach Solana do wypisywania wiadomości do dziennika programu.

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(())
}

Zbuduj program

Następnie zbuduj program za pomocą polecenia cargo build-sbf.

Terminal
cargo build-sbf

To polecenie generuje katalog target/deploy zawierający dwa ważne pliki:

  1. Plik .so (np. hello_world.so): Jest to skompilowany program Solana, który zostanie wdrożony w sieci jako "smart contract".
  2. Plik keypair (np. hello_world-keypair.json): Klucz publiczny tego keypair jest używany jako identyfikator programu podczas wdrażania programu.

Aby wyświetlić identyfikator programu, uruchom następujące polecenie w terminalu. To polecenie wypisuje klucz publiczny keypair znajdującego się w określonej ścieżce pliku:

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

Przykładowy wynik:

4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz

Przetestuj program

Następnie przetestuj program za pomocą pakietu solana-program-test. Dodaj poniższe dependencje do Cargo.toml.

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

Dodaj poniższy test do src/lib.rs, poniżej kodu programu. Jest to moduł testowy, który wywołuje program 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());
}
}

Uruchom test za pomocą polecenia cargo test-sbf. Dziennik programu wyświetli "Hello, world!".

Terminal
cargo test-sbf

Przykładowy wynik:

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

Wdróż program

Następnie wdróż program. Podczas pracy lokalnej możemy użyć solana-test-validator.

Najpierw skonfiguruj Solana CLI, aby używało lokalnego klastra Solana.

Terminal
solana config set -ul

Przykładowy wynik:

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

Otwórz nowe okno terminala i uruchom polecenie solana-test-validators, aby uruchomić lokalny validator.

Terminal
solana-test-validator

Podczas działania testowego validatora uruchom polecenie solana program deploy w osobnym terminalu, aby wdróż program do lokalnego validatora.

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

Przykładowy wynik:

Program Id: 4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz
Signature:
5osMiNMiDZGM7L1e2tPHxU8wdB8gwG8fDnXLg5G7SbhwFz4dHshYgAijk4wSQL5cXiu8z1MMou5kLadAQuHp7ybH

Możesz sprawdzić ID programu i sygnaturę transakcji w Solana Explorer. Zwróć uwagę, że klaster w Solana Explorer musi być również localhost. Opcja "Custom RPC URL" w Solana Explorer domyślnie wskazuje na http://localhost:8899.

Wywołaj program

Następnie pokażemy, jak wywołać program za pomocą klienta Rust.

Najpierw utwórz katalog examples i plik client.rs.

Terminal
mkdir -p examples
touch examples/client.rs

Dodaj poniższe do Cargo.toml.

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

Dodaj zależność solana-client.

Terminal
cargo add solana-client@1.18.26 --dev

Dodaj następujący kod do examples/client.rs. Jest to skrypt klienta w języku Rust, który finansuje nowy keypair, aby opłacić opłaty transakcyjne, a następnie wywołuje program "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),
}
}

Przed uruchomieniem skryptu zamień ID programu w powyższym fragmencie kodu na ID swojego programu.

Możesz uzyskać ID swojego programu, uruchamiając następujące polecenie.

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();
}
}

Uruchom skrypt klienta za pomocą następującego polecenia.

Terminal
cargo run --example client

Przykładowy wynik:

Transaction Signature: 54TWxKi3Jsi3UTeZbhLGUFX6JQH7TspRJjRRFZ8NFnwG5BXM9udxiX77bAACjKAS9fGnVeEazrXL4SfKrW7xZFYV

Możesz sprawdzić podpis transakcji w Solana Explorer (lokalny klaster), aby zobaczyć "Hello, world!" w logu programu.

Zaktualizuj program

Programy Solana można aktualizować, ponownie wdrażając je pod tym samym ID programu. Zaktualizuj program w src/lib.rs, aby wyświetlał "Hello, Solana!" zamiast "Hello, world!".

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

Przetestuj zaktualizowany program, uruchamiając polecenie cargo test-sbf.

Terminal
cargo test-sbf

Powinieneś zobaczyć "Hello, Solana!" w logu programu.

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

Uruchom polecenie cargo build-sbf, aby wygenerować zaktualizowany plik .so.

Terminal
cargo build-sbf

Ponownie wdroż program za pomocą polecenia solana program deploy.

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

Uruchom ponownie kod klienta i sprawdź podpis transakcji w Solana Explorer, aby zobaczyć "Hello, Solana!" w logu programu.

Terminal
cargo run --example client

Zamknij program

Możesz zamknąć swój program Solana, aby odzyskać SOL przypisane do konta. Zamknięcie programu jest nieodwracalne, dlatego należy to zrobić ostrożnie.

Aby zamknąć program, użyj polecenia solana program close <PROGRAM_ID>. Na przykład:

Terminal
solana program close 4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz
--bypass-warning

Przykładowy wynik:

Closed Program Id 4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz, 0.1350588 SOL
reclaimed

Pamiętaj, że po zamknięciu programu jego identyfikator (program ID) nie może być ponownie użyty. Próba wdrożenia programu z wcześniej zamkniętym identyfikatorem programu zakończy się błędem.

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

Jeśli musisz ponownie wdrożyć program z tym samym kodem źródłowym po jego zamknięciu, musisz wygenerować nowy identyfikator programu. Aby wygenerować nową parę kluczy dla programu, uruchom następujące polecenie:

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

Alternatywnie możesz usunąć istniejący plik pary kluczy (np. ./target/deploy/hello_world-keypair.json) i ponownie uruchomić cargo build-sbf, co spowoduje wygenerowanie nowego pliku pary kluczy.

Is this page helpful?

Spis treści

Edytuj stronę