Documentazione SolanaSviluppo di programmi

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.

Terminal
$
cargo new hello_world --lib

Naviga nella directory del progetto. Dovresti vedere i file predefiniti src/lib.rs e Cargo.toml

Terminal
$
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.

Terminal
$
cargo add solana-program@2.2.0

Aggiungi il crate-type

Successivamente, aggiungi il seguente snippet a Cargo.toml.

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:

Cargo.toml
[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.

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

Compila il programma

Successivamente, compila il programma utilizzando il comando cargo build-sbf.

Terminal
$
cargo build-sbf

Questo comando genera una directory target/deploy contenente due file importanti:

  1. Un file .so (es., hello_world.so): Questo è il programma Solana compilato che verrà distribuito sulla rete come "smart contract".
  2. 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:

Terminal
$
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.

Terminal
$
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.

src/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(())
}
#[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 instance
let mut svm = LiteSVM::new();
// Create a keypair for the transaction payer
let payer = Keypair::new();
// Airdrop some lamports to the payer
svm.airdrop(&payer.pubkey(), 1_000_000_000).unwrap();
// Load our program
let 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 data
let instruction = Instruction {
program_id,
accounts: vec![],
data: vec![],
};
// Create transaction
let message = Message::new(&[instruction], Some(&payer.pubkey()));
let transaction = Transaction::new(&[&payer], message, svm.latest_blockhash());
// Send transaction and verify it succeeds
let 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!".

Terminal
$
cargo test -- --no-capture

Esempio di output:

Terminal
running 1 test
Logs: [
"Program 9528phXNvdWp5kkR4rgpoeZvR8ZWT5THVywK95YRprkk invoke [1]",
"Program log: Hello, world!",
"Program 9528phXNvdWp5kkR4rgpoeZvR8ZWT5THVywK95YRprkk consumed 211 of 200000 compute units",
"Program 9528phXNvdWp5kkR4rgpoeZvR8ZWT5THVywK95YRprkk success",
]
test test::test_hello_world ... ok
test 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.

Terminal
$
solana config set -ul

Esempio di output:

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

Apri un nuovo terminale ed esegui il comando solana-test-validators per avviare il validator locale.

Terminal
$
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.

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

Esempio di output:

Program Id: 4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz
Signature:
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.

Terminal
$
mkdir -p examples && touch examples/client.rs

Aggiungi quanto segue a Cargo.toml.

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

Aggiungi le dipendenze solana-client e tokio.

Terminal
$
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.

examples/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://localhost: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),
}
}

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.

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

Invoca il programma

Esegui lo script client con il seguente comando.

Terminal
$
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!".

lib.rs
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.

Terminal
$
cargo build-sbf

Testa il programma aggiornato eseguendo il comando cargo test.

Terminal
$
cargo test -- --no-capture

Dovresti vedere "Hello, Solana!" nel log del programma.

Terminal
running 1 test
Logs: [
"Program 5y8bHrnwfq2dLDgLn3WoTHb9dDuyorj9gyapW6aeyrpV invoke [1]",
"Program log: Hello, Solana!",
"Program 5y8bHrnwfq2dLDgLn3WoTHb9dDuyorj9gyapW6aeyrpV consumed 211 of 200000 compute units",
"Program 5y8bHrnwfq2dLDgLn3WoTHb9dDuyorj9gyapW6aeyrpV success",
]
test test::test_hello_world ... ok
test 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.

Terminal
$
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.

Terminal
$
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:

Terminal
$
solana program close 4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz --bypass-warning

Esempio di output:

Closed Program Id 4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz, 0.1350588 SOL
reclaimed

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, use
a 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:

Terminal
$
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.

Crea un nuovo programma

Prima, crea un nuovo progetto Rust utilizzando il comando standard cargo new con il flag --lib.

Terminal
$
cargo new hello_world --lib

Naviga nella directory del progetto. Dovresti vedere i file predefiniti src/lib.rs e Cargo.toml

Terminal
$
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.

Terminal
$
cargo add solana-program@2.2.0

Aggiungi il crate-type

Successivamente, aggiungi il seguente snippet a Cargo.toml.

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

Se non includi questa configurazione, la directory target/deploy non verrà generata quando compili il programma.

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.

Compila il programma

Successivamente, compila il programma utilizzando il comando cargo build-sbf.

Terminal
$
cargo build-sbf

Questo comando genera una directory target/deploy contenente due file importanti:

  1. Un file .so (es., hello_world.so): Questo è il programma Solana compilato che verrà distribuito sulla rete come "smart contract".
  2. 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:

Terminal
$
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.

Terminal
$
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.

Esegui il test usando il comando cargo test. Il log del programma mostrerà "Hello, world!".

Terminal
$
cargo test -- --no-capture

Esempio di output:

Terminal
running 1 test
Logs: [
"Program 9528phXNvdWp5kkR4rgpoeZvR8ZWT5THVywK95YRprkk invoke [1]",
"Program log: Hello, world!",
"Program 9528phXNvdWp5kkR4rgpoeZvR8ZWT5THVywK95YRprkk consumed 211 of 200000 compute units",
"Program 9528phXNvdWp5kkR4rgpoeZvR8ZWT5THVywK95YRprkk success",
]
test test::test_hello_world ... ok
test 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.

Terminal
$
solana config set -ul

Esempio di output:

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

Apri un nuovo terminale ed esegui il comando solana-test-validators per avviare il validator locale.

Terminal
$
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.

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

Esempio di output:

Program Id: 4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz
Signature:
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.

Terminal
$
mkdir -p examples && touch examples/client.rs

Aggiungi quanto segue a Cargo.toml.

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

Aggiungi le dipendenze solana-client e tokio.

Terminal
$
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.

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.

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

Invoca il programma

Esegui lo script client con il seguente comando.

Terminal
$
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!".

lib.rs
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.

Terminal
$
cargo build-sbf

Testa il programma aggiornato eseguendo il comando cargo test.

Terminal
$
cargo test -- --no-capture

Dovresti vedere "Hello, Solana!" nel log del programma.

Terminal
running 1 test
Logs: [
"Program 5y8bHrnwfq2dLDgLn3WoTHb9dDuyorj9gyapW6aeyrpV invoke [1]",
"Program log: Hello, Solana!",
"Program 5y8bHrnwfq2dLDgLn3WoTHb9dDuyorj9gyapW6aeyrpV consumed 211 of 200000 compute units",
"Program 5y8bHrnwfq2dLDgLn3WoTHb9dDuyorj9gyapW6aeyrpV success",
]
test test::test_hello_world ... ok
test 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.

Terminal
$
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.

Terminal
$
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:

Terminal
$
solana program close 4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz --bypass-warning

Esempio di output:

Closed Program Id 4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz, 0.1350588 SOL
reclaimed

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, use
a 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:

Terminal
$
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.

lib.rs
Cargo.toml
[package]
name = "hello_world"
version = "0.1.0"
edition = "2021"
[dependencies]

Is this page helpful?

Indice

Modifica Pagina