O Entrypoint e o Dispatch
O entrypoint é a única superfície RPC do seu programa. O dispatch faz parsing de instruction_data, valida o contexto e roteia para handlers com semântica de erro consistente.
Receita
entrypoint!(process_instruction);
let ix = MyInstruction::try_from_slice(data)?;
match ix { /* ... */ }Quando usar:
- Construir programas nativos sem dispatch do Anchor.
- Adicionar uma nova variante de instruction a um programa existente.
- Auditar parsing de instruction por ambiguidade.
Exemplo Funcional
use borsh::BorshDeserialize;
use solana_program::{account_info::AccountInfo, entrypoint, entrypoint::ProgramResult, pubkey::Pubkey};
entrypoint!(process_instruction);
#[derive(BorshDeserialize)]
pub enum MyInstruction { Init, Increment }
pub fn process_instruction(program_id: &Pubkey, accounts: &[AccountInfo], data: &[u8]) -> ProgramResult {
if data.is_empty() { return Err(ProgramError::InvalidInstructionData); }
let ix = MyInstruction::deserialize(&mut &data[..]).map_err(|_| ProgramError::InvalidInstructionData)?;
match ix {
MyInstruction::Init => init(program_id, accounts),
MyInstruction::Increment => increment(program_id, accounts),
}
}O que isso demonstra:
- Guarda contra data vazio antes de deserialize.
- Mapeia erros de parse para
InvalidInstructionData. - Handlers recebem
program_idpara derivação de PDA.
Aprofundamento
Como Funciona
- O runtime passa bytes raw da instruction da transação.
- O discriminante do enum é o primeiro byte serializado, a menos que use tags manuais.
- Cada handler possui a iteração de contas do seu subconjunto.
Estilos de Dispatch
| Estilo | Prós |
|---|---|
| Enum Borsh | Idiomático, compacto |
| Byte opcode manual | Estilo C, versionamento explícito |
Anchor #[program] | IDL + constraints automáticos |
Notas Rust
// Mantenha handlers finos; empurre checks compartilhados para validators.Erros Comuns
- Data vazio ambíguo - Tratado como enum vazio válido em alguns layouts.. Correção: Rejeite
data.is_empty()quando não existir instruction padrão. - Reordenação de variante - Quebra clients silenciosamente.. Correção: Apenas acrescente variantes; versione mudanças breaking.
- Match arms gordos - Handlers grandes obscurecem trilha de auditoria.. Correção: Uma função por instruction.
program_idausente - Handlers não podem verificar PDAs.. Correção: Passeprogram_idpor todos os caminhos.- Unwrap não verificado em slice - Comprimento ruim causa panic.. Correção: Use mapeamento de Result de
deserialize.
Alternativas
| Alternativa | Use Quando | Não Use Quando |
|---|---|---|
| Dispatch Anchor | IDL + validação de conta | Binário mínimo |
| Entrypoint Pinocchio | Menor overhead | Ecossistema de macros |
| Tabelas de opcode | Programas estilo firmware | Enums simples |
FAQs
Posso ter múltiplos entrypoints?
Não - um por binário de programa.
Onde fazer parse das contas?
Dentro de cada handler após parse do cabeçalho compartilhado.
Byte prefixo de versão?
Padrão comum: primeiro byte é versão do schema.
Compartilhar código com o client?
Publique crate de instruction para builders @solana/kit.
Testar dispatch?
Serialize bytes de ix em testes LiteSVM.
Variante desconhecida?
Borsh retorna erro - mapeie para InvalidInstructionData.
Contas opcionais?
Documente e use sentinel ou instructions separadas.
Tamanho máximo de instruction data?
Limitado pelo tamanho da transação (~1232 bytes).
entrypoint_no_alloc?
Padrão avançado para evitar allocator no entry.
Parse cross-program?
Nunca confie no callee para fazer parse dos seus dados.
Logging no dispatch?
OK para dev; evite em hot path de produção.
Refatorar match para tabela?
Use fn pointers apenas se ganho de tamanho de binário importar.
Relacionado
- Noções Básicas de Programas Nativos - Estrutura
- Dados de Instruction (de)Serialização - Layouts
- Noções Básicas de CPI - Chamando outros
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.