Dokumentacja SolanaTworzenie programów

Tworzenie programów w Rust

Programy Solana są głównie tworzone w języku programowania Rust. Ta strona koncentruje się na pisaniu programów Solana w Rust bez użycia frameworka Anchor, co często nazywane jest pisaniem programów w "czystym Rust".

Tworzenie w czystym Rust daje programistom bezpośrednią kontrolę nad ich programami Solana. Jednak podejście to wymaga więcej ręcznej konfiguracji i szablonowego kodu w porównaniu do użycia frameworka Anchor. Metoda ta jest zalecana dla programistów, którzy:

  • Chcą mieć szczegółową kontrolę nad logiką programu i optymalizacjami
  • Chcą poznać podstawowe koncepcje przed przejściem do frameworków wyższego poziomu

Dla początkujących zalecamy rozpoczęcie od frameworka Anchor. Zobacz sekcję Anchor po więcej informacji.

Wymagania wstępne

Szczegółowe instrukcje instalacji znajdziesz na stronie instalacja.

Przed rozpoczęciem upewnij się, że masz zainstalowane następujące elementy:

  • Rust: Język programowania do tworzenia programów Solana.
  • Solana CLI: Narzędzie wiersza poleceń do rozwoju Solana.

Pierwsze kroki

Poniższy przykład obejmuje podstawowe kroki tworzenia pierwszego programu Solana napisanego w Rust. Stworzymy minimalny program, który wypisuje "Hello, world!" do logu programu.

Utwórz nowy program

Najpierw utwórz nowy projekt w Rust, używając standardowego polecenia cargo new z flagą --lib.

Terminal
$
cargo new hello_world --lib

Przejdź do katalogu projektu. Powinieneś zobaczyć domyślne pliki src/lib.rs i Cargo.toml.

Terminal
$
cd hello_world

Zaktualizuj pole edition w pliku Cargo.toml na 2021. W przeciwnym razie możesz napotkać błąd podczas budowania programu.

Dodaj zależność solana-program

Następnie dodaj zależność solana-program. Jest to minimalna zależność wymagana do zbudowania programu Solana.

Terminal
$
cargo add solana-program@2.2.0

Dodaj typ crate

Następnie dodaj poniższy fragment do Cargo.toml.

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

Jeśli nie uwzględnisz tej konfiguracji, katalog target/deploy nie zostanie wygenerowany podczas budowania programu.

Twój plik Cargo.toml powinien wyglądać następująco:

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

Dodaj kod programu

Następnie zastąp zawartość src/lib.rs poniższym kodem. Jest to minimalny program Solana, który wypisuje "Hello, world!" do dziennika programu, gdy program zostanie wywołany.

Makro msg! jest używane w programach Solana do wypisywania wiadomości do dziennika programu.

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

Zbuduj program

Następnie zbuduj program za pomocą polecenia cargo build-sbf.

Terminal
$
cargo build-sbf

To polecenie generuje katalog target/deploy zawierający dwa ważne pliki:

  1. Plik .so (np. hello_world.so): Jest to skompilowany program Solana, który zostanie wdrożony w sieci jako "smart contract".
  2. Plik keypair (np. hello_world-keypair.json): Klucz publiczny tego keypair jest używany jako identyfikator programu podczas wdrażania programu.

Aby wyświetlić identyfikator programu, uruchom następujące polecenie w terminalu. To polecenie wypisuje klucz publiczny keypair znajdującego się w określonej ścieżce pliku:

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

Przykładowy wynik:

4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz

Dodaj zależności testowe

Następnie przetestuj program, używając biblioteki litesvm. Dodaj następujące zależności do pliku Cargo.toml.

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

Przetestuj program

Dodaj następujący test do pliku src/lib.rs, poniżej kodu programu. Jest to moduł testowy, który wywołuje program 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:#?}");
}
}

Uruchom test za pomocą polecenia cargo test. W dzienniku programu pojawi się "Hello, world!".

Terminal
$
cargo test -- --no-capture

