O Modelo Mental da Solana vs. EVM
Se você vem do Ethereum, a maior mudança é onde o estado vive. Contratos EVM agrupam código e storage. A Solana separa programas (código) de contas (dados). Isso dirige paralelismo, dimensionamento de contas e padrões de segurança.
Receita
Cartão de receita de referência rápida - pronto para copiar.
| Conceito EVM | Equivalente Solana |
|---|---|
| Contract | Program (conta executável) |
| Contract storage | Contas de dados com owner programa |
msg.sender | Conta signatária na struct Accounts |
| Contract address | Program ID (ou PDA para estado derivado) |
mapping | Múltiplas contas indexadas por seeds |
| Gas | Compute units (CU) + priority fees |
Quando usar:
- Portar arquitetura de dapp EVM para Solana
- Explicar Solana a colegas nativos de Ethereum
- Projetar layouts de conta em vez de mappings de storage
- Entender por que transações listam todas as contas explicitamente
- Evitar anti-padrões "um contrato possui tudo"
Exemplo Prático
use anchor_lang::prelude::*;
declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");
// Equivalente EVM: contract UserProfile { mapping(address => Profile) profiles; }
// Solana: cada profile é sua própria conta, com owner deste programa
#[account]
pub struct UserProfile {
pub authority: Pubkey,
pub name: String,
pub score: u64,
}
#[derive(Accounts)]
pub struct CreateProfile<'info> {
#[account(
init,
payer = authority,
space = 8 + 32 + (4 + 32) + 8,
seeds = [b"profile", authority.key().as_ref()],
bump,
)]
pub profile: Account<'info, UserProfile>,
#[account(mut)]
pub authority: Signer<'info>,
pub system_program: Program<'info, System>,
}
#[program]
pub mod profiles {
use super::*;
pub fn create_profile(ctx: Context<CreateProfile>, name: String) -> Result<()> {
let profile = &mut ctx.accounts.profile;
profile.authority = ctx.accounts.authority.key();
profile.name = name;
profile.score = 0;
Ok(())
}
}O que isso demonstra:
- Estado é conta
UserProfileseparada, não storage dentro do programa - Seeds PDA (
b"profile", authority) substituemmapping(address => Profile) initcria e financia conta com lamports isentos de rent- O programa é sem estado - só lê/escreve contas passadas na instrução
Aprofundamento
Como Funciona
- Programas são bytecode em contas executáveis. Não armazenam dados de aplicativo.
- Contas de dados guardam bytes serializados. Um programa escreve só em contas que possui.
- Transações declaram toda conta tocada em todas instruções.
- Sealevel agenda transações não conflitantes em paralelo com base em locks de conta.
Comparação EVM vs Solana
| Aspecto | EVM | Solana |
|---|---|---|
| Localização do estado | Dentro do contrato | Contas separadas |
| Paralelismo | Sequencial por contrato | Paralelo em contas não sobrepostas |
| Modelo de conta | Contrato tem saldo + storage | Toda entidade é uma conta |
| Upgradeability | Padrões proxy | Loader upgradeable (BPF Upgradeable) |
| Identidade | Endereço de contrato | Program ID + PDAs |
Implicações de Design
- Dimensione contas antecipadamente (ou
realloc) - sem mappings ilimitados - Passe todas contas explicitamente - sem
CALLcom contexto implícito - Use PDAs como endereços determinísticos por usuário/entidade
- Programas validam ownership em toda instrução
Notas Rust
// EVM: require(msg.sender == owner)
// Solana: constraint na struct Accounts
#[account(has_one = authority)]
pub data: Account<'info, MyData>,
pub authority: Signer<'info>,Erros Comuns
- Uma conta grande para todos usuários - atinge limites de tamanho e impede paralelismo. Correção: uma conta por usuário/entidade com seeds PDA.
- Esperar contexto implícito de caller - Solana não tem
msg.senderglobal. Correção: passe contas signatárias e valide com constraints. - Chamar programas sem declarar contas - transações falham em runtime. Correção: liste toda conta que o callee precisa na transação.
- Armazenar saldos dentro do binário do programa - impossível; programas são executáveis somente leitura. Correção: use contas de token ou saldos de lamports em contas de dados.
- Assumir estado cross-program atômico - CPI compartilha locks de conta da transação. Correção: projete instruções com todas contas necessárias em uma transação.
- Ignorar rent - contas precisam depósitos de lamports. Correção: financie contas até mínimo isento de rent na criação.
Alternativas
| Alternativa | Use Quando | Não Use Quando |
|---|---|---|
| PDA por entidade | Estado específico de usuário | Config global (use PDA única) |
| Contas zero-copy | Datasets grandes, economia de CU | Structs pequenas onde Borsh basta |
| State compression | Milhões de NFTs/holders | Estado quente mutado frequentemente |
| EVM na Solana (experimentos Alloy/SVM) | Port de Solidity legado | Apps greenfield nativas Solana |
FAQs
Onde meu programa armazena dados na Solana?
Em contas separadas que seu programa possui. O programa em si guarda apenas bytecode executável.
O que substitui um mapping EVM?
PDAs derivadas de seeds (ex.: [b"user", user_pubkey]). Cada entrada é sua própria conta.
Existe equivalente Solana de msg.sender?
A conta signatária passada à sua instrução. Valide com Signer<'info> ou constraints has_one.
Dois programas podem escrever a mesma conta?
Só o programa owner pode escrever dados. Outros programas podem ler se a conta for passada e marcada writable pelo owner via CPI.
Por que transações devem listar todas contas antecipadamente?
O Sealevel usa a lista para agendar execução paralela e aplicar regras de lock antes da execução começar.
Programas Solana têm saldos?
Contas de programa guardam lamports para rent, mas saldos de token/SOL de aplicativo vivem em contas de usuário/token, não no programa.
Como upgradeability se compara a proxies EVM?
A Solana usa BPF Upgradeable Loader - buffer de programa e conta de program data. Authority pode implantar novo bytecode.
O que substitui ERC-20 na Solana?
Programa SPL Token com mint e contas de token. Não é contrato por token.
Gas é o mesmo que compute units?
Conceito similar. CU mede compute on-chain. Taxas incluem custo base de signature mais priority fee por preço de CU.
Posso implantar um programa por usuário como factory contracts?
Tecnicamente sim, mas é desperdício. Use um programa com muitas contas de dados (PDAs) por usuário.
Como eventos funcionam vs logs EVM?
Programas emitem logs via msg! e Anchor emit!. Clientes fazem parse de logs de transação - não há store persistente de logs on-chain.
A Solana tem construtores de contrato?
Não. Use instrução init que cria e configura contas no primeiro uso.
Relacionado
- Noções Básicas de Solana - visão geral do modelo de contas
- Como uma Transação Flui - design centrado em transação
- SOL, Lamports e Unidades - tratamento de moeda nativa
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.