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 new avec le drapeau --lib.

Terminal
$
cargo new 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

Mettez à jour le champ edition dans Cargo.toml à 2021. Sinon, vous pourriez rencontrer une erreur lors de la compilation du programme.

Ajouter la dépendance solana-program

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

Terminal
$
cargo add solana-program@2.2.0

Ajouter le crate-type

Ensuite, ajoutez l'extrait suivant à Cargo.toml.

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

Si vous n'incluez pas cette configuration, le répertoire target/deploy ne sera pas généré lorsque vous construirez le programme.

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 = "2.2.0"

Ajouter le code du programme

Ensuite, remplacez le contenu de src/lib.rs par le code suivant. C'est 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 afficher un message dans le journal du programme.

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

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 ex., hello_world.so) : C'est le programme Solana compilé qui sera déployé sur le réseau comme un "smart contract".
  2. Un fichier keypair (par ex., hello_world-keypair.json) : La clé publique de ce keypair est utilisée comme ID du programme lors du déploiement du programme.

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

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

Exemple de sortie :

4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz

Ajouter les dépendances de test

Ensuite, testez le programme en utilisant le crate litesvm. Ajoutez les dépendances suivantes à Cargo.toml.

Terminal
$
cargo add litesvm --dev
$
cargo add solana-sdk@2.2.0 --dev

Tester le programme

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

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

Terminal
$
cargo test -- --no-capture

Exemple de sortie :

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

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 l'interface en ligne de commande 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 validator local.

Terminal
$
solana-test-validator

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

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

Exemple de sortie :

Program Id: 4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz
Signature:
5osMiNMiDZGM7L1e2tPHxU8wdB8gwG8fDnXLg5G7SbhwFz4dHshYgAijk4wSQL5cXiu8z1MMou5kLadAQuHp7ybH

Vous pouvez examiner 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 "URL RPC personnalisée" sur Solana Explorer est par défaut http://localhost:8899.

Créer un client d'exemple

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 les dépendances solana-client et tokio.

Terminal
$
cargo add solana-client@2.2.0 --dev
$
cargo add tokio --dev

Ajouter le client

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

Remplacer l'ID du programme

Avant d'exécuter le code client, remplacez l'ID du programme dans l'extrait de code 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

Invoquer le programme

Exécutez le script client avec la commande suivante.

Terminal
$
cargo run --example client

Exemple de sortie :

Transaction Signature: 54TWxKi3Jsi3UTeZbhLGUFX6JQH7TspRJjRRFZ8NFnwG5BXM9udxiX77bAACjKAS9fGnVeEazrXL4SfKrW7xZFYV

Vous pouvez examiner la signature de la 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(())
}

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

Terminal
$
cargo build-sbf

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

Terminal
$
cargo test -- --no-capture

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

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

Redéployer le programme

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

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

Exécutez à nouveau le code client et examinez la signature de la 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 pas être réutilisé. Toute tentative 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

Redéployer un programme fermé

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 un nouveau keypair 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 keypair existant (par ex. ./target/deploy/hello_world-keypair.json) et exécuter cargo build-sbf à nouveau, ce qui générera un nouveau fichier keypair.

Créer un nouveau programme

D'abord, créez un nouveau projet Rust en utilisant la commande standard cargo new avec le drapeau --lib.

Terminal
$
cargo new 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

Mettez à jour le champ edition dans Cargo.toml à 2021. Sinon, vous pourriez rencontrer une erreur lors de la compilation du programme.

Ajouter la dépendance solana-program

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

Terminal
$
cargo add solana-program@2.2.0

Ajouter le crate-type

Ensuite, ajoutez l'extrait suivant à Cargo.toml.

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

Si vous n'incluez pas cette configuration, le répertoire target/deploy ne sera pas généré lorsque vous construirez le programme.

Ajouter le code du programme

Ensuite, remplacez le contenu de src/lib.rs par le code suivant. C'est 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 afficher un message dans le journal du programme.

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 ex., hello_world.so) : C'est le programme Solana compilé qui sera déployé sur le réseau comme un "smart contract".
  2. Un fichier keypair (par ex., hello_world-keypair.json) : La clé publique de ce keypair est utilisée comme ID du programme lors du déploiement du programme.

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

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

Exemple de sortie :

4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz

Ajouter les dépendances de test

Ensuite, testez le programme en utilisant le crate litesvm. Ajoutez les dépendances suivantes à Cargo.toml.

Terminal
$
cargo add litesvm --dev
$
cargo add solana-sdk@2.2.0 --dev

Tester le programme

Ajoutez le test suivant à src/lib.rs, sous le code du programme. Il s'agit d'un module de test qui invoque le programme hello world.

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

Terminal
$
cargo test -- --no-capture

Exemple de sortie :

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

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 l'interface en ligne de commande 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 validator local.

Terminal
$
solana-test-validator

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

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

Exemple de sortie :

Program Id: 4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz
Signature:
5osMiNMiDZGM7L1e2tPHxU8wdB8gwG8fDnXLg5G7SbhwFz4dHshYgAijk4wSQL5cXiu8z1MMou5kLadAQuHp7ybH

Vous pouvez examiner 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 "URL RPC personnalisée" sur Solana Explorer est par défaut http://localhost:8899.

Créer un client d'exemple

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 les dépendances solana-client et tokio.

Terminal
$
cargo add solana-client@2.2.0 --dev
$
cargo add tokio --dev

Ajouter le client

Ajoutez le code suivant à examples/client.rs. Il s'agit d'un script client Rust qui finance un nouveau keypair pour payer les frais de transaction, puis invoque le programme hello world.

Remplacer l'ID du programme

Avant d'exécuter le code client, remplacez l'ID du programme dans l'extrait de code 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

Invoquer le programme

Exécutez le script client avec la commande suivante.

Terminal
$
cargo run --example client

Exemple de sortie :

Transaction Signature: 54TWxKi3Jsi3UTeZbhLGUFX6JQH7TspRJjRRFZ8NFnwG5BXM9udxiX77bAACjKAS9fGnVeEazrXL4SfKrW7xZFYV

Vous pouvez examiner la signature de la 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(())
}

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

Terminal
$
cargo build-sbf

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

Terminal
$
cargo test -- --no-capture

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

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

Redéployer le programme

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

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

Exécutez à nouveau le code client et examinez la signature de la 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 pas être réutilisé. Toute tentative 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

Redéployer un programme fermé

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 un nouveau keypair 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 keypair existant (par ex. ./target/deploy/hello_world-keypair.json) et exécuter cargo build-sbf à nouveau, ce qui générera un nouveau fichier keypair.

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

Is this page helpful?

Table des matières

Modifier la page