Desenvolvendo Programas em Rust
Os programas Solana são desenvolvidos principalmente usando a linguagem de programação Rust. Esta página concentra-se na escrita de programas Solana em Rust sem usar o framework Anchor, uma abordagem frequentemente referida como escrita de programas "Rust nativos".
O desenvolvimento em Rust nativo proporciona aos desenvolvedores controle direto sobre seus programas Solana. No entanto, esta abordagem requer mais configuração manual e código boilerplate em comparação com o uso do framework Anchor. Este método é recomendado para desenvolvedores que:
- Buscam controle granular sobre a lógica do programa e otimizações
- Querem aprender os conceitos subjacentes antes de passar para frameworks de nível superior
Para iniciantes, recomendamos começar com o framework Anchor. Veja a seção Anchor para mais informações.
Pré-requisitos
Para instruções detalhadas de instalação, visite a página de instalação.
Antes de começar, certifique-se de ter o seguinte instalado:
- Rust: A linguagem de programação para construir programas Solana.
- Solana CLI: Ferramenta de linha de comando para desenvolvimento Solana.
Primeiros Passos
O exemplo abaixo cobre os passos básicos para criar seu primeiro programa Solana escrito em Rust. Vamos criar um programa mínimo que imprime "Hello, world!" no log do programa.
Criar um novo Programa
Primeiro, crie um novo projeto Rust usando o comando padrão cargo init
com a
flag --lib
.
cargo init hello_world --lib
Navegue até o diretório do projeto. Você deve ver os arquivos padrão
src/lib.rs
e Cargo.toml
cd hello_world
Em seguida, adicione a dependência solana-program
. Esta é a dependência mínima
necessária para construir um programa Solana.
cargo add solana-program@1.18.26
Em seguida, adicione o seguinte trecho ao Cargo.toml
. Se você não incluir esta
configuração, o diretório target/deploy
não será gerado quando você compilar o
programa.
[lib]crate-type = ["cdylib", "lib"]
Seu arquivo Cargo.toml
deve se parecer com o seguinte:
[package]name = "hello_world"version = "0.1.0"edition = "2021"[lib]crate-type = ["cdylib", "lib"][dependencies]solana-program = "1.18.26"
Em seguida, substitua o conteúdo de src/lib.rs
com o código a seguir. Este é
um programa Solana mínimo que imprime "Hello, world!" no log do programa quando
o programa é invocado.
A macro msg!
é usada em programas Solana para imprimir uma mensagem no log do
programa.
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(())}
Compilar o programa
Em seguida, compile o programa usando o comando cargo build-sbf
.
cargo build-sbf
Este comando gera um diretório target/deploy
contendo dois arquivos
importantes:
- Um arquivo
.so
(ex.:hello_world.so
): Este é o programa Solana compilado que será implantado na rede como um "smart contract". - Um arquivo keypair (ex.:
hello_world-keypair.json
): A chave pública deste keypair é usada como ID do programa ao implantar o programa.
Para visualizar o ID do programa, execute o seguinte comando no seu terminal. Este comando imprime a chave pública do keypair no caminho de arquivo especificado:
solana address -k ./target/deploy/hello_world-keypair.json
Exemplo de saída:
4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz
Testar o programa
Em seguida, teste o programa usando o crate solana-program-test
. Adicione as
seguintes dependências ao Cargo.toml
.
cargo add solana-program-test@1.18.26 --devcargo add solana-sdk@1.18.26 --devcargo add tokio --dev
Adicione o seguinte teste ao src/lib.rs
, abaixo do código do programa. Este é
um módulo de teste que invoca o programa 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());}}
Execute o teste usando o comando cargo test-sbf
. O log do programa exibirá
"Hello, world!".
cargo test-sbf
Exemplo de saída:
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
Implantar o programa
Em seguida, implante o programa. Durante o desenvolvimento local, podemos usar o
solana-test-validator
.
Primeiro, configure a CLI da Solana para usar o cluster local da Solana.
solana config set -ul
Exemplo de saída:
Config File: /.config/solana/cli/config.ymlRPC URL: http://localhost:8899WebSocket URL: ws://localhost:8900/ (computed)Keypair Path: /.config/solana/id.jsonCommitment: confirmed
Abra um novo terminal e execute o comando solana-test-validators
para iniciar
o validator local.
solana-test-validator
Enquanto o validator de teste estiver em execução, execute o comando
solana program deploy
em um terminal separado para implantar o programa no
validator local.
solana program deploy ./target/deploy/hello_world.so
Exemplo de saída:
Program Id: 4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMzSignature:5osMiNMiDZGM7L1e2tPHxU8wdB8gwG8fDnXLg5G7SbhwFz4dHshYgAijk4wSQL5cXiu8z1MMou5kLadAQuHp7ybH
Você pode inspecionar o ID do programa e a assinatura da transação no
Solana Explorer.
Observe que o cluster no Solana Explorer também deve ser localhost. A opção
"Custom RPC URL" no Solana Explorer tem como padrão http://localhost:8899
.
Invocar o programa
Em seguida, demonstraremos como invocar o programa usando um cliente Rust.
Primeiro crie um diretório examples
e um arquivo client.rs
.
mkdir -p examplestouch examples/client.rs
Adicione o seguinte ao Cargo.toml
.
[[example]]name = "client"path = "examples/client.rs"
Adicione a dependência solana-client
.
cargo add solana-client@1.18.26 --dev
Adicione o seguinte código ao examples/client.rs
. Este é um script cliente em
Rust que financia um novo keypair para pagar taxas de transação e depois invoca
o programa 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),}}
Antes de executar o script, substitua o ID do programa no trecho de código acima pelo ID do seu programa.
Você pode obter o ID do seu programa executando o seguinte comando.
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();}}
Execute o script cliente com o seguinte comando.
cargo run --example client
Exemplo de saída:
Transaction Signature: 54TWxKi3Jsi3UTeZbhLGUFX6JQH7TspRJjRRFZ8NFnwG5BXM9udxiX77bAACjKAS9fGnVeEazrXL4SfKrW7xZFYV
Você pode inspecionar a assinatura da transação no Solana Explorer (cluster local) para ver "Hello, world!" no log do programa.
Atualizar o programa
Os programas Solana podem ser atualizados reimplantando no mesmo ID de programa.
Atualize o programa em src/lib.rs
para imprimir "Hello, Solana!" em vez de
"Hello, world!".
pub fn process_instruction(_program_id: &Pubkey,_accounts: &[AccountInfo],_instruction_data: &[u8],) -> ProgramResult {- msg!("Hello, world!");+ msg!("Hello, Solana!");Ok(())}
Teste o programa atualizado executando o comando cargo test-sbf
.
cargo test-sbf
Você deverá ver "Hello, Solana!" no log do programa.
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
Execute o comando cargo build-sbf
para gerar um arquivo .so
atualizado.
cargo build-sbf
Reimplante o programa usando o comando solana program deploy
.
solana program deploy ./target/deploy/hello_world.so
Execute o código cliente novamente e inspecione a assinatura da transação no Solana Explorer para ver "Hello, Solana!" no log do programa.
cargo run --example client
Fechar o programa
Você pode fechar seu programa Solana para recuperar o SOL alocado na conta. Fechar um programa é irreversível, portanto, deve ser feito com cautela.
Para fechar um programa, use o comando solana program close <PROGRAM_ID>
. Por
exemplo:
solana program close 4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz--bypass-warning
Exemplo de saída:
Closed Program Id 4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz, 0.1350588 SOLreclaimed
Observe que uma vez que um programa é fechado, seu ID de programa não pode ser reutilizado. Tentar implantar um programa com um ID de programa previamente fechado resultará em um erro.
Error: Program 4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz has been closed, usea new Program Id
Se você precisar reimplantar um programa com o mesmo código-fonte após fechar um programa, você deve gerar um novo ID de programa. Para gerar um novo keypair para o programa, execute o seguinte comando:
solana-keygen new -o ./target/deploy/hello_world-keypair.json --force
Alternativamente, você pode excluir o arquivo de keypair existente (por exemplo,
./target/deploy/hello_world-keypair.json
) e executar cargo build-sbf
novamente, que gerará um novo arquivo de keypair.
Is this page helpful?