Documentation SolanaDéveloppement de programmes

Développement de programmes en Rust

Les programmes Solana sont principalement développés en utilisant le langage de programmation Rust. Cette page se concentre sur l'écriture de programmes Solana en Rust sans utiliser le framework Anchor, une approche souvent appelée écriture de programmes "Rust natifs".

Le développement en Rust natif offre aux développeurs un contrôle direct sur leurs programmes Solana. Cependant, cette approche nécessite plus de configuration manuelle et de code standard par rapport à l'utilisation du framework Anchor. Cette méthode est recommandée pour les développeurs qui :

  • Recherchent un contrôle granulaire sur la logique et les optimisations du programme
  • Souhaitent apprendre les concepts sous-jacents avant de passer à des frameworks de plus haut niveau

Pour les débutants, nous recommandons de commencer avec le framework Anchor. Consultez la section Anchor pour plus d'informations.

Prérequis

Pour des instructions d'installation détaillées, visitez la page installation.

Avant de commencer, assurez-vous d'avoir installé les éléments suivants :

  • Rust : Le langage de programmation pour construire des programmes Solana.
  • Solana CLI : Outil en ligne de commande pour le développement Solana.

Premiers pas

L'exemple ci-dessous couvre les étapes de base pour créer votre premier programme Solana écrit en Rust. Nous allons créer un programme minimal qui affiche "Hello, world !" dans le journal du programme.

Créer un nouveau programme

D'abord, créez un nouveau projet Rust en utilisant la commande standard cargo init avec l'option --lib.

Terminal
cargo init hello_world --lib

Naviguez vers le répertoire du projet. Vous devriez voir les fichiers par défaut src/lib.rs et Cargo.toml

Terminal
cd hello_world

Ensuite, ajoutez la dépendance solana-program. C'est la dépendance minimale requise pour construire un programme Solana.

Terminal
cargo add solana-program@1.18.26

Ensuite, ajoutez l'extrait suivant à Cargo.toml. Si vous n'incluez pas cette configuration, le répertoire target/deploy ne sera pas généré lors de la compilation du programme.

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

Votre fichier Cargo.toml devrait ressembler à ce qui suit :

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

Ensuite, remplacez le contenu de src/lib.rs par le code suivant. Il s'agit d'un programme Solana minimal qui affiche "Hello, world!" dans le journal du programme lorsque le programme est invoqué.

La macro msg! est utilisée dans les programmes Solana pour imprimer un message dans le journal du programme.

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

Compiler le programme

Ensuite, compilez le programme en utilisant la commande cargo build-sbf.

Terminal
cargo build-sbf

Cette commande génère un répertoire target/deploy contenant deux fichiers importants :

  1. Un fichier .so (par exemple, hello_world.so) : c'est le programme Solana compilé qui sera déployé sur le réseau en tant que "smart contract".
  2. Un fichier de paire de clés (par exemple, hello_world-keypair.json) : la clé publique de cette paire de clés est utilisée comme ID de programme lors du déploiement du programme.

Pour afficher l'ID du programme, exécutez la commande suivante dans votre terminal. Cette commande affiche la clé publique de la paire de clés au chemin de fichier spécifié :

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

Exemple de sortie :

4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz

Tester le programme

Ensuite, testez le programme en utilisant la crate solana-program-test. Ajoutez les dépendances suivantes à Cargo.toml.

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

Ajoutez le test suivant à src/lib.rs, en dessous du code du programme. Il s'agit d'un module de test qui invoque le programme 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());
}
}

Exécutez le test en utilisant la commande cargo test-sbf. Le journal du programme affichera "Hello, world!".

Terminal
cargo test-sbf

Exemple de sortie :

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

Déployer le programme

Ensuite, déployez le programme. Lors du développement en local, nous pouvons utiliser le solana-test-validator.

D'abord, configurez le CLI Solana pour utiliser le cluster Solana local.

Terminal
solana config set -ul

Exemple de sortie :

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

