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
.
cargo init hello_world --lib
Przejdź do katalogu projektu. Powinieneś zobaczyć domyślne pliki src/lib.rs
i
Cargo.toml
.
cd hello_world
Następnie dodaj zależność solana-program
. Jest to minimalna zależność wymagana
do stworzenia programu Solana.
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.
[lib]crate-type = ["cdylib", "lib"]
Twój plik Cargo.toml
powinien wyglądać następująco:
[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.
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
.
cargo build-sbf
To polecenie generuje katalog target/deploy
zawierający dwa ważne pliki:
- Plik
.so
(np.hello_world.so
): Jest to skompilowany program Solana, który zostanie wdrożony w sieci jako "smart contract". - 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:
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
.
cargo add solana-program-test@1.18.26 --devcargo add solana-sdk@1.18.26 --devcargo 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.
#[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());}}
Uruchom test za pomocą polecenia cargo test-sbf
. Dziennik programu wyświetli
"Hello, world!".
cargo test-sbf
Przykładowy wynik:
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
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.
solana config set -ul
Przykładowy wynik:
Config File: /.config/solana/cli/config.ymlRPC URL: http://localhost:8899WebSocket URL: ws://localhost:8900/ (computed)Keypair Path: /.config/solana/id.jsonCommitment: confirmed
Otwórz nowe okno terminala i uruchom polecenie solana-test-validators
, aby
uruchomić lokalny validator.
solana-test-validator
Podczas działania testowego validatora uruchom polecenie solana program deploy
w osobnym terminalu, aby wdróż program do lokalnego validatora.
solana program deploy ./target/deploy/hello_world.so
Przykładowy wynik:
Program Id: 4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMzSignature: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
.
mkdir -p examplestouch examples/client.rs
Dodaj poniższe do Cargo.toml
.
[[example]]name = "client"path = "examples/client.rs"
Dodaj zależność solana-client
.
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".
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),}}
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.
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.
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!".
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
.
cargo test-sbf
Powinieneś zobaczyć "Hello, Solana!" w logu programu.
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
Uruchom polecenie cargo build-sbf
, aby wygenerować zaktualizowany plik .so
.
cargo build-sbf
Ponownie wdroż program za pomocą polecenia solana program deploy
.
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.
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:
solana program close 4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz--bypass-warning
Przykładowy wynik:
Closed Program Id 4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz, 0.1350588 SOLreclaimed
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, usea 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:
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?