Rustでのプログラム開発
Solanaプログラムは主にRustプログラミング言語を使用して開発されています。このページでは、Anchorフレームワークを使用せずにRustでSolanaプログラムを書くことに焦点を当てています。このアプローチは「ネイティブRust」プログラムを書くとも呼ばれています。
ネイティブRust開発は、開発者にSolanaプログラムに対する直接的な制御を提供します。ただし、このアプローチはAnchorフレームワークを使用する場合と比較して、より多くの手動セットアップとボイラープレートコードが必要です。このメソッドは以下のような開発者に推奨されます:
- プログラムロジックと最適化に対する細かい制御を求める開発者
- 上位レベルのフレームワークに移る前に基礎となる概念を学びたい開発者
初心者の方には、Anchorフレームワークから始めることをお勧めします。詳細については Anchorセクションをご覧ください。
前提条件
詳細なインストール手順については、 インストールページをご覧ください。
始める前に、以下がインストールされていることを確認してください:
- Rust: Solanaプログラムを構築するためのプログラミング言語。
- Solana CLI: Solana開発のためのコマンドラインツール。
はじめに
以下の例では、Rustで書かれた最初のSolanaプログラムを作成するための基本的なステップを説明します。プログラムログに「Hello, world!」と表示する最小限のプログラムを作成します。
新しいプログラムの作成
まず、標準の cargo new
コマンドと --lib
フラグを使用して新しいRustプロジェクトを作成します。
cargo new hello_world --lib
プロジェクトディレクトリに移動します。デフォルトの Cargo.toml
と src/lib.rs
ファイルが表示されるはずです
cd hello_world
次に、solana-program
依存関係を追加します。これはSolanaプログラムを構築するために必要な最小限の依存関係です。
cargo add solana-program@1.18.26
次に、以下のスニペットをCargo.toml
に追加します。このコンフィグを含めないと、プログラムをビルドする際にtarget/deploy
ディレクトリが生成されません。
[lib]crate-type = ["cdylib", "lib"]
あなたのCargo.toml
ファイルは以下のようになるはずです:
[package]name = "hello_world"version = "0.1.0"edition = "2021"[lib]crate-type = ["cdylib", "lib"][dependencies]solana-program = "1.18.26"
次に、src/lib.rs
の内容を以下のコードに置き換えます。これはプログラムが呼び出されたときにプログラムログに「Hello,
world!」と表示する最小限のSolanaプログラムです。
msg!
マクロはSolanaプログラムでメッセージをプログラムログに出力するために使用されます。
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(())}
プログラムのビルド
次に、cargo build-sbf
コマンドを使用してプログラムをビルドします。
cargo build-sbf
このコマンドは、2つの重要なファイルを含むtarget/deploy
ディレクトリを生成します:
.so
ファイル(例:hello_world.so
):これは「スマートコントラクト」としてネットワークにデプロイされるコンパイル済みのSolanaプログラムです。- keypairファイル(例:
hello_world-keypair.json
):このkeypairの公開鍵はプログラムをデプロイする際のプログラムIDとして使用されます。
プログラムIDを確認するには、ターミナルで以下のコマンドを実行します。このコマンドは指定されたファイルパスにあるkeypairの公開鍵を表示します:
solana address -k ./target/deploy/hello_world-keypair.json
出力例:
4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz
プログラムのテスト
次に、solana-program-test
クレートを使用してプログラムをテストします。以下の依存関係をCargo.toml
に追加します。
cargo add solana-program-test@1.18.26 --devcargo add solana-sdk@1.18.26 --devcargo add tokio --dev
以下のテストをプログラムコードの下のsrc/lib.rs
に追加します。これは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());}}
cargo test-sbf
コマンドを使用してテストを実行します。プログラムログには「Hello,
world!」と表示されます。
cargo test-sbf
出力例:
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
プログラムのデプロイ
次に、プログラムをデプロイします。ローカル開発時には、
solana-test-validator
を使用できます。
まず、Solana CLIをローカルSolanaクラスターを使用するように設定します。
solana config set -ul
出力例:
Config File: /.config/solana/cli/config.ymlRPC URL: http://localhost:8899WebSocket URL: ws://localhost:8900/ (computed)Keypair Path: /.config/solana/id.jsonCommitment: confirmed
新しいターミナルを開き、solana-test-validators
コマンドを実行してローカルvalidatorを起動します。
solana-test-validator
テストvalidatorが実行されている間に、別のターミナルでsolana program deploy
コマンドを実行して、プログラムをローカルvalidatorにデプロイします。
solana program deploy ./target/deploy/hello_world.so
出力例:
Program Id: 4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMzSignature:5osMiNMiDZGM7L1e2tPHxU8wdB8gwG8fDnXLg5G7SbhwFz4dHshYgAijk4wSQL5cXiu8z1MMou5kLadAQuHp7ybH
プログラムIDとトランザクション署名は
Solana Explorerで確認できます。Solana
Explorerのクラスターもlocalhostに設定する必要があります。Solana
Explorerの「Custom RPC
URL」オプションのデフォルトはhttp://localhost:8899
です。
プログラムの呼び出し
次に、Rustクライアントを使用してプログラムを呼び出す方法を示します。
まずexamples
ディレクトリとclient.rs
ファイルを作成します。
mkdir -p examplestouch examples/client.rs
以下をCargo.toml
に追加します。
[[example]]name = "client"path = "examples/client.rs"
solana-client
依存関係を追加します。
cargo add solana-client@1.18.26 --dev
以下のコードをexamples/client.rs
に追加してください。これはトランザクション手数料を支払うための新しいkeypairに資金を提供し、helloワールドプログラムを呼び出すRustクライアントスクリプトです。
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),}}
スクリプトを実行する前に、上記のコードスニペットのプログラムIDをあなたのプログラムのものに置き換えてください。
以下のコマンドを実行することで、プログラムIDを取得できます。
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();}}
以下のコマンドでクライアントスクリプトを実行してください。
cargo run --example client
出力例:
Transaction Signature: 54TWxKi3Jsi3UTeZbhLGUFX6JQH7TspRJjRRFZ8NFnwG5BXM9udxiX77bAACjKAS9fGnVeEazrXL4SfKrW7xZFYV
Solana Explorer(ローカルクラスター)でトランザクション署名を確認すると、プログラムログに「Hello, world!」が表示されます。
プログラムの更新
Solanaプログラムは、同じプログラムIDに再デプロイすることで更新できます。src/lib.rs
のプログラムを更新して、「Hello,
world!」の代わりに「Hello, Solana!」と表示するようにしましょう。
pub fn process_instruction(_program_id: &Pubkey,_accounts: &[AccountInfo],_instruction_data: &[u8],) -> ProgramResult {- msg!("Hello, world!");+ msg!("Hello, Solana!");Ok(())}
cargo test-sbf
コマンドを実行して、更新されたプログラムをテストしてください。
cargo test-sbf
プログラムログに「Hello, Solana!」が表示されるはずです。
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
cargo build-sbf
コマンドを実行して、更新された.so
ファイルを生成してください。
cargo build-sbf
solana program deploy
コマンドを使用してプログラムを再デプロイしてください。
solana program deploy ./target/deploy/hello_world.so
クライアントコードを再度実行し、Solana Explorerでトランザクション署名を確認して、プログラムログに「Hello, Solana!」が表示されていることを確認してください。
cargo run --example client
プログラムを閉じる
Solanaプログラムを閉じて、アカウントに割り当てられたSOLを回収することができます。プログラムの閉鎖は元に戻せないため、注意して行う必要があります。
プログラムを閉じるには、solana program close <PROGRAM_ID>
コマンドを使用します。例えば:
solana program close 4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz--bypass-warning
出力例:
Closed Program Id 4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz, 0.1350588 SOLreclaimed
プログラムが閉じられると、そのプログラムIDは再利用できなくなることに注意してください。以前に閉じられたプログラムIDでプログラムをデプロイしようとすると、エラーが発生します。
Error: Program 4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz has been closed, usea new Program Id
プログラムを閉じた後に同じソースコードでプログラムを再デプロイする必要がある場合は、新しいプログラムIDを生成する必要があります。プログラム用の新しいkeypairを生成するには、次のコマンドを実行します:
solana-keygen new -o ./target/deploy/hello_world-keypair.json --force
または、既存のkeypairファイル(例:./target/deploy/hello_world-keypair.json
)を削除して、cargo build-sbf
を再度実行することもできます。これにより、新しいkeypairファイルが生成されます。
Is this page helpful?