Przykładowy wynik:

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

Wdróż program

Następnie wdroż program. Podczas pracy lokalnej możemy użyć solana-test-validator.

Najpierw skonfiguruj Solana CLI, aby używać lokalnego klastra Solana.

Terminal
$
solana config set -ul

Przykładowy wynik:

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

Otwórz nowe okno terminala i uruchom polecenie solana-test-validators, aby uruchomić lokalny validator.

Terminal
$
solana-test-validator

Podczas gdy testowy validator działa, uruchom polecenie solana program deploy w osobnym terminalu, aby wdrożyć program na lokalnym validatorze.

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

Przykładowy wynik:

Program Id: 4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz
Signature:
5osMiNMiDZGM7L1e2tPHxU8wdB8gwG8fDnXLg5G7SbhwFz4dHshYgAijk4wSQL5cXiu8z1MMou5kLadAQuHp7ybH

Możesz sprawdzić identyfikator programu i podpis transakcji na Solana Explorer.

Pamiętaj, że klaster na Solana Explorer musi również być localhost. Opcja "Custom RPC URL" na Solana Explorer domyślnie wskazuje na http://localhost:8899.

Utwórz przykładowego klienta

Następnie pokażemy, jak wywołać program za pomocą klienta w języku Rust.

Najpierw utwórz katalog examples i plik client.rs.

Terminal
$
mkdir -p examples && touch examples/client.rs

Dodaj następujące elementy do Cargo.toml.

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

Dodaj zależności solana-client i tokio.

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

Dodaj klienta

Dodaj następujący kod do examples/client.rs. Jest to skrypt klienta w języku Rust, który finansuje nowy keypair, aby opłacić opłaty transakcyjne, a następnie wywołuje program 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),
}
}

Zamień identyfikator programu

Przed uruchomieniem kodu klienta zamień identyfikator programu w fragmencie kodu na ten, który odpowiada Twojemu programowi.

Możesz uzyskać identyfikator swojego programu, uruchamiając następujące polecenie.

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

Wywołaj program

Uruchom skrypt klienta za pomocą następującego polecenia.

Terminal
$
cargo run --example client

Przykładowy wynik:

Transaction Signature: 54TWxKi3Jsi3UTeZbhLGUFX6JQH7TspRJjRRFZ8NFnwG5BXM9udxiX77bAACjKAS9fGnVeEazrXL4SfKrW7xZFYV

Możesz sprawdzić podpis transakcji w Solana Explorer (lokalny klaster), aby zobaczyć "Hello, world!" w logu programu.

Zaktualizuj program

Programy Solana można aktualizować, ponownie wdrażając je pod tym samym ID programu. Zaktualizuj program w src/lib.rs, aby wyświetlał "Hello, Solana!" zamiast "Hello, world!".

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

Uruchom polecenie cargo build-sbf, aby wygenerować zaktualizowany plik .so.

Terminal
$
cargo build-sbf

Przetestuj zaktualizowany program, uruchamiając polecenie cargo test.

Terminal
$
cargo test -- --no-capture

Powinieneś zobaczyć "Hello, Solana!" w logu programu.

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

Ponownie wdroż program

Ponownie wdroż program, używając tego samego polecenia solana program deploy.

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

Uruchom ponownie kod klienta i sprawdź podpis transakcji w Solana Explorer, aby zobaczyć "Hello, Solana!" w logu programu.

Terminal
$
cargo run --example client

Zamknij program

Możesz zamknąć swój program Solana, aby odzyskać SOL przypisane do konta. Zamknięcie programu jest nieodwracalne, więc należy to zrobić ostrożnie.

Aby zamknąć program, użyj polecenia solana program close <PROGRAM_ID>. Na przykład:

Terminal
$
solana program close 4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz --bypass-warning

Przykładowy wynik:

Closed Program Id 4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz, 0.1350588 SOL
reclaimed

