Phát triển chương trình bằng Rust
Các chương trình Solana chủ yếu được phát triển bằng ngôn ngữ lập trình Rust. Trang này tập trung vào việc viết các chương trình Solana bằng Rust mà không sử dụng framework Anchor, một phương pháp thường được gọi là viết chương trình "Rust nguyên bản".
Phát triển Rust nguyên bản cung cấp cho các nhà phát triển quyền kiểm soát trực tiếp đối với chương trình Solana của họ. Tuy nhiên, phương pháp này đòi hỏi nhiều thiết lập thủ công và mã boilerplate hơn so với việc sử dụng framework Anchor. Phương pháp này được khuyến nghị cho các nhà phát triển:
- Tìm kiếm kiểm soát chi tiết đối với logic chương trình và tối ưu hóa
- Muốn tìm hiểu các khái niệm cơ bản trước khi chuyển sang các framework cấp cao hơn
Đối với người mới bắt đầu, chúng tôi khuyên bạn nên bắt đầu với framework Anchor. Xem phần Anchor để biết thêm thông tin.
Điều kiện tiên quyết
Để biết hướng dẫn cài đặt chi tiết, hãy truy cập trang cài đặt.
Trước khi bắt đầu, hãy đảm bảo bạn đã cài đặt những thứ sau:
- Rust: Ngôn ngữ lập trình để xây dựng các chương trình Solana.
- Solana CLI: Công cụ dòng lệnh cho phát triển Solana.
Bắt đầu
Ví dụ dưới đây bao gồm các bước cơ bản để tạo chương trình Solana đầu tiên của bạn viết bằng Rust. Chúng ta sẽ tạo một chương trình tối thiểu in "Hello, world!" vào nhật ký chương trình.
Tạo một chương trình mới
Đầu tiên, tạo một dự án Rust mới bằng lệnh tiêu chuẩn cargo init
với cờ
--lib
.
cargo init hello_world --lib
Di chuyển đến thư mục dự án. Bạn sẽ thấy các tệp mặc định src/lib.rs
và
Cargo.toml
cd hello_world
Tiếp theo, thêm dependency solana-program
. Đây là dependency tối thiểu cần
thiết để xây dựng một chương trình Solana.
cargo add solana-program@1.18.26
Tiếp theo, thêm đoạn mã sau vào Cargo.toml
. Nếu bạn không bao gồm cấu hình
này, thư mục target/deploy
sẽ không được tạo khi bạn build chương trình.
[lib]crate-type = ["cdylib", "lib"]
File Cargo.toml
của bạn nên trông như sau:
[package]name = "hello_world"version = "0.1.0"edition = "2021"[lib]crate-type = ["cdylib", "lib"][dependencies]solana-program = "1.18.26"
Tiếp theo, thay thế nội dung của src/lib.rs
bằng mã sau. Đây là một chương
trình Solana tối giản in ra "Hello, world!" vào nhật ký chương trình khi chương
trình được gọi.
Macro msg!
được sử dụng trong các chương trình Solana để in một thông báo vào
nhật ký chương trình.
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(())}
Build chương trình
Tiếp theo, build chương trình bằng lệnh cargo build-sbf
.
cargo build-sbf
Lệnh này tạo ra một thư mục target/deploy
chứa hai file quan trọng:
- Một file
.so
(ví dụ:hello_world.so
): Đây là chương trình Solana đã được biên dịch sẽ được triển khai lên mạng như một "smart contract". - Một file keypair (ví dụ:
hello_world-keypair.json
): Public key của keypair này được sử dụng làm program ID khi triển khai chương trình.
Để xem program ID, chạy lệnh sau trong terminal của bạn. Lệnh này in ra public key của keypair tại đường dẫn file được chỉ định:
solana address -k ./target/deploy/hello_world-keypair.json
Ví dụ kết quả:
4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz
Kiểm tra chương trình
Tiếp theo, kiểm tra chương trình bằng cách sử dụng crate solana-program-test
.
Thêm các dependencies sau vào Cargo.toml
.
cargo add solana-program-test@1.18.26 --devcargo add solana-sdk@1.18.26 --devcargo add tokio --dev
Thêm bài kiểm tra sau vào src/lib.rs
, bên dưới mã chương trình. Đây là một
module kiểm tra gọi chương trình 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());}}
Chạy bài kiểm tra bằng lệnh cargo test-sbf
. Nhật ký chương trình sẽ hiển thị
"Hello, world!".
cargo test-sbf
Kết quả đầu ra mẫu:
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
Triển khai chương trình
Tiếp theo, triển khai chương trình. Khi phát triển cục bộ, chúng ta có thể sử
dụng solana-test-validator
.
Đầu tiên, cấu hình Solana CLI để sử dụng cụm Solana cục bộ.
solana config set -ul
Kết quả đầu ra mẫu:
Config File: /.config/solana/cli/config.ymlRPC URL: http://localhost:8899WebSocket URL: ws://localhost:8900/ (computed)Keypair Path: /.config/solana/id.jsonCommitment: confirmed
Mở một terminal mới và chạy lệnh solana-test-validators
để khởi động validator
cục bộ.
solana-test-validator
Trong khi validator thử nghiệm đang chạy, chạy lệnh solana program deploy
trong một terminal riêng biệt để triển khai chương trình lên validator cục bộ.
solana program deploy ./target/deploy/hello_world.so
Kết quả đầu ra mẫu:
Program Id: 4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMzSignature:5osMiNMiDZGM7L1e2tPHxU8wdB8gwG8fDnXLg5G7SbhwFz4dHshYgAijk4wSQL5cXiu8z1MMou5kLadAQuHp7ybH
Bạn có thể kiểm tra ID chương trình và chữ ký giao dịch trên
Solana Explorer.
Lưu ý rằng cụm trên Solana Explorer cũng phải là localhost. Tùy chọn "Custom RPC
URL" trên Solana Explorer mặc định là http://localhost:8899
.
Gọi chương trình
Tiếp theo, chúng ta sẽ minh họa cách gọi chương trình bằng client Rust.
Đầu tiên tạo một thư mục examples
và một tệp client.rs
.
mkdir -p examplestouch examples/client.rs
Thêm nội dung sau vào Cargo.toml
.
[[example]]name = "client"path = "examples/client.rs"
Thêm dependency solana-client
.
cargo add solana-client@1.18.26 --dev
Thêm đoạn mã sau vào examples/client.rs
. Đây là một tập lệnh khách hàng Rust
nạp tiền vào một keypair mới để thanh toán phí giao dịch và sau đó gọi chương
trình hello world.
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),}}
Trước khi chạy tập lệnh, hãy thay thế ID chương trình trong đoạn mã trên bằng ID của chương trình của bạn.
Bạn có thể lấy ID chương trình của mình bằng cách chạy lệnh sau.
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();}}
Chạy tập lệnh khách hàng với lệnh sau.
cargo run --example client
Ví dụ về kết quả:
Transaction Signature: 54TWxKi3Jsi3UTeZbhLGUFX6JQH7TspRJjRRFZ8NFnwG5BXM9udxiX77bAACjKAS9fGnVeEazrXL4SfKrW7xZFYV
Bạn có thể kiểm tra chữ ký giao dịch trên Solana Explorer (cụm cục bộ) để xem "Hello, world!" trong nhật ký chương trình.
Cập nhật chương trình
Các chương trình Solana có thể được cập nhật bằng cách triển khai lại với cùng
một ID chương trình. Cập nhật chương trình trong src/lib.rs
để in "Hello,
Solana!" thay vì "Hello, world!".
pub fn process_instruction(_program_id: &Pubkey,_accounts: &[AccountInfo],_instruction_data: &[u8],) -> ProgramResult {- msg!("Hello, world!");+ msg!("Hello, Solana!");Ok(())}
Kiểm tra chương trình đã cập nhật bằng cách chạy lệnh cargo test-sbf
.
cargo test-sbf
Bạn sẽ thấy "Hello, Solana!" trong nhật ký chương trình.
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
Chạy lệnh cargo build-sbf
để tạo một tệp .so
đã cập nhật.
cargo build-sbf
Triển khai lại chương trình bằng lệnh solana program deploy
.
solana program deploy ./target/deploy/hello_world.so
Chạy mã khách hàng một lần nữa và kiểm tra chữ ký giao dịch trên Solana Explorer để xem "Hello, Solana!" trong nhật ký chương trình.
cargo run --example client
Đóng chương trình
Bạn có thể đóng chương trình Solana của mình để lấy lại SOL đã được phân bổ cho tài khoản. Việc đóng chương trình là không thể hoàn tác, vì vậy nên thực hiện một cách thận trọng.
Để đóng một chương trình, sử dụng lệnh solana program close <PROGRAM_ID>
. Ví
dụ:
solana program close 4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz--bypass-warning
Kết quả ví dụ:
Closed Program Id 4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz, 0.1350588 SOLreclaimed
Lưu ý rằng một khi chương trình đã đóng, ID chương trình của nó không thể được sử dụng lại. Việc cố gắng triển khai một chương trình với ID chương trình đã đóng trước đó sẽ dẫn đến lỗi.
Error: Program 4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz has been closed, usea new Program Id
Nếu bạn cần triển khai lại một chương trình với cùng mã nguồn sau khi đóng chương trình, bạn phải tạo một ID chương trình mới. Để tạo một keypair mới cho chương trình, chạy lệnh sau:
solana-keygen new -o ./target/deploy/hello_world-keypair.json --force
Hoặc, bạn có thể xóa tệp keypair hiện có (ví dụ:
./target/deploy/hello_world-keypair.json
) và chạy cargo build-sbf
một lần
nữa, điều này sẽ tạo một tệp keypair mới.
Is this page helpful?