Um programa nativo no Solana é um crate Rust que depende de solana-program, tem como alvo SBF como cdylib, e expõe um entrypoint que recebe um ID de programa, uma fatia de AccountInfos e dados de instrução. Não há macro de struct de contas, nenhuma geração automática de restrições e nenhum IDL embutido. Você possui o caminho completo, desde bytes de entrada até mudanças de estado de saída.
Esta página é o mapa da seção. Use-a para posicionar o dispatch do entrypoint, validação manual, (des)serialização, leitura/escrita, criação de conta via CPI, logging e trade-offs de framework em um contínuo antes de seguir as páginas de receitas focadas.
Programas Solana nativos são módulos SBF comuns. O runtime chama process_instruction uma vez por instrução, entrega apenas o que a transação declarou e espera Ok(()) ou um ProgramError.
Sem Anchor, três tarefas caem no seu código. Parsear dados de instrução em um enum estável ou layout de opcode. Validar cada conta que o manipulador usa: signers, writability, owners, igualdade de chaves, seeds de PDA e relacionamentos de negócios. Modificar bytes de contas de propriedade do programa sob as regras de empréstimo do Solana, incluindo CPI do System Program quando uma nova conta deve existir.
Essas tarefas também são a principal superfície de risco. Uma verificação is_signer ausente, uma suposição incorreta de owner, ou um caminho de reinit em uma conta existente é um bug crítico. Frameworks codificam as mesmas regras em macros; código nativo as torna visíveis e fáceis de omitir.
Escolha nativo quando precisar de controle explícito, binários menores, CU base menor, layouts incomuns ou verificações visíveis para auditoria. Escolha Anchor 0.32.1 (ou um wrapper fino como Pinocchio) quando velocidade, geração de IDL/cliente e restrições declarativas forem mais importantes. Muitas equipes prototipam em Anchor, depois reescrevem caminhos quentes como programas nativos compostos via CPI.
Nativo significa que você programa contra a API solana-program sem a camada #[program] / #[account] do Anchor. Você ainda implanta um .so, paga taxas em lamports, declara metadados de conta de clientes como @solana/kit 7.0.0, e constrói com Agave 4.1.1 / Solana CLI 3.0.10 ferramentas SBF. Nativo é uma camada de aplicação mais fina, não uma cadeia diferente.
A chave pública do seu programa; verificações de owner e derivação de PDA
accounts: &[AccountInfo]
Contas listadas pelo cliente, com flags de signer/writable verificadas pelo runtime
instruction_data: &[u8]
Bytes opacos que você decodifica em um enum de instrução ou opcode
O runtime não re-deriva a intenção dos seus tipos Rust. Conta errada no slot 2, dados curtos, ou layout incorreto devem falhar de forma fechada no seu manipulador.
AccountInfo expõe chave, lamports, dados, owner, executável, is_signer e is_writable. Essas flags refletem o que a transação declarou e o runtime verificou para assinaturas. Elas não provam "esta é a vault para este usuário" ou "este é o estado seguro do programa". Essa política é sua: comparações, verificações de PDA e inspeção de campos dentro dos dados.
Layout típico: cdylib, entrypoint!(process_instruction), módulos para instruction, processor, state, e error, mais solana-program e um serializador (frequentemente Borsh). Um entrypoint por binário; múltiplos tipos de instrução vivem atrás de um match em dados parseados. Noções Básicas de Programa Nativo percorre o esqueleto com exemplos.
Cliente (@solana/kit / CLI / Chamador de CPI) | Lista AccountMeta + instruction_data | Assina (ou invoke_signed do chamador) v Runtime: carrega contas, verifica sigs e metadados graváveis | v entrypoint! -> process_instruction(program_id, accounts, data) | | 1. desserializa instruction_data | 2. next_account_info / ordem fixa de contas | 3. valida signers, owners, PDAs, relacionamentos | 4. pega emprestado/modifica dados, ou CPI System Program | 5. msg! opcional / sol_log_data v Ok(()) confirma | Err(ProgramError) aborta instrução
Valide antes de efeitos colaterais sempre que possível. Uma instrução (ou transação) falha não deixa efeitos parciais do programa desse caminho de falha.
Desserialize uma vez no topo, então match para os manipuladores. Passe program_id para caminhos de PDA e owner. Mapeie erros de domínio para códigos estáveis ProgramError::Custom para clientes.
Os dados de instrução são o formato de comunicação entre construtores off-chain e código on-chain. Um padrão comum é um enum Borsh (primeiro byte do índice da variante, depois os campos):
Não reordene variantes ativas. Limite strings e vetores ilimitados. Adicione um byte de versão quando precisar quebrar o layout. Espelhe a mesma codificação em TypeScript com @solana/kit 7.0.0 ou um pipeline Codama/schema compartilhado para que os clientes não possam divergir silenciosamente. Veja Serialização/Desserialização de Dados de Instrução.
A segurança nativa é uma lista de verificação explícita em cada caminho:
Verificação
Padrão
Signer
account.is_signer
Gravável
account.is_writable
Owner é seu programa
account.owner == program_id
Owner é System/Token/etc.
igualdade com o ID do programa esperado
Identidade PDA
find_program_address + bump armazenado
Relacionamentos
igualdade de chaves; campos de mint/authority nos dados
Sysvars
Sysvar::get() ou chaves conhecidas, não falsificações
Execute verificações de flags baratas antes de CPI ou desserialização pesada. Documente a ordem das contas; consuma com next_account_info. Para contas de token, o owner é o programa Token; a autoridade e o mint vivem dentro dos dados.
Programas criam contas via CPI para o System Program (create_account ou alocar/atribuir relacionados). O pagador financia lamports isentos de aluguel; space dimensiona o buffer; owner se torna seu program_id para o estado do programa.
PDAs não têm chave privada. Use invoke_signed com seeds e bump exatos:
let rent = Rent::get()?;let lamports = rent.minimum_balance(State::LEN);invoke_signed( &system_instruction::create_account( payer.key, pda.key, lamports, State::LEN as u64, program_id, ), &[payer.clone(), pda.clone(), system_program.clone()], &[&[b"vault", owner.key.as_ref(), &[bump]]],)?;// inicializa dados após a criação
Valide o ID do System Program, suposições de conta vazia/nova e correspondência de seeds. Caminhos de reinit e "conta já existe" são classes clássicas de exploração. Fluxo completo: Criando Contas via CPI.
msg! e helpers relacionados escrevem logs de transação para simulação, exploradores e indexadores. O custo escala com o volume e o tamanho da string. Use breadcrumbs estruturados em desenvolvimento e logs esparsos em produção. Prefira erros customizados tipados para falhas esperadas. Veja Emitindo Logs.
Nativo ainda precisa de uma história de cliente: construtores escritos à mão, um crate compartilhado, ou ferramentas Codama/IDL. Testes devem afirmar falhas de validação (owner errado, signer ausente, PDA ruim), não apenas caminhos felizes. Testes unitários estilo LiteSVM e validadores locais sob Solana CLI 3.0.10 cobrem a velocidade da lógica versus loops completos de deploy RPC.
Prefira nativo quando pelo menos dois se aplicarem: CU da instrução é crítica para o negócio; o layout conflita com contas Anchor; o tamanho do binário é restrito; auditores exigem validação totalmente explícita; ou você envia uma primitiva para a qual outros programas farão CPI.
Não escolha nativo apenas porque "Anchor é lento" sem profiling. Contenção, RPC e algoritmos frequentemente dominam a sobrecarga de macros.
Forma comum: Anchor para admin e instruções de baixa frequência; nativo para o loop apertado (passo de match, tick de jogo, liquidação). Componha com CPI e layouts compartilhados. Documente qual ID de programa possui qual estado.
Para cada instrução pergunte: quem deve assinar; quais contas são escritas e com qual owner; um PDA, mint ou conta de token diferente pode ser substituído; initialize pode ser chamado novamente em dados não vazios; seeds/bumps são canônicos; empréstimos são liberados antes da CPI; o layout da instrução corresponde aos clientes publicados?
Fixe Agave, CLI e solana-program como dependências de aplicação. Documente códigos de erro customizados para consumidores de @solana/kit. Trate mudanças de layout como migrações com portões de versão.
Conceito Errado: Nativo pula a segurança porque o runtime já verificou as contas.
O runtime verifica assinaturas e metadados graváveis para as contas listadas. Ele não conhece suas seeds de vault, vinculações de mint ou política de admin.
Conceito Errado: is_writable significa que a conta pode ser tratada como seu estado.
Gravável apenas significa que a transação permitiu mutação. Ainda verifique owner, identidade e discriminadores.
Conceito Errado: Owner igual a Token Program é suficiente para "a conta de token do usuário".
Autoridade, mint e quantidade vivem nos dados. Valide campos (e muitas vezes a derivação de ATA) para a ação econômica.
Conceito Errado: Enums de instrução podem ser reordenados se o Rust ainda compilar.
Índices de variantes são formato de comunicação. Reordenar quebra clientes antigos e pode mapear opcodes antigos para manipuladores novos.
Conceito Errado: Criar um PDA é um create_account simples sem seeds.
Ações autorizadas por PDA precisam de invoke_signed com as seeds que o runtime espera.
Conceito Errado: Logging é observabilidade gratuita.
Logs custam CU e incham metadados. Não são substitutos para erros ou métricas off-chain.
Conceito Errado: Nativo é automaticamente mais seguro que Anchor.
Ambos falham sob validação incorreta. Nativo move o padrão de "macro pode omitir" para "autor pode omitir".
Conceito Errado: Programas nativos não precisam de um IDL ou esquema de cliente.
Sem uma codificação publicada, os construtores divergem. Envie um esquema, crate compartilhado ou pipeline Codama.
Um crate SBF solana-program com um entrypoint que analisa manualmente dados de instrução, valida AccountInfos e atualiza o estado de propriedade do programa (muitas vezes com CPI do System Program), sem macros Anchor.
Programas nativos usam um runtime diferente dos programas Anchor?
Não. Ambos são SBF sob o mesmo runtime Agave. Anchor gera mais cola; a cadeia vê um ID de programa e bytecode de qualquer maneira.
O que o entrypoint recebe?
program_id, uma fatia de AccountInfo para contas listadas e uma fatia de bytes de dados de instrução.
Por que a ordem das contas faz parte da API?
Clientes constroem uma lista paralela de AccountMeta. Manipuladores tipicamente consomem contas em ordem fixa com next_account_info. Documente essa ordem ou gere-a a partir de uma única fonte de verdade.
O que devo validar que o runtime não valida?
Identidade de negócios: qual PDA, mint e autoridade; se initialize já foi executado; relacionamentos entre contas; e política de owner além da presença de assinatura.
Como devo estruturar os dados de instrução?
Prefira um layout versionado e documentado (comumente um enum Borsh). Mantenha variantes estáveis, limite tamanhos dinâmicos e espelhe o layout nos clientes.
Como crio uma conta de propriedade do programa a partir de código nativo?
CPI system_instruction::create_account com lamports isentos de aluguel, espaço desejado e owner = program_id. Use invoke_signed quando o novo endereço for um PDA.
Quando preciso de `invoke_signed`?
Sempre que um PDA precisar autorizar uma ação porque nenhuma chave privada Ed25519 existe para esse endereço.
Como leio e escrevo estado com segurança?
Verifique owner e comprimento, pegue emprestado os dados, desserialize ou use uma visualização segura, modifique com aritmética verificada, serialize dentro da capacidade e libere empréstimos antes da CPI na mesma conta.
Logs `msg!` são obrigatórios?
Não. Use-os para depuração e breadcrumbs esparsos em produção. Prefira valores claros de ProgramError para falhas esperadas.
Como os clientes se comunicam com programas nativos?
Construa transações que listem as contas corretas e serialize os mesmos bytes de instrução que o programa espera, usando @solana/kit 7.0.0 ou outros SDKs.
Nativo sempre tem CU menor que Anchor?
Nativo tem um piso mais baixo e mais controle, mas o CU real depende de verificações, logs, serialização e CPI. Meça instruções quentes.
Posso misturar Anchor e nativo?
Sim. Programas separados compostos com CPI é comum: Anchor para superfícies de admin, nativo para lógica central sensível ao desempenho.
Qual é o maior erro de segurança em programas nativos?
Validação incompleta: signer ausente, owner errado, substituição de PDA ou reinicialização em conta existente. Trate cada instrução como entrada hostil.
Para onde devo ir a seguir nesta seção?
Comece com Noções Básicas de Programa Nativo, depois aprofunde validação, dados de instrução, criação via CPI, I/O de conta e logs através dos Relacionados abaixo.