Contas de Dados & Layout O estado do programa é um buffer de bytes no campo data de uma conta. Anchor 0.32.1 usa a serialização Borsh com um prefixo discriminador de 8 bytes. O dimensionamento correto do layout evita falhas de inicialização e exploits de desserialização.
Receita #[account] #[derive(InitSpace)] pub struct Market { pub authority: Pubkey, pub price: u64, pub name: String, // max 32 em InitSpace via #[max_len(32)] } // space = 8 + Market::INIT_SPACE Quando usar isso: Calculando o espaço de init para novos tipos de conta Versionando esquemas de conta para atualizações Escolhendo Borsh vs zero-copy para trade-offs de CU e tamanho Analisando contas desconhecidas de RPC em clientes Exemplo de Trabalho use anchor_lang::prelude::*; #[account] #[derive(InitSpace)] pub struct UserStats { pub authority: Pubkey, #[max_len(16)] pub nickname: String, pub wins: u32, pub losses: u32, } #[derive(Accounts)] pub struct InitStats<'info> { #[account( init, payer = authority, space = 8 + UserStats::INIT_SPACE, seeds = [b"stats", authority.key().as_ref()], bump, )] pub stats: Account<'info, UserStats>, #[account(mut)] pub authority: Signer<'info>, pub system_program: Program<'info, System>, } #[program] pub mod stats { use super::*; pub fn init(ctx: Context<InitStats>, nickname: String) -> Result<()> { require!(nickname.len() <= 16, StatsError::NameTooLong); ctx.accounts.stats.nickname = nickname; ctx.accounts.stats.wins = 0; ctx.accounts.stats.losses = 0; Ok(()) } } O que isso demonstra: InitSpace computa o tamanho Borsh, incluindo strings max_len O discriminador de 8 bytes é adicionado automaticamente pelo Anchor O tempo de execução valida o comprimento da string em relação ao espaço alocado Mergulho Profundo Estrutura do Layout [ 8 bytes discriminador ][ Campo Borsh 1 ][ Campo 2 ]... Regras de Dimensionamento Tipos de tamanho fixo: Pubkey 32, u64 8, bool 1 String/Vec: comprimento de 4 bytes + bytes de conteúdo máximo Enums: índice de variante de 1 byte + tamanho da maior variante Versionamento Adicione version: u8 como primeiro campo após o discriminador Ou use um novo tipo de conta com um novo discriminador Nunca encolha contas sem migração Armadilhas Omissão de max_len em String/Vec - erro de compilação ou tamanho ilimitado. Correção: sempre defina #[max_len(N)] no Anchor 0.32.1. Erros de cálculo manual de espaço - erro de um caractere em enums. Correção: prefira o derive InitSpace. Reordenação de campos - quebra contas existentes. Correção: apenas adicione novos campos com versionamento. Desserialização de contas não confiáveis - o atacante cria bytes. Correção: valide o proprietário, o discriminador e os intervalos de campos. Contas enormes - custo de aluguel e de desserialização de CU. Correção: zero-copy ou divisão entre contas. Alternativas AlternativaUse QuandoNão Use QuandoBorsh + AnchorEstado padrão do programaConjuntos de dados de vários MBZero-copy (AccountLoader)Estruturas grandes, economia de CUEstruturas pequenas e simplesbytemuck PODLayouts compactados de tamanho fixoStrings de comprimento variávelCompressão externaDados em escala de NFTCampos mutáveis "quentes" FAQs O que é o discriminador de 8 bytes? Os primeiros 8 bytes do SHA256("account:StructName") no Anchor - identifica o tipo da conta. Como calculo o espaço manualmente? Some os tamanhos Borsh + 8. Para String(max N): 4 + N bytes. Posso alterar a ordem dos campos em um upgrade? Não - quebra a desserialização de contas existentes. O que é InitSpace? Macro derive do Anchor 0.32.1 que calcula a constante INIT_SPACE para o atributo space. Como os clientes decodificam os dados da conta? Use clientes Codama/@solana/kit do IDL, ou leituras de buffer manuais que correspondam ao layout Borsh. Qual é o tamanho máximo da conta? 10 MB por conta no Agave 4.1.1 - limites práticos são menores devido ao aluguel/CU. Posso armazenar JSON em contas? Desperdício e ilimitado. Use layouts binários tipados. Como os enums afetam o espaço? Borsh usa uma tag de variante de 1 byte + o tamanho da maior carga útil da variante. O que é layout zero-copy? #[account(zero_copy)] mapeia a struct diretamente para os bytes da conta sem alocação de desserialização. Devo empacotar campos manualmente? Apenas para otimização extrema de CU. O layout padrão Borsh é bom para a maioria dos programas. Como lidar com campos opcionais? Use Option<T> em Borsh (tag de 1 byte + T) ou valores sentinela. Duas structs podem compartilhar um discriminador? Não - cada tipo de conta Anchor tem um discriminador exclusivo. Relacionado Aluguel & Isenção de Aluguel - o espaço impulsiona o aluguel Estado de Propriedade do Programa - onde os layouts vivem Criação e Fechamento de Contas - realloc para crescimento Versões da Pilha: 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.