Zwróć uwagę, że po zamknięciu programu jego identyfikator programu (program ID) nie może być ponownie użyty. Próba wdrożenia programu z wcześniej zamkniętym identyfikatorem programu zakończy się błędem.

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

Ponowne wdrożenie zamkniętego programu

Jeśli musisz ponownie wdrożyć program z tym samym kodem źródłowym po jego zamknięciu, musisz wygenerować nowy identyfikator programu (program ID). Aby wygenerować nową parę kluczy dla programu, uruchom następujące polecenie:

Terminal
$
solana-keygen new -o ./target/deploy/hello_world-keypair.json --force

Alternatywnie możesz usunąć istniejący plik pary kluczy (np. ./target/deploy/hello_world-keypair.json) i ponownie uruchomić cargo build-sbf, co spowoduje wygenerowanie nowego pliku pary kluczy.

Utwórz nowy program

Najpierw utwórz nowy projekt w Rust, używając standardowego polecenia cargo new z flagą --lib.

Terminal
$
cargo new hello_world --lib

Przejdź do katalogu projektu. Powinieneś zobaczyć domyślne pliki src/lib.rs i Cargo.toml.

Terminal
$
cd hello_world

Zaktualizuj pole edition w pliku Cargo.toml na 2021. W przeciwnym razie możesz napotkać błąd podczas budowania programu.

Dodaj zależność solana-program

Następnie dodaj zależność solana-program. Jest to minimalna zależność wymagana do zbudowania programu Solana.

Terminal
$
cargo add solana-program@2.2.0

Dodaj typ crate

Następnie dodaj poniższy fragment do Cargo.toml.

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

Jeśli nie uwzględnisz tej konfiguracji, katalog target/deploy nie zostanie wygenerowany podczas budowania programu.

Dodaj kod programu

Następnie zastąp zawartość src/lib.rs poniższym kodem. Jest to minimalny program Solana, który wypisuje "Hello, world!" do dziennika programu, gdy program zostanie wywołany.

Makro msg! jest używane w programach Solana do wypisywania wiadomości do dziennika programu.

Zbuduj program

Następnie zbuduj program za pomocą polecenia cargo build-sbf.

Terminal
$
cargo build-sbf

To polecenie generuje katalog target/deploy zawierający dwa ważne pliki:

  1. Plik .so (np. hello_world.so): Jest to skompilowany program Solana, który zostanie wdrożony w sieci jako "smart contract".
  2. Plik keypair (np. hello_world-keypair.json): Klucz publiczny tego keypair jest używany jako identyfikator programu podczas wdrażania programu.

Aby wyświetlić identyfikator programu, uruchom następujące polecenie w terminalu. To polecenie wypisuje klucz publiczny keypair znajdującego się w określonej ścieżce pliku:

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

Przykładowy wynik:

4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz

Dodaj zależności testowe

Następnie przetestuj program, używając biblioteki litesvm. Dodaj następujące zależności do pliku Cargo.toml.

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

Przetestuj program

Dodaj następujący test do pliku src/lib.rs, poniżej kodu programu. Jest to moduł testowy, który wywołuje program hello world.

Uruchom test za pomocą polecenia cargo test. W dzienniku programu pojawi się "Hello, world!".

Terminal
$
cargo test -- --no-capture

Przykładowy wynik:

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

Wdróż program

Następnie wdroż program. Podczas pracy lokalnej możemy użyć solana-test-validator.

Najpierw skonfiguruj Solana CLI, aby używać lokalnego klastra Solana.

Terminal
$
solana config set -ul

Przykładowy wynik:

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

Otwórz nowe okno terminala i uruchom polecenie solana-test-validators, aby uruchomić lokalny validator.

Terminal
$
solana-test-validator

Podczas gdy testowy validator działa, uruchom polecenie solana program deploy w osobnym terminalu, aby wdrożyć program na lokalnym validatorze.

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

Przykładowy wynik:

Program Id: 4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz
Signature:
5osMiNMiDZGM7L1e2tPHxU8wdB8gwG8fDnXLg5G7SbhwFz4dHshYgAijk4wSQL5cXiu8z1MMou5kLadAQuHp7ybH

