Esecuzione del programma

Riepilogo

I programmi vengono compilati in sBPF tramite LLVM ed eseguiti in una VM sandbox con un budget di 1,4M CU per transazione. Il runtime memorizza nella cache fino a 512 programmi compilati, fornisce syscall per logging, CPI, crittografia e memoria, e ritarda i nuovi deployment di 1 slot.

Compilazione

Solana utilizza LLVM per compilare i programmi in binari ELF contenenti Solana Bytecode Format (sBPF). Il binario ELF viene memorizzato on-chain in un account eseguibile.

sBPF è la variante personalizzata di Solana del bytecode eBPF, adattata per il runtime Solana. Non è eBPF standard e presenta modifiche specifiche per Solana.

Scrivere programmi

I programmi Solana sono scritti principalmente in Rust utilizzando uno dei due approcci:

Modello di esecuzione del programma

Quando viene elaborata una transazione, il runtime esegue ogni istruzione sequenzialmente tramite process_message(). Per ogni istruzione, il runtime:

  1. Prepara il contesto dell'istruzione. Chiama prepare_next_top_level_instruction() per mappare gli indici degli account dell'istruzione, impostare i flag signer e writable, e configurare l' TransactionContext.

  2. Verifica i precompile. Se il programma è un precompile, il runtime chiama process_precompile(), che comunque inserisce ed estrae un frame dello stack (tramite push() e pop()) ma bypassa la VM sBPF e la ricerca nella cache dei programmi, eseguendo il codice nativo direttamente.

  3. Inserisce uno stack frame. (I passaggi 3-6 avvengono all'interno di InvokeContext::process_instruction() e process_executable_chain(), chiamati da process_message().) Chiama push() su InvokeContext, che incrementa l'altezza dello stack delle istruzioni e applica la regola di rientranza: un programma può rientrare in se stesso solo se il chiamante immediato (il programma attualmente in cima allo stack delle istruzioni) è lo stesso programma. La ricorsione profonda su se stesso (A -> A -> A) è consentita, soggetta ai limiti di profondità dello stack. Altri pattern di rientranza (ad esempio, A chiama B che chiama A) restituiscono InstructionError::ReentrancyNotAllowed.

  4. Risolve il programma. Il runtime chiama process_executable_chain() che determina il loader. Se il proprietario del program account è il native loader, il programma è un builtin e la sua funzione entrypoint viene cercata direttamente dal ProgramCacheForTxBatch. Se il proprietario è uno dei BPF loader (bpf_loader_deprecated, bpf_loader, bpf_loader_upgradeable, o loader_v4), viene invece invocato l'entrypoint builtin del loader stesso.

  5. Esegue il programma BPF. Per i programmi BPF, l' entrypoint del loader cerca l'eseguibile compilato dalla cache dei programmi. La funzione execute() quindi:

    • Serializza i dati dell'account in un buffer di parametri flat
    • Crea la VM sBPF con stack, heap e regioni di memoria
    • Esegue il codice compilato, consumando compute unit durante l'esecuzione. Restituisce ComputationalBudgetExceeded se il budget viene superato.
    • Deserializza i dati dell'account dal buffer riportandoli nello stato dell'account
  6. Rimuove lo stack frame. Chiama pop() che verifica che l'istruzione non abbia violato le regole di contabilità del runtime (i saldi in lamport sono bilanciati, gli account readonly non sono stati modificati, le dimensioni dei dati degli account rientrano nei limiti).

  7. Accumula le compute unit. Le compute unit consumate dall'istruzione vengono aggiunte al totale della transazione tramite saturating_add.

Cache dei programmi

Il runtime mantiene una ProgramCache globale che memorizza i programmi verificati e compilati. È consapevole del fork-graph e gestisce le regole di visibilità del deployment, l'eviction e la ricompilazione ai confini delle epoch.

Tipi di entry della cache

Ogni programma in cache ha un ProgramCacheEntryType che determina il suo comportamento a runtime:

TipoDescrizione
LoadedProgramma verificato e compilato, pronto per l'esecuzione.
BuiltinProgramma nativo compilato nel binario del validator (System, Stake, Vote, ecc.). Non memorizzato on-chain.
UnloadedProgramma precedentemente verificato il cui eseguibile compilato è stato rimosso dalla memoria per liberare spazio. Continua a tracciare le statistiche di utilizzo. Può essere ricaricato senza ri-verifica.
FailedVerificationTombstone per programmi che non hanno superato il verificatore sBPF con il set di feature corrente. Può diventare Loaded se le attivazioni delle feature modificano le regole di verifica.
ClosedTombstone per programmi che sono stati esplicitamente chiusi o mai deployati. Utilizzato anche per account (come i buffer account) che appartengono a un loader ma non contengono codice eseguibile.
DelayVisibilityTombstone sintetico restituito da ProgramCacheForTxBatch::find() quando esiste un'entry Loaded ma non è ancora effettiva (il suo effective_slot è nel futuro). Mai memorizzato direttamente nella cache.

Ritardo di visibilità

I programmi appena deployati o aggiornati non sono effettivi immediatamente. La costante DELAY_VISIBILITY_SLOT_OFFSET è 1, il che significa che un programma deployato nello slot N diventa effettivo nello slot N+1. Durante lo slot di deployment, qualsiasi tentativo di invocare la nuova versione restituisce DelayVisibility, causando la segnalazione da parte del runtime di "Program is not deployed."

Politica di rimozione

La cache contiene fino a MAX_LOADED_ENTRY_COUNT (512) voci di programmi compilati. Quando viene raggiunto il limite, i programmi meno utilizzati vengono rimossi allo stato Unloaded. L'utilizzo è tracciato da tx_usage_counter (incrementato ogni volta che una transazione fa riferimento al programma) e latest_access_slot.

Ricompilazione al confine dell'epoch

Se l'attivazione di una funzionalità modifica l' ProgramRuntimeEnvironments al confine di un epoch, tutti i programmi in cache vengono ricompilati contro il nuovo ambiente.

Dati di ritorno

I programmi possono impostare dati di ritorno tramite la syscall sol_set_return_data. I dati sono memorizzati in una struttura TransactionReturnData a livello di transazione che contiene i byte dei dati e il program_id del programma la cui istruzione ha chiamato la syscall. La dimensione massima è di 1.024 byte (MAX_RETURN_DATA).

Is this page helpful?

Indice dei contenuti

Modifica pagina

Gestito da

© 2026 Solana Foundation.
Tutti i diritti riservati.
Resta connesso