Execução de programas

Resumo

Os programas são compilados para sBPF via LLVM e executados numa VM isolada com um orçamento de 1,4M CU por transação. O runtime mantém em cache até 512 programas compilados, fornece syscalls para logging, CPI, criptografia e memória, e atrasa novas implementações em 1 slot.

Compilação

A Solana usa LLVM para compilar programas em binários ELF contendo Solana Bytecode Format (sBPF). O binário ELF é armazenado on-chain numa conta executável.

sBPF é a variante personalizada da Solana do bytecode eBPF, adaptada para o runtime da Solana. Não é eBPF padrão e possui modificações específicas da Solana.

Escrever programas

Os programas Solana são escritos principalmente em Rust usando uma de duas abordagens:

Modelo de execução de programas

Quando uma transação é processada, o runtime executa cada instrução sequencialmente através de process_message(). Para cada instrução, o runtime:

  1. Prepara o contexto da instrução. Chama prepare_next_top_level_instruction() para mapear os índices de conta da instrução, definir flags de signatário e escrita, e configurar o TransactionContext.

  2. Verifica precompilações. Se o programa for uma precompilação, o runtime chama process_precompile(), que ainda adiciona e remove um stack frame (via push() e pop()) mas ignora a VM sBPF e a pesquisa na cache de programas, executando código nativo diretamente.

  3. Empurra um stack frame. (Os passos 3-6 acontecem dentro de InvokeContext::process_instruction() e process_executable_chain(), chamados de process_message().) Chama push() em InvokeContext, que incrementa a altura da pilha de instruções e aplica a regra de reentrada: um programa só pode reentrar em si mesmo se o chamador imediato (o programa no topo atual da pilha de instruções) for o mesmo programa. Auto-recursão profunda (A -> A -> A) é permitida, sujeita aos limites de profundidade da pilha. Outros padrões de reentrada (por exemplo, A chama B chama A) retornam InstructionError::ReentrancyNotAllowed.

  4. Resolve o programa. O runtime chama process_executable_chain() que determina o loader. Se o proprietário da conta do programa for o native loader, o programa é um builtin e sua função de entrypoint é procurada diretamente no ProgramCacheForTxBatch. Se o proprietário for um dos loaders BPF (bpf_loader_deprecated, bpf_loader, bpf_loader_upgradeable, ou loader_v4), o entrypoint builtin do próprio loader é invocado.

  5. Executa o programa BPF. Para programas BPF, o entrypoint do loader procura o executável compilado no cache de programas. A função execute() então:

    • Serializa os dados da conta num buffer de parâmetros plano
    • Cria a VM sBPF com regiões de pilha, heap e memória
    • Executa o código compilado, consumindo unidades de computação durante a execução. Retorna ComputationalBudgetExceeded se o orçamento for excedido.
    • Desserializa os dados da conta do buffer de volta para o estado da conta
  6. Remove o stack frame. Chama pop() que verifica se a instrução não violou as regras de contabilidade do runtime (saldos de lamport estão equilibrados, contas somente leitura não foram modificadas, tamanhos de dados de conta estão dentro dos limites).

  7. Acumula unidades de computação. As unidades de computação consumidas pela instrução são adicionadas ao total da transação via saturating_add.

Cache de programas

O runtime mantém um ProgramCache global que armazena programas verificados e compilados. Ele reconhece o grafo de bifurcações e lida com regras de visibilidade de implantação, remoção e recompilação no limite de epoch.

Tipos de entrada de cache

Cada programa em cache possui um ProgramCacheEntryType que determina seu comportamento em tempo de execução:

TipoDescrição
LoadedPrograma verificado e compilado, pronto para execução.
BuiltinPrograma nativo compilado no binário do validador (System, Stake, Vote, etc.). Não armazenado on-chain.
UnloadedPrograma previamente verificado cujo executável compilado foi removido da memória para liberar espaço. Ainda rastreia estatísticas de uso. Pode ser recarregado sem reverificação.
FailedVerificationMarcador para programas que não passaram no verificador sBPF sob o conjunto de recursos atual. Pode tornar-se Loaded se as ativações de recursos alterarem as regras de verificação.
ClosedMarcador para programas que foram explicitamente fechados ou nunca implantados. Também usado para contas (como contas de buffer) que pertencem a um carregador mas não contêm código executável.
DelayVisibilityMarcador sintético retornado por ProgramCacheForTxBatch::find() quando uma entrada Loaded existe mas ainda não está efetiva (seu effective_slot está no futuro). Nunca armazenado diretamente no cache.

Atraso de visibilidade

Programas recém-implantados ou atualizados não são efetivos imediatamente. A constante DELAY_VISIBILITY_SLOT_OFFSET é 1, o que significa que um programa implantado no slot N torna-se efetivo no slot N+1. Durante o slot de implantação, qualquer tentativa de invocar a nova versão retorna DelayVisibility, fazendo com que o runtime reporte "Programa não está implantado."

Política de remoção

O cache armazena até MAX_LOADED_ENTRY_COUNT (512) entradas de programas compilados. Quando o limite é atingido, os programas menos utilizados são removidos para o estado Unloaded. O uso é rastreado por tx_usage_counter (incrementado cada vez que uma transação referencia o programa) e latest_access_slot.

Recompilação no limite de epoch

Se uma ativação de funcionalidade alterar o ProgramRuntimeEnvironments no limite de um epoch, todos os programas em cache são recompilados contra o novo ambiente.

Dados de retorno

Os programas podem definir dados de retorno através da syscall sol_set_return_data. Os dados são armazenados numa estrutura TransactionReturnData ao nível da transação que contém os bytes de dados e o program_id do programa cuja instrução chamou a syscall. O tamanho máximo é de 1.024 bytes (MAX_RETURN_DATA).

Is this page helpful?

Índice

Editar Página

Gerenciado por

© 2026 Fundação Solana.
Todos os direitos reservados.
Conecte-se
  • Blog