Możesz sprawdzić identyfikator programu i podpis transakcji na Solana Explorer.

Pamiętaj, że klaster na Solana Explorer musi również być localhost. Opcja "Custom RPC URL" na Solana Explorer domyślnie wskazuje na http://localhost:8899.

Utwórz przykładowego klienta

Następnie pokażemy, jak wywołać program za pomocą klienta w języku Rust.

Najpierw utwórz katalog examples i plik client.rs.

Terminal
$
mkdir -p examples && touch examples/client.rs

Dodaj następujące elementy do Cargo.toml.

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

Dodaj zależności solana-client i tokio.

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

Dodaj klienta

Dodaj następujący kod do examples/client.rs. Jest to skrypt klienta w języku Rust, który finansuje nowy keypair, aby opłacić opłaty transakcyjne, a następnie wywołuje program hello world.

Zamień identyfikator programu

Przed uruchomieniem kodu klienta zamień identyfikator programu w fragmencie kodu na ten, który odpowiada Twojemu programowi.

Możesz uzyskać identyfikator swojego programu, uruchamiając następujące polecenie.

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

Wywołaj program

Uruchom skrypt klienta za pomocą następującego polecenia.

Terminal
$
cargo run --example client

Przykładowy wynik:

Transaction Signature: 54TWxKi3Jsi3UTeZbhLGUFX6JQH7TspRJjRRFZ8NFnwG5BXM9udxiX77bAACjKAS9fGnVeEazrXL4SfKrW7xZFYV

Możesz sprawdzić podpis transakcji w Solana Explorer (lokalny klaster), aby zobaczyć "Hello, world!" w logu programu.

Zaktualizuj program

Programy Solana można aktualizować, ponownie wdrażając je pod tym samym ID programu. Zaktualizuj program w src/lib.rs, aby wyświetlał "Hello, Solana!" zamiast "Hello, world!".

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

Uruchom polecenie cargo build-sbf, aby wygenerować zaktualizowany plik .so.

Terminal
$
cargo build-sbf

Przetestuj zaktualizowany program, uruchamiając polecenie cargo test.

Terminal
$
cargo test -- --no-capture

Powinieneś zobaczyć "Hello, Solana!" w logu programu.

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

Ponownie wdroż program

Ponownie wdroż program, używając tego samego polecenia solana program deploy.

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

Uruchom ponownie kod klienta i sprawdź podpis transakcji w Solana Explorer, aby zobaczyć "Hello, Solana!" w logu programu.

Terminal
$
cargo run --example client

Zamknij program

Możesz zamknąć swój program Solana, aby odzyskać SOL przypisane do konta. Zamknięcie programu jest nieodwracalne, więc należy to zrobić ostrożnie.

Aby zamknąć program, użyj polecenia solana program close <PROGRAM_ID>. Na przykład:

Terminal
$
solana program close 4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz --bypass-warning

Przykładowy wynik:

Closed Program Id 4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz, 0.1350588 SOL
reclaimed

Zwróć uwagę, że po zamknięciu programu jego identyfikator programu (program ID) nie może być ponownie użyty. Próba wdrożenia programu z wcześniej zamkniętym identyfikatorem programu zakończy się błędem.

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

Ponowne wdrożenie zamkniętego programu

Jeśli musisz ponownie wdrożyć program z tym samym kodem źródłowym po jego zamknięciu, musisz wygenerować nowy identyfikator programu (program ID). Aby wygenerować nową parę kluczy dla programu, uruchom następujące polecenie:

Terminal
$
solana-keygen new -o ./target/deploy/hello_world-keypair.json --force

Alternatywnie możesz usunąć istniejący plik pary kluczy (np. ./target/deploy/hello_world-keypair.json) i ponownie uruchomić cargo build-sbf, co spowoduje wygenerowanie nowego pliku pary kluczy.

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

Is this page helpful?

Spis treści

Edytuj stronę