Ouvrez un nouveau terminal et exécutez la commande solana-test-validators pour démarrer le validateur local.

Terminal
solana-test-validator

Pendant que le validateur de test est en cours d'exécution, lancez la commande solana program deploy dans un terminal séparé pour déployer le programme sur le validateur local.

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

Exemple de sortie :

Program Id: 4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz
Signature:
5osMiNMiDZGM7L1e2tPHxU8wdB8gwG8fDnXLg5G7SbhwFz4dHshYgAijk4wSQL5cXiu8z1MMou5kLadAQuHp7ybH

Vous pouvez inspecter l'ID du programme et la signature de transaction sur Solana Explorer. Notez que le cluster sur Solana Explorer doit également être localhost. L'option "Custom RPC URL" sur Solana Explorer est par défaut http://localhost:8899.

Invoquer le programme

Ensuite, nous allons démontrer comment invoquer le programme en utilisant un client Rust.

Créez d'abord un répertoire examples et un fichier client.rs.

Terminal
mkdir -p examples
touch examples/client.rs

Ajoutez ce qui suit à Cargo.toml.

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

Ajoutez la dépendance solana-client.

Terminal
cargo add solana-client@1.18.26 --dev

Ajoutez le code suivant à examples/client.rs. Il s'agit d'un script client Rust qui finance une nouvelle paire de clés pour payer les frais de transaction, puis invoque le programme 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),
}
}

Avant d'exécuter le script, remplacez l'ID du programme dans l'extrait de code ci-dessus par celui de votre programme.

Vous pouvez obtenir l'ID de votre programme en exécutant la commande suivante.

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

Exécutez le script client avec la commande suivante.

Terminal
cargo run --example client

Exemple de sortie :

Transaction Signature: 54TWxKi3Jsi3UTeZbhLGUFX6JQH7TspRJjRRFZ8NFnwG5BXM9udxiX77bAACjKAS9fGnVeEazrXL4SfKrW7xZFYV

Vous pouvez inspecter la signature de transaction sur Solana Explorer (cluster local) pour voir "Hello, world!" dans le journal du programme.

Mettre à jour le programme

Les programmes Solana peuvent être mis à jour en redéployant sur le même ID de programme. Mettez à jour le programme dans src/lib.rs pour afficher "Hello, Solana!" au lieu de "Hello, world!".

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

Testez le programme mis à jour en exécutant la commande cargo test-sbf.

Terminal
cargo test-sbf

Vous devriez voir "Hello, Solana!" dans le journal du programme.

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

Exécutez la commande cargo build-sbf pour générer un fichier .so mis à jour.

Terminal
cargo build-sbf

Redéployez le programme en utilisant la commande solana program deploy.

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

Exécutez à nouveau le code client et inspectez la signature de transaction sur Solana Explorer pour voir "Hello, Solana!" dans le journal du programme.

Terminal
cargo run --example client

Fermer le programme

Vous pouvez fermer votre programme Solana pour récupérer le SOL alloué au compte. La fermeture d'un programme est irréversible, elle doit donc être effectuée avec prudence.

Pour fermer un programme, utilisez la commande solana program close <PROGRAM_ID>. Par exemple :

Terminal
solana program close 4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz
--bypass-warning

Exemple de sortie :

Closed Program Id 4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz, 0.1350588 SOL
reclaimed

Notez qu'une fois qu'un programme est fermé, son ID de programme ne peut plus être réutilisé. Tenter de déployer un programme avec un ID de programme précédemment fermé entraînera une erreur.

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

Si vous devez redéployer un programme avec le même code source après avoir fermé un programme, vous devez générer un nouvel ID de programme. Pour générer une nouvelle paire de clés pour le programme, exécutez la commande suivante :

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

Alternativement, vous pouvez supprimer le fichier de paire de clés existant (par exemple ./target/deploy/hello_world-keypair.json) et exécuter cargo build-sbf à nouveau, ce qui générera un nouveau fichier de paire de clés.

Is this page helpful?

Table des matières

Modifier la page