Noções Básicas de Programas Nativos
10 exemplos para você começar com Programas Nativos - 7 básicos e 3 intermediários.
Pré-requisitos
- Solana CLI 3.0.10 com
cargo build-sbf. - Rust 1.91.1 e um crate de programa com dependência
solana-program. - Familiaridade com Noções Básicas de Rust para Solana.
Exemplos Básicos
1. Cargo.toml mínimo
Programas nativos visam SBF com crate type cdylib.
[lib]
crate-type = ["cdylib"]
[dependencies]
solana-program = "2.2"
borsh = "1.5"cdylibproduz o.soimplantável.- Fixe
solana-programpara corresponder ao SDK Agave 4.1.1. - Mantenha a contagem de dependências baixa.
2. Esqueleto lib.rs
A raiz do crate conecta módulos e entrypoint.
#![no_std]
extern crate alloc;
mod error;
mod instruction;
mod processor;
use solana_program::entrypoint;
entrypoint!(processor::process_instruction);- Separe dispatch, state e errors em módulos.
- Apenas um
entrypoint!por crate. - Exporte o enum de instruction em
instruction.rs.
3. Enum Instruction
Marque instructions com um enum Borsh.
use borsh::{BorshDeserialize, BorshSerialize};
#[derive(BorshSerialize, BorshDeserialize)]
pub enum HelloInstruction {
Greet { name: String },
}- O primeiro byte é o índice da variante por padrão.
- Mantenha variantes estáveis entre upgrades.
- Corresponda exatamente à serialização do client.
Relacionado: Dados de Instruction (de)Serialização - parsing
4. Match de dispatch
Roteie instructions parseadas para handlers.
pub fn process_instruction(
program_id: &Pubkey,
accounts: &[AccountInfo],
data: &[u8],
) -> ProgramResult {
let ix = HelloInstruction::deserialize(&mut &data[..])?;
match ix {
HelloInstruction::Greet { name } => greet(accounts, name),
}
}- Deserialize uma vez no nível superior.
- Passe
program_idpara handlers que derivam PDAs. - Use
?para propagação de erros.
Relacionado: O Entrypoint e o Dispatch - padrões
5. Iterador de contas
Consuma contas em ordem fixa.
let iter = &mut accounts.iter();
let payer = next_account_info(iter)?;
let state = next_account_info(iter)?;- A ordem deve corresponder à lista
AccountMetado client. - Retorne
NotEnoughAccountKeysse o iterador estiver vazio. - Documente a ordem no README/IDL do programa.
6. Módulo de erro customizado
Centralize erros de domínio.
#[repr(u32)]
pub enum MyError { BadName = 0 }
impl From<MyError> for ProgramError {
fn from(e: MyError) -> Self { ProgramError::Custom(e as u32) }
}- Mapeie para
ProgramError::Custompara clients. - Evite sobrepor ranges do Anchor se houver tooling misto.
- Exporte códigos para clients @solana/kit 7.0.0.
7. Struct State com LEN
Defina constante de tamanho da conta.
#[derive(BorshSerialize, BorshDeserialize)]
pub struct State { pub counter: u64 }
impl State {
pub const LEN: usize = 8;
}- Use a constante ao chamar
create_account. - Asserte o comprimento em cada acesso.
InitSpacedo Anchor é o equivalente em macro.
Exemplos Intermediários
8. Criar conta via CPI
O System Program aloca espaço e atribui owner.
invoke(
&system_instruction::create_account(
payer.key, state.key, rent, State::LEN as u64, program_id,
),
&[payer.clone(), state.clone(), system_program.clone()],
)?;- O payer deve assinar e ser writable.
- Isenção de rent calculada com sysvar
Rent. - Após o CPI, serialize o state inicial.
Relacionado: Criando Contas via CPI - fluxo completo
9. Ler e atualizar state
Borrow data, mute, serialize de volta.
let mut state = State::deserialize(&mut &account.data.borrow()[..])?;
state.counter = state.counter.saturating_add(1);
state.serialize(&mut &mut account.data.borrow_mut()[..])?;- Libere borrows antes de CPI que toca a mesma conta.
- Use aritmética checked/saturating.
- O owner deve ser seu programa.
Relacionado: Lendo e Escrevendo Dados de Conta - padrões
10. Emitir uma linha de log
Depure com msg! durante o desenvolvimento.
solana_program::msg!("greet: {}", name);- Visível em explorers e simulação.
- Custa CUs - remova em hot paths se necessário.
- Prefira erros para falhas voltadas ao usuário.
Relacionado: Emitindo Logs - guia de logging
Versões do 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.