Noções Básicas de Rust para Solana
10 exemplos para você começar com Rust On-Chain - 7 básicos e 3 intermediários.
Pré-requisitos
- Rust 1.91.1 com
cargoe toolchain Solana CLI 3.0.10 (cargo build-sbf). - Um crate de programa usando
solana-program(nativo) ou Anchor 0.32.1. - Validador local via Surfpool 0.12.0 ou
solana-test-validatorpara testes de integração.
Exemplos Básicos
1. Entrypoint do programa
Todo programa on-chain expõe um único entrypoint! que recebe contas e dados de instrução.
use solana_program::{
account_info::AccountInfo, entrypoint, entrypoint::ProgramResult,
pubkey::Pubkey,
};
entrypoint!(process_instruction);
pub fn process_instruction(
_program_id: &Pubkey,
_accounts: &[AccountInfo],
_instruction_data: &[u8],
) -> ProgramResult {
Ok(())
}- O runtime chama
process_instructionpara cada instrução em uma transação. - Retorne
Ok(())em sucesso; retorneErr(ProgramError::...)para falhar a transação. - Sem função
main- o loader BPF/SBF invoca seu entrypoint diretamente.
Relacionado: The Entrypoint & Dispatch - roteamento de instruções
2. Ambiente no_std
Crates on-chain compilam sem a biblioteca padrão.
#![no_std]
extern crate alloc;
use alloc::vec::Vec;#![no_std]desabilitastd; useallocparaVec,StringeBoxquando necessário.- Sem filesystem, threads ou rede - apenas syscalls Solana via
solana_program. - Mantenha dependências mínimas para reduzir tamanho do binário e compute units (CUs).
Relacionado: no_std & the Program Environment - APIs disponíveis
3. Serializar dados de conta com Borsh
A maioria dos layouts de conta usa Borsh para codificação de bytes determinística.
use borsh::{BorshDeserialize, BorshSerialize};
#[derive(BorshSerialize, BorshDeserialize)]
pub struct Counter {
pub count: u64,
}
let mut data = account.try_borrow_mut_data()?;
counter.serialize(&mut &mut data[..])?;- Borsh é o formato de fato para dados de instrução e structs de conta pequenas.
- Serialize no slice de bytes da conta; pré-aloque espaço na criação da conta.
- Sempre valide o comprimento da conta antes de deserializar.
Relacionado: Borsh Serialization - guia completo
4. Ler um Pubkey a partir de bytes
Pubkeys são identificadores de 32 bytes para contas e programas.
use solana_program::pubkey::Pubkey;
let key = Pubkey::new_from_array(account.key.to_bytes());
if *account.key != expected_owner {
return Err(ProgramError::IncorrectProgramId);
}PubkeyimplementaCopye compara em tempo constante - use para checagens de owner.- Nunca confie em pubkeys fornecidos pelo cliente sem verificar contra seeds ou estado armazenado.
- IDs de programa são pubkeys derivados do keypair do programa no deploy.
5. Aritmética verificada
Overflow em panic aborta a transação - use math verificada.
let new_balance = old_balance
.checked_add(amount)
.ok_or(ProgramError::InvalidArgument)?;- Builds release em SBF não fazem trap em overflow da mesma forma que Rust host - ainda use
checked_*. saturating_*é apropriado quando limitar valores é aceitável.- Lógica financeira nunca deve usar
+,-ou*sem verificação.
Relacionado: Safe Arithmetic - padrões de overflow
6. Retornar erro de programa
Falhe rápido com erros tipados em vez de panic.
use solana_program::program_error::ProgramError;
if amount == 0 {
return Err(ProgramError::InvalidArgument);
}- Códigos
ProgramErrorsão compactos e baratos comparados a strings customizadas. - Enums de erro customizados (via
thiserrorou manual) mapeiam para códigosu32para clientes. - Nunca use
unwrap()ouexpect()em caminhos de produção do programa.
Relacionado: Error Handling On-Chain - erros customizados
7. Borrow de dados de conta
Dados de conta são acessados por borrows estilo RefCell.
let data = account.try_borrow_data()?;
if data.len() < Counter::LEN {
return Err(ProgramError::InvalidAccountData);
}try_borrow_datafalha se a conta já estiver em borrow mutável.- Solte borrows antes de CPIs que tocam a mesma conta.
- Valide
data.len()corresponde ao tamanho da struct antes de parsear.
Exemplos Intermediários
8. Header de conta zero-copy
Contas grandes podem usar bytemuck para reinterpretar bytes sem copiar.
use bytemuck::{Pod, Zeroable};
#[repr(C)]
#[derive(Clone, Copy, Pod, Zeroable)]
pub struct Header {
pub discriminator: u64,
pub count: u64,
}
let header = bytemuck::from_bytes::<Header>(&data[..8]);Pod+Zeroableexigem#[repr(C)]e sem surpresas de padding.- Zero-copy evita alocação em heap e economiza CUs em caminhos quentes.
- Combine com tail Borsh para campos de comprimento variável quando necessário.
Relacionado: Zero-Copy with bytemuck - regras Pod
9. Log sem estourar orçamento de CU
Use msg! com moderação; logs custam compute units.
solana_program::msg!("deposit: {} lamports", amount);- Logs aparecem na metadata da transação e na saída de simulação.
- Format strings e muitos logs podem dominar uso de CU em loops apertados.
- Prefira erros customizados estruturados para falhas voltadas ao cliente.
Relacionado: Logging with msg! - logging consciente de CU
10. Padrão de loop consciente de CU
Limite iterações e evite crescimento de heap em caminhos quentes.
const MAX_ITEMS: usize = 32;
for (i, item) in items.iter().take(MAX_ITEMS).enumerate() {
process_item(i, item)?;
}- Loops sem limite são achado comum de auditoria e vetor de exaustão de CU.
- Pré-dimensione vectors na init da conta em vez de push a cada instrução.
- Profile com
solana program show --programse simulação de transação.
Relacionado: Program Size & CU Discipline - otimização
Versões da stack: Esta página foi escrita para Agave 4.1.1, Solana CLI 3.0.10, Anchor 0.32.1, anchor-lang 0.32.1, Rust 1.91.1, @solana/kit 7.0.0, Surfpool 0.12.0 e LiteSVM 0.6.x.