Solana ドキュメントプログラム開発

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.tomlsrc/lib.rs ファイルが表示されるはずです

cd hello_world

次に、solana-program 依存関係を追加します。これはSolanaプログラムを構築するために必要な最小限の依存関係です。

Terminal
cargo add solana-program@1.18.26

次に、以下のスニペットをCargo.tomlに追加します。このコンフィグを含めないと、プログラムをビルドする際にtarget/deployディレクトリが生成されません。

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

あなたのCargo.tomlファイルは以下のようになるはずです:

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プログラムでメッセージをプログラムログに出力するために使用されます。

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

プログラムのビルド

次に、cargo build-sbfコマンドを使用してプログラムをビルドします。

Terminal
cargo build-sbf

このコマンドは、2つの重要なファイルを含むtarget/deployディレクトリを生成します:

  1. .soファイル(例:hello_world.so):これは「スマートコントラクト」としてネットワークにデプロイされるコンパイル済みのSolanaプログラムです。
  2. keypairファイル(例:hello_world-keypair.json):このkeypairの公開鍵はプログラムをデプロイする際のプログラムIDとして使用されます。

プログラムIDを確認するには、ターミナルで以下のコマンドを実行します。このコマンドは指定されたファイルパスにあるkeypairの公開鍵を表示します:

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

出力例:

4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz

プログラムのテスト

次に、solana-program-testクレートを使用してプログラムをテストします。以下の依存関係をCargo.tomlに追加します。

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

以下のテストをプログラムコードの下のsrc/lib.rsに追加します。これは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());
}
}

cargo test-sbfコマンドを使用してテストを実行します。プログラムログには「Hello, world!」と表示されます。

Terminal
cargo test-sbf

出力例:

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

プログラムのデプロイ

次に、プログラムをデプロイします。ローカル開発時には、 solana-test-validatorを使用できます。

まず、Solana CLIをローカルSolanaクラスターを使用するように設定します。

Terminal
solana config set -ul

出力例:

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

新しいターミナルを開き、solana-test-validatorsコマンドを実行してローカルvalidatorを起動します。

Terminal
solana-test-validator

テストvalidatorが実行されている間に、別のターミナルでsolana program deployコマンドを実行して、プログラムをローカルvalidatorにデプロイします。

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

出力例:

Program Id: 4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz
Signature:
5osMiNMiDZGM7L1e2tPHxU8wdB8gwG8fDnXLg5G7SbhwFz4dHshYgAijk4wSQL5cXiu8z1MMou5kLadAQuHp7ybH

プログラムIDとトランザクション署名は Solana Explorerで確認できます。Solana Explorerのクラスターもlocalhostに設定する必要があります。Solana Explorerの「Custom RPC URL」オプションのデフォルトはhttp://localhost:8899です。

プログラムの呼び出し

次に、Rustクライアントを使用してプログラムを呼び出す方法を示します。

まずexamplesディレクトリとclient.rsファイルを作成します。

Terminal
mkdir -p examples
touch examples/client.rs

以下をCargo.tomlに追加します。

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

solana-client依存関係を追加します。

Terminal
cargo add solana-client@1.18.26 --dev

以下のコードをexamples/client.rsに追加してください。これはトランザクション手数料を支払うための新しいkeypairに資金を提供し、helloワールドプログラムを呼び出すRustクライアントスクリプトです。

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

スクリプトを実行する前に、上記のコードスニペットのプログラムIDをあなたのプログラムのものに置き換えてください。

以下のコマンドを実行することで、プログラムIDを取得できます。

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

以下のコマンドでクライアントスクリプトを実行してください。

Terminal
cargo run --example client

出力例:

Transaction Signature: 54TWxKi3Jsi3UTeZbhLGUFX6JQH7TspRJjRRFZ8NFnwG5BXM9udxiX77bAACjKAS9fGnVeEazrXL4SfKrW7xZFYV

Solana Explorer(ローカルクラスター)でトランザクション署名を確認すると、プログラムログに「Hello, world!」が表示されます。

プログラムの更新

Solanaプログラムは、同じプログラムIDに再デプロイすることで更新できます。src/lib.rsのプログラムを更新して、「Hello, world!」の代わりに「Hello, Solana!」と表示するようにしましょう。

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

cargo test-sbfコマンドを実行して、更新されたプログラムをテストしてください。

Terminal
cargo test-sbf

プログラムログに「Hello, Solana!」が表示されるはずです。

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

cargo build-sbfコマンドを実行して、更新された.soファイルを生成してください。

Terminal
cargo build-sbf

solana program deployコマンドを使用してプログラムを再デプロイしてください。

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

クライアントコードを再度実行し、Solana Explorerでトランザクション署名を確認して、プログラムログに「Hello, Solana!」が表示されていることを確認してください。

Terminal
cargo run --example client

プログラムを閉じる

Solanaプログラムを閉じて、アカウントに割り当てられたSOLを回収することができます。プログラムの閉鎖は元に戻せないため、注意して行う必要があります。

プログラムを閉じるには、solana program close <PROGRAM_ID>コマンドを使用します。例えば:

Terminal
solana program close 4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz
--bypass-warning

出力例:

Closed Program Id 4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz, 0.1350588 SOL
reclaimed

プログラムが閉じられると、そのプログラムIDは再利用できなくなることに注意してください。以前に閉じられたプログラムIDでプログラムをデプロイしようとすると、エラーが発生します。

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

プログラムを閉じた後に同じソースコードでプログラムを再デプロイする必要がある場合は、新しいプログラムIDを生成する必要があります。プログラム用の新しいkeypairを生成するには、次のコマンドを実行します:

Terminal
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?

目次

ページを編集