Documentação SolanaDesenvolvendo programas

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 e otimizações do programa
  • 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 new com a flag --lib.

Terminal
$
cargo new hello_world --lib

Navegue até o diretório do projeto. Você deverá ver os arquivos padrão src/lib.rs e Cargo.toml

Terminal
$
cd hello_world

Atualize o campo edition no Cargo.toml para 2021. Caso contrário, você pode encontrar um erro ao compilar o programa.

Adicione a dependência solana-program

Em seguida, adicione a dependência solana-program. Esta é a dependência mínima necessária para construir um programa Solana.

Terminal
$
cargo add solana-program@2.2.0

Adicione o crate-type

Em seguida, adicione o seguinte trecho ao Cargo.toml.

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

Se você não incluir esta configuração, o diretório target/deploy não será gerado quando você compilar o programa.

Seu arquivo Cargo.toml deve parecer com o seguinte:

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

Adicione o código do programa

Em seguida, substitua o conteúdo de src/lib.rs pelo seguinte código. 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.

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

Compile o programa

Em seguida, compile o programa usando o comando cargo build-sbf.

Terminal
$
cargo build-sbf

Este comando gera um diretório target/deploy contendo dois arquivos importantes:

  1. Um arquivo .so (ex.: hello_world.so): Este é o programa Solana compilado que será implantado na rede como um "contrato inteligente".
  2. Um arquivo keypair (ex.: hello_world-keypair.json): A chave pública deste keypair é usada como o 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:

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

Exemplo de saída:

$ cargo new hello-world
Created binary (application) `hello-world` package
$ cd hello-world
$ cargo init --lib
Created library package

Adicionar dependências de teste

Em seguida, teste o programa usando o crate litesvm. Adicione as seguintes dependências ao Cargo.toml.

[package]
name = "hello-world"
version = "0.1.0"
edition = "2021"
[dependencies]
solana-program = "1.18.0"
[dev-dependencies]
solana-program-test = "1.18.0"
solana-sdk = "1.18.0"
$ cargo build

Testar o programa

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 super::*;
use solana_program::instruction::{AccountMeta, Instruction};
use solana_program_test::*;
use solana_sdk::{signature::Signer, transaction::Transaction};
#[tokio::test]
async fn test_transaction() {
let program_id = Pubkey::new_unique();
let (mut banks_client, payer, recent_blockhash) = ProgramTest::new(
"hello-world",
program_id,
processor!(process_instruction),
)
.start()
.await;
let instruction = Instruction::new_with_bincode(
program_id,
&[0],
vec![],
);
let mut transaction = Transaction::new_with_payer(
&[instruction],
Some(&payer.pubkey()),
);
transaction.sign(&[&payer], recent_blockhash);
banks_client.process_transaction(transaction).await.unwrap();
}
}

Execute o teste usando o comando cargo test. O log do programa exibirá "Hello, world!".

$ cargo test

Exemplo de saída:

running 1 test
test test::test_transaction ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Program log: Hello, world!

Implantar o programa

Em seguida, implante o programa. Ao desenvolver localmente, podemos usar o solana-test-validator.

Primeiro, configure a CLI da Solana para usar o cluster local da Solana.

$ solana config set --url localhost

Exemplo de saída:

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

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.

$ cargo build-sbf
$ solana program deploy target/deploy/hello_world.so

Exemplo de saída:

Program Id: 4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz
Signature:
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.

Criar cliente de exemplo

A seguir, demonstraremos como invocar o programa usando um cliente Rust.

Primeiro, crie um diretório examples e um arquivo client.rs.

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

Adicione o seguinte ao Cargo.toml.

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

Adicione as dependências solana-client e tokio.

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

Adicionar o cliente

Adicione o seguinte código ao examples/client.rs. Este é um script cliente em Rust que financia um novo keypair para pagar as taxas de transação e então invoca o programa 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),
}
}

Substituir o ID do programa

Antes de executar o código do cliente, substitua o ID do programa no trecho de código pelo ID do seu programa.

Você pode obter o ID do seu programa executando o seguinte comando.

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

Invocar o programa

Execute o script do cliente com o seguinte comando.

Terminal
$
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-os com o mesmo ID de programa. Atualize o programa em src/lib.rs para imprimir "Hello, Solana!" em vez de "Hello, world!".

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

Execute o comando cargo build-sbf para gerar um arquivo .so atualizado.

Terminal
$
cargo build-sbf

Teste o programa atualizado executando o comando cargo test.

Terminal
$
cargo test -- --no-capture

Você deverá ver "Hello, Solana!" no log do programa.

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

Reimplantar o programa

Reimplante o programa usando o mesmo comando solana program deploy.

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

Execute o código do cliente novamente e inspecione a assinatura da transação no Solana Explorer para ver "Hello, Solana!" no log do programa.

Terminal
$
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, então deve ser feito com cautela.

Para fechar um programa, use o comando solana program close <PROGRAM_ID>. Por exemplo:

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

Exemplo de saída:

Closed Program Id 4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz, 0.1350588 SOL
reclaimed

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, use
a new Program Id

Reimplantar um programa fechado

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:

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

Alternativamente, você pode excluir o arquivo keypair existente (por exemplo, ./target/deploy/hello_world-keypair.json) e executar cargo build-sbf novamente, que irá gerar um novo arquivo keypair.

Criar um novo programa

Primeiro, crie um novo projeto Rust usando o comando padrão cargo new com a flag --lib.

Terminal
$
cargo new hello_world --lib

Navegue até o diretório do projeto. Você deverá ver os arquivos padrão src/lib.rs e Cargo.toml

Terminal
$
cd hello_world

Atualize o campo edition no Cargo.toml para 2021. Caso contrário, você pode encontrar um erro ao compilar o programa.

Adicione a dependência solana-program

Em seguida, adicione a dependência solana-program. Esta é a dependência mínima necessária para construir um programa Solana.

Terminal
$
cargo add solana-program@2.2.0

Adicione o crate-type

Em seguida, adicione o seguinte trecho ao Cargo.toml.

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

Se você não incluir esta configuração, o diretório target/deploy não será gerado quando você compilar o programa.

Adicione o código do programa

Em seguida, substitua o conteúdo de src/lib.rs pelo seguinte código. 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.

Compile o programa

Em seguida, compile o programa usando o comando cargo build-sbf.

Terminal
$
cargo build-sbf

Este comando gera um diretório target/deploy contendo dois arquivos importantes:

  1. Um arquivo .so (ex.: hello_world.so): Este é o programa Solana compilado que será implantado na rede como um "contrato inteligente".
  2. Um arquivo keypair (ex.: hello_world-keypair.json): A chave pública deste keypair é usada como o 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:

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

Exemplo de saída:

$ cargo new hello-world
Created binary (application) `hello-world` package
$ cd hello-world
$ cargo init --lib
Created library package

Adicionar dependências de teste

Em seguida, teste o programa usando o crate litesvm. Adicione as seguintes dependências ao Cargo.toml.

[package]
name = "hello-world"
version = "0.1.0"
edition = "2021"
[dependencies]
solana-program = "1.18.0"
[dev-dependencies]
solana-program-test = "1.18.0"
solana-sdk = "1.18.0"
$ cargo build

Testar o programa

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 super::*;
use solana_program::instruction::{AccountMeta, Instruction};
use solana_program_test::*;
use solana_sdk::{signature::Signer, transaction::Transaction};
#[tokio::test]
async fn test_transaction() {
let program_id = Pubkey::new_unique();
let (mut banks_client, payer, recent_blockhash) = ProgramTest::new(
"hello-world",
program_id,
processor!(process_instruction),
)
.start()
.await;
let instruction = Instruction::new_with_bincode(
program_id,
&[0],
vec![],
);
let mut transaction = Transaction::new_with_payer(
&[instruction],
Some(&payer.pubkey()),
);
transaction.sign(&[&payer], recent_blockhash);
banks_client.process_transaction(transaction).await.unwrap();
}
}

Execute o teste usando o comando cargo test. O log do programa exibirá "Hello, world!".

$ cargo test

Exemplo de saída:

running 1 test
test test::test_transaction ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Program log: Hello, world!

Implantar o programa

Em seguida, implante o programa. Ao desenvolver localmente, podemos usar o solana-test-validator.

Primeiro, configure a CLI da Solana para usar o cluster local da Solana.

$ solana config set --url localhost

Exemplo de saída:

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

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.

$ cargo build-sbf
$ solana program deploy target/deploy/hello_world.so

Exemplo de saída:

Program Id: 4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz
Signature:
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.

Criar cliente de exemplo

A seguir, demonstraremos como invocar o programa usando um cliente Rust.

Primeiro, crie um diretório examples e um arquivo client.rs.

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

Adicione o seguinte ao Cargo.toml.

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

Adicione as dependências solana-client e tokio.

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

Adicionar o cliente

Adicione o seguinte código ao examples/client.rs. Este é um script cliente em Rust que financia um novo keypair para pagar as taxas de transação e então invoca o programa hello world.

Substituir o ID do programa

Antes de executar o código do cliente, substitua o ID do programa no trecho de código pelo ID do seu programa.

Você pode obter o ID do seu programa executando o seguinte comando.

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

Invocar o programa

Execute o script do cliente com o seguinte comando.

Terminal
$
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-os com o mesmo ID de programa. Atualize o programa em src/lib.rs para imprimir "Hello, Solana!" em vez de "Hello, world!".

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

Execute o comando cargo build-sbf para gerar um arquivo .so atualizado.

Terminal
$
cargo build-sbf

Teste o programa atualizado executando o comando cargo test.

Terminal
$
cargo test -- --no-capture

Você deverá ver "Hello, Solana!" no log do programa.

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

Reimplantar o programa

Reimplante o programa usando o mesmo comando solana program deploy.

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

Execute o código do cliente novamente e inspecione a assinatura da transação no Solana Explorer para ver "Hello, Solana!" no log do programa.

Terminal
$
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, então deve ser feito com cautela.

Para fechar um programa, use o comando solana program close <PROGRAM_ID>. Por exemplo:

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

Exemplo de saída:

Closed Program Id 4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz, 0.1350588 SOL
reclaimed

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, use
a new Program Id

Reimplantar um programa fechado

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:

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

Alternativamente, você pode excluir o arquivo keypair existente (por exemplo, ./target/deploy/hello_world-keypair.json) e executar cargo build-sbf novamente, que irá gerar um novo arquivo keypair.

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

Is this page helpful?

Índice

Editar Página