Padrões de Inicialização de Conta
A inicialização é o momento de maior risco: ataques de reinit, substituição de conta e omissão de discriminador comprometem permanentemente a custódia. Separe criar de init, escreva discriminadores uma vez e rejeite contas já inicializadas.
Receita
if account.lamports() > 0 && is_initialized(&account)? { return Err(...); }Quando usar isso:
- Primeira instrução de onboarding do usuário.
- Escolha entre
initeinit_if_neededno Anchor. - Auditoria de criação de cofre.
Exemplo de Trabalho
pub fn initialize(state: &AccountInfo, payer: &AccountInfo, system: &AccountInfo, program_id: &Pubkey, bump: u8) -> ProgramResult {
if state.lamports() > 0 {
let data = state.try_borrow_data()?;
if data.len() >= 8 && data[..8] == STATE_DISC { return Err(ProgramError::AccountAlreadyInitialized); }
}
// create_account CPI if empty, then write disc + State::default()
Ok(())
}O que isso demonstra:
- Detecta discriminador existente.
- Retorna equivalente a AccountAlreadyInitialized.
- Cria somente quando vazio.
Mergulho Profundo
Padrões
| Padrão | Risco |
|---|---|
| init | Baixo se disc verificado |
| init_if_needed | Reinit se guarda fraca |
| create pelo cliente + init pelo programa | Confiança dividida |
Anchor 0.32.1
Constraints init, init_if_needed, realloc.
Notas de Rust
// Always set discriminator before accepting deposits.Armadilhas
- init_if_needed sem verificação de disc - Dreno por reinit.. Correção: Guarda de inicializado forte.
- Init após transferência de token - Qualquer um pode front-run a forma.. Correção: Init antes do valor.
- Tipo de conta errado inicializado - Confusão de tipo.. Correção: Disc único por tipo.
- Pagador não é signatário - Create falha ou pagador errado.. Correção: Valide signatário.
- Pular verificação de rent - Conta desalocada.. Correção: Financie minimum_balance.
Alternativas
| Alternativa | Use Quando | Não Use Quando |
|---|---|---|
| Txs create/init em duas etapas | Custo de UX mais seguro | Conveniência em um passo |
| Create apenas pelo cliente | Programa mais simples | Fluxos PDA mais difíceis |
| Macro init do Anchor | Mais rápido | Deve entender a expansão |
FAQs
AccountAlreadyInitialized?
Custom ou InvalidAccountData.
Pagador init do Anchor?
Constraint de signatário.
Init de PDA?
invoke_signed create.
Disc primeiro?
Antes de fundos aceitos.
Realloc no init?
Se tamanho desconhecido antecipadamente - raro.
Fechar e depois reinit?
Permitido se totalmente zerado.
Init de conta de token?
Fluxo SPL separado.
Testes?
Tente double init no LiteSVM.
Front-run de init?
Use create idempotente ou pagador assinado apenas pelo usuário.
Programa imutável?
Lógica de init congelada - teste pesadamente.
Surfpool?
Simule create+init.
Auditoria #1?
Classe de reinicialização.
Relacionados
- Ataques de Reinicialização - Exploits
- Criando Contas via CPI - Create via CPI
- Discriminadores de Conta - Tags
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.