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プロジェクトを作成します。

Terminal
$
cargo new hello_world --lib

プロジェクトディレクトリに移動します。デフォルトの src/lib.rsCargo.toml ファイルが表示されるはずです

Terminal
$
cd hello_world

Cargo.tomledition フィールドを 2021 に更新してください。そうしないと、 プログラムをビルドする際にエラーが発生する可能性があります。

solana-programの依存関係を追加する

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

Terminal
$
cargo add solana-program@2.2.0

crate-typeを追加する

次に、以下のスニペットをCargo.tomlに追加します。

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

このコンフィグを含めないと、プログラムをビルドする際にtarget/deployディレクトリが生成されません。

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

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

プログラムコードを追加する

次に、src/lib.rsの内容を以下のコードに置き換えます。これはプログラムが呼び出されたときに「Hello, world!」をプログラムログに出力する最小限のSolanaプログラムです。

msg!マクロはSolanaプログラムでメッセージをプログラムログに出力するために使用されます。

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

プログラムをビルドする

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

Terminal
$
cargo build-sbf

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

  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

テスト依存関係の追加

次に、litesvm クレートを使用してプログラムをテストします。以下の依存関係を Cargo.toml に追加してください。

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

プログラムのテスト

以下のテストをプログラムコードの下の src/lib.rs に追加します。これはハローワールドプログラムを呼び出すテストモジュールです。

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:#?}");
}
}

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

Terminal
$
cargo test -- --no-capture

出力例:

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

プログラムのデプロイ

次に、プログラムをデプロイします。ローカルで開発する場合は、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-clienttokio の依存関係を追加します。

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

クライアントの追加

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

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

プログラムIDの置き換え

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

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

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

プログラムの呼び出し

以下のコマンドでクライアントスクリプトを実行します。

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 build-sbfコマンドを実行して、更新された.soファイルを生成します。

Terminal
$
cargo build-sbf

cargo testコマンドを実行して、更新されたプログラムをテストします。

Terminal
$
cargo test -- --no-capture

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

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

プログラムの再デプロイ

同じ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ファイルが生成されます。

新しいプログラムを作成する

まず、標準の cargo new コマンドを --lib フラグと共に使用して、新しいRustプロジェクトを作成します。

Terminal
$
cargo new hello_world --lib

プロジェクトディレクトリに移動します。デフォルトの src/lib.rsCargo.toml ファイルが表示されるはずです

Terminal
$
cd hello_world

Cargo.tomledition フィールドを 2021 に更新してください。そうしないと、 プログラムをビルドする際にエラーが発生する可能性があります。

solana-programの依存関係を追加する

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

Terminal
$
cargo add solana-program@2.2.0

crate-typeを追加する

次に、以下のスニペットをCargo.tomlに追加します。

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

このコンフィグを含めないと、プログラムをビルドする際にtarget/deployディレクトリが生成されません。

プログラムコードを追加する

次に、src/lib.rsの内容を以下のコードに置き換えます。これはプログラムが呼び出されたときに「Hello, world!」をプログラムログに出力する最小限のSolanaプログラムです。

msg!マクロはSolanaプログラムでメッセージをプログラムログに出力するために使用されます。

プログラムをビルドする

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

Terminal
$
cargo build-sbf

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

  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

テスト依存関係の追加

次に、litesvm クレートを使用してプログラムをテストします。以下の依存関係を Cargo.toml に追加してください。

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

プログラムのテスト

以下のテストをプログラムコードの下の src/lib.rs に追加します。これはハローワールドプログラムを呼び出すテストモジュールです。

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

Terminal
$
cargo test -- --no-capture

出力例:

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

プログラムのデプロイ

次に、プログラムをデプロイします。ローカルで開発する場合は、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-clienttokio の依存関係を追加します。

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

クライアントの追加

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

プログラムIDの置き換え

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

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

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

プログラムの呼び出し

以下のコマンドでクライアントスクリプトを実行します。

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 build-sbfコマンドを実行して、更新された.soファイルを生成します。

Terminal
$
cargo build-sbf

cargo testコマンドを実行して、更新されたプログラムをテストします。

Terminal
$
cargo test -- --no-capture

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

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

プログラムの再デプロイ

同じ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ファイルが生成されます。

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

Is this page helpful?

目次

ページを編集