Sviluppare programmi in Rust
I programmi Solana sono principalmente sviluppati utilizzando il linguaggio di programmazione Rust. Questa pagina si concentra sulla scrittura di programmi Solana in Rust senza utilizzare il framework Anchor, un approccio spesso definito come scrittura di programmi "Rust nativi".
Lo sviluppo in Rust nativo offre agli sviluppatori un controllo diretto sui loro programmi Solana. Tuttavia, questo approccio richiede più configurazione manuale e codice boilerplate rispetto all'utilizzo del framework Anchor. Questo metodo è consigliato per gli sviluppatori che:
- Cercano un controllo granulare sulla logica del programma e sulle ottimizzazioni
- Vogliono imparare i concetti di base prima di passare a framework di livello superiore
Per i principianti, consigliamo di iniziare con il framework Anchor. Consulta la sezione Anchor per maggiori informazioni.
Prerequisiti
Per istruzioni dettagliate sull'installazione, visita la pagina di installazione.
Prima di iniziare, assicurati di avere installato quanto segue:
- Rust: Il linguaggio di programmazione per costruire programmi Solana.
- Solana CLI: Strumento da riga di comando per lo sviluppo Solana.
Primi passi
L'esempio seguente copre i passaggi di base per creare il tuo primo programma Solana scritto in Rust. Creeremo un programma minimo che stampa "Hello, world!" nel log del programma.
Crea un nuovo programma
Prima, crea un nuovo progetto Rust utilizzando il comando standard cargo init
con l'opzione --lib
.
cargo init hello_world --lib
Naviga nella directory del progetto. Dovresti vedere i file predefiniti
src/lib.rs
e Cargo.toml
cd hello_world
Successivamente, aggiungi la dipendenza solana-program
. Questa è la dipendenza
minima richiesta per costruire un programma Solana.
cargo add solana-program@1.18.26
Successivamente, aggiungi il seguente snippet a Cargo.toml
. Se non includi
questa configurazione, la directory target/deploy
non verrà generata quando
compili il programma.
[lib]crate-type = ["cdylib", "lib"]
Il tuo file Cargo.toml
dovrebbe apparire come segue:
[package]name = "hello_world"version = "0.1.0"edition = "2021"[lib]crate-type = ["cdylib", "lib"][dependencies]solana-program = "1.18.26"
Successivamente, sostituisci il contenuto di src/lib.rs
con il seguente
codice. Questo è un programma Solana minimale che stampa "Hello, world!" nel log
del programma quando viene invocato.
La macro msg!
viene utilizzata nei programmi Solana per stampare un messaggio
nel log del programma.
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(())}
Compila il programma
Successivamente, compila il programma utilizzando il comando cargo build-sbf
.
cargo build-sbf
Questo comando genera una directory target/deploy
contenente due file
importanti:
- Un file
.so
(es.,hello_world.so
): Questo è il programma Solana compilato che verrà distribuito sulla rete come "smart contract". - Un file keypair (es.,
hello_world-keypair.json
): La chiave pubblica di questo keypair viene utilizzata come ID del programma durante la distribuzione del programma.
Per visualizzare l'ID del programma, esegui il seguente comando nel tuo terminale. Questo comando stampa la chiave pubblica del keypair nel percorso file specificato:
solana address -k ./target/deploy/hello_world-keypair.json
Esempio di output:
4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz
Testa il programma
Successivamente, testa il programma utilizzando il crate solana-program-test
.
Aggiungi le seguenti dipendenze a Cargo.toml
.
cargo add solana-program-test@1.18.26 --devcargo add solana-sdk@1.18.26 --devcargo add tokio --dev
Aggiungi il seguente test a src/lib.rs
, sotto il codice del programma. Questo
è un modulo di test che invoca il programma 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());}}
Esegui il test utilizzando il comando cargo test-sbf
. Il log del programma
mostrerà "Hello, world!".
cargo test-sbf
Output di esempio:
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
Distribuisci il programma
Successivamente, distribuisci il programma. Durante lo sviluppo locale, possiamo
utilizzare il solana-test-validator
.
Prima, configura la CLI di Solana per utilizzare il cluster Solana locale.
solana config set -ul
Output di esempio:
Config File: /.config/solana/cli/config.ymlRPC URL: http://localhost:8899WebSocket URL: ws://localhost:8900/ (computed)Keypair Path: /.config/solana/id.jsonCommitment: confirmed
Apri un nuovo terminale ed esegui il comando solana-test-validators
per
avviare il validator locale.
solana-test-validator
Mentre il validator di test è in esecuzione, esegui il comando
solana program deploy
in un terminale separato per distribuire il programma al
validator locale.
solana program deploy ./target/deploy/hello_world.so
Output di esempio:
Program Id: 4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMzSignature:5osMiNMiDZGM7L1e2tPHxU8wdB8gwG8fDnXLg5G7SbhwFz4dHshYgAijk4wSQL5cXiu8z1MMou5kLadAQuHp7ybH
Puoi ispezionare l'ID del programma e la firma della transazione su
Solana Explorer.
Nota che il cluster su Solana Explorer deve essere anch'esso localhost.
L'opzione "Custom RPC URL" su Solana Explorer è impostata di default su
http://localhost:8899
.
Invoca il programma
Successivamente, dimostreremo come invocare il programma utilizzando un client Rust.
Prima crea una directory examples
e un file client.rs
.
mkdir -p examplestouch examples/client.rs
Aggiungi quanto segue a Cargo.toml
.
[[example]]name = "client"path = "examples/client.rs"
Aggiungi la dipendenza solana-client
.
cargo add solana-client@1.18.26 --dev
Aggiungi il seguente codice a examples/client.rs
. Questo è uno script client
in Rust che finanzia un nuovo keypair per pagare le commissioni di transazione e
poi invoca il programma 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),}}
Prima di eseguire lo script, sostituisci l'ID del programma nel frammento di codice sopra con quello del tuo programma.
Puoi ottenere l'ID del tuo programma eseguendo il seguente comando.
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();}}
Esegui lo script client con il seguente comando.
cargo run --example client
Esempio di output:
Transaction Signature: 54TWxKi3Jsi3UTeZbhLGUFX6JQH7TspRJjRRFZ8NFnwG5BXM9udxiX77bAACjKAS9fGnVeEazrXL4SfKrW7xZFYV
Puoi ispezionare la firma della transazione su Solana Explorer (cluster locale) per vedere "Hello, world!" nel log del programma.
Aggiornare il programma
I programmi Solana possono essere aggiornati ridistribuendoli allo stesso ID
programma. Aggiorna il programma in src/lib.rs
per stampare "Hello, Solana!"
invece di "Hello, world!".
pub fn process_instruction(_program_id: &Pubkey,_accounts: &[AccountInfo],_instruction_data: &[u8],) -> ProgramResult {- msg!("Hello, world!");+ msg!("Hello, Solana!");Ok(())}
Testa il programma aggiornato eseguendo il comando cargo test-sbf
.
cargo test-sbf
Dovresti vedere "Hello, Solana!" nel log del programma.
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
Esegui il comando cargo build-sbf
per generare un file .so
aggiornato.
cargo build-sbf
Ridistribuisci il programma usando il comando solana program deploy
.
solana program deploy ./target/deploy/hello_world.so
Esegui nuovamente il codice client e ispeziona la firma della transazione su Solana Explorer per vedere "Hello, Solana!" nel log del programma.
cargo run --example client
Chiudere il programma
Puoi chiudere il tuo programma Solana per recuperare il SOL allocato all'account. La chiusura di un programma è irreversibile, quindi dovrebbe essere fatta con cautela.
Per chiudere un programma, usa il comando solana program close <PROGRAM_ID>
.
Per esempio:
solana program close 4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz--bypass-warning
Output di esempio:
Closed Program Id 4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz, 0.1350588 SOLreclaimed
Nota che una volta chiuso un programma, il suo program ID non può essere riutilizzato. Il tentativo di distribuire un programma con un program ID precedentemente chiuso risulterà in un errore.
Error: Program 4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz has been closed, usea new Program Id
Se hai bisogno di ridistribuire un programma con lo stesso codice sorgente dopo aver chiuso un programma, devi generare un nuovo program ID. Per generare una nuova keypair per il programma, esegui il seguente comando:
solana-keygen new -o ./target/deploy/hello_world-keypair.json --force
In alternativa, puoi eliminare il file keypair esistente (ad es.
./target/deploy/hello_world-keypair.json
) ed eseguire nuovamente
cargo build-sbf
, che genererà un nuovo file keypair.
Is this page helpful?