Sviluppo di 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 su 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 new
con il flag --lib
.
$cargo new hello_world --lib
Naviga nella directory del progetto. Dovresti vedere i file predefiniti
src/lib.rs
e Cargo.toml
$cd hello_world
Aggiorna il campo edition
in Cargo.toml
a 2021
. Altrimenti, potresti
incontrare un errore durante la compilazione del programma.
Aggiungi la dipendenza solana-program
Successivamente, aggiungi la dipendenza solana-program
. Questa è la dipendenza
minima richiesta per costruire un programma Solana.
$cargo add solana-program@2.2.0
Aggiungi il crate-type
Successivamente, aggiungi il seguente snippet a Cargo.toml
.
[lib]crate-type = ["cdylib", "lib"]
Se non includi questa configurazione, la directory target/deploy
non verrà
generata quando compili il programma.
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 = "2.2.0"
Aggiungi il codice del programma
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 il programma 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 del file specificato:
$solana address -k ./target/deploy/hello_world-keypair.json
Esempio di output:
4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz
Aggiungi dipendenze per i test
Successivamente, testa il programma utilizzando il crate litesvm
. Aggiungi le
seguenti dipendenze al file Cargo.toml
.
$cargo add litesvm --dev$cargo add solana-sdk@2.2.0 --dev
Testa il programma
Aggiungi il seguente test a src/lib.rs
, sotto il codice del programma. Questo
è un modulo di test che invoca il programma 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:#?}");}}
Esegui il test usando il comando cargo test
. Il log del programma mostrerà
"Hello, world!".
$cargo test -- --no-capture
Esempio di output:
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
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
Esempio di output:
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
Esempio di output:
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
.
Crea un client di esempio
Successivamente, dimostreremo come invocare il programma utilizzando un client Rust.
Prima crea una directory examples
e un file client.rs
.
$mkdir -p examples && touch examples/client.rs
Aggiungi quanto segue a Cargo.toml
.
[[example]]name = "client"path = "examples/client.rs"
Aggiungi le dipendenze solana-client
e tokio
.
$cargo add solana-client@2.2.0 --dev$cargo add tokio --dev
Aggiungi il client
Aggiungi il seguente codice a examples/client.rs
. Questo è uno script client
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://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),}}
Sostituisci l'ID del programma
Prima di eseguire il codice client, sostituisci l'ID del programma nel frammento di codice 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
Invoca il programma
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.
Aggiorna 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(())}
Esegui il comando cargo build-sbf
per generare un file .so
aggiornato.
$cargo build-sbf
Testa il programma aggiornato eseguendo il comando cargo test
.
$cargo test -- --no-capture
Dovresti vedere "Hello, Solana!" nel log del programma.
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
Ridistribuisci il programma
Ridistribuisci il programma utilizzando lo stesso 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
Chiudi 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
Esempio di output:
Closed Program Id 4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz, 0.1350588 SOLreclaimed
Nota che una volta che un programma è chiuso, il suo ID programma non può essere riutilizzato. Il tentativo di distribuire un programma con un ID programma precedentemente chiuso risulterà in un errore.
Error: Program 4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz has been closed, usea new Program Id
Ridistribuire un programma chiuso
Se hai bisogno di ridistribuire un programma con lo stesso codice sorgente dopo aver chiuso un programma, devi generare un nuovo ID programma. Per generare un nuovo 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 cargo build-sbf
di
nuovo, che genererà un nuovo file keypair.
Is this page helpful?