Programmausführung

Zusammenfassung

Programme werden über LLVM zu sBPF kompiliert und laufen in einer Sandbox-VM mit einem Budget von 1,4 Mio. CU pro Transaktion. Die Runtime cached bis zu 512 kompilierte Programme, stellt Syscalls für Logging, CPI, Kryptografie und Speicher bereit und verzögert neue Deployments um 1 Slot.

Kompilierung

Solana verwendet LLVM, um Programme in ELF-Binärdateien zu kompilieren, die das Solana Bytecode Format (sBPF) enthalten. Die ELF-Binärdatei wird on-chain in einem ausführbaren Konto gespeichert.

sBPF ist Solanas angepasste Variante des eBPF-Bytecodes, zugeschnitten auf die Solana-Runtime. Es ist kein Standard-eBPF und weist Solana-spezifische Modifikationen auf.

Programme schreiben

Solana-Programme werden hauptsächlich in Rust geschrieben, wobei einer von zwei Ansätzen verwendet wird:

Programmausführungsmodell

Wenn eine Transaktion verarbeitet wird, führt die Runtime jede Instruktion sequenziell über process_message() aus. Für jede Instruktion führt die Runtime folgende Schritte aus:

  1. Bereitet den Instruktionskontext vor. Ruft prepare_next_top_level_instruction() auf, um die Konto-Indizes der Instruktion zuzuordnen, Signer- und Writable-Flags zu setzen und den TransactionContext zu konfigurieren.

  2. Prüft Precompiles. Wenn das Programm ein Precompile ist, ruft die Runtime process_precompile() auf, was immer noch einen Stack-Frame pusht und popt (über push() und pop()), aber die sBPF-VM und das Programm-Cache-Lookup umgeht und nativen Code direkt ausführt.

  3. Schiebt einen Stack-Frame. (Schritte 3-6 erfolgen innerhalb von InvokeContext::process_instruction() und process_executable_chain(), aufgerufen von process_message().) Ruft push() auf InvokeContext auf, was die Höhe des Instruction-Stacks erhöht und die Reentrancy-Regel durchsetzt: Ein Programm darf sich nur dann selbst erneut aufrufen, wenn der unmittelbare Aufrufer (das Programm an der aktuellen Spitze des Instruction-Stacks) dasselbe Programm ist. Tiefe Selbstrekursion (A -> A -> A) ist erlaubt, vorbehaltlich der Stack-Tiefenbeschränkungen. Andere Reentrancy-Muster (z. B. A ruft B auf, B ruft A auf) geben InstructionError::ReentrancyNotAllowed zurück.

  4. Löst das Programm auf. Die Runtime ruft process_executable_chain() auf, was den Loader bestimmt. Wenn der Owner des Program-Kontos der Native Loader ist, handelt es sich bei dem Programm um ein Builtin und seine Entrypoint-Funktion wird direkt aus dem ProgramCacheForTxBatch nachgeschlagen. Wenn der Owner einer der BPF-Loader ist (bpf_loader_deprecated, bpf_loader, bpf_loader_upgradeable oder loader_v4), wird stattdessen der Builtin-Entrypoint des Loaders aufgerufen.

  5. Führt das BPF-Programm aus. Bei BPF-Programmen schlägt der Loader-Entrypoint die kompilierte ausführbare Datei aus dem Programm-Cache nach. Die Funktion execute():

    • Serialisiert Kontodaten in einen flachen Parameter-Buffer
    • Erstellt die sBPF-VM mit Stack-, Heap- und Speicherbereichen
    • Führt den kompilierten Code aus und verbraucht dabei Compute Units. Gibt ComputationalBudgetExceeded zurück, wenn das Budget überschritten wird.
    • Deserialisiert Kontodaten aus dem Buffer zurück in den Kontostatus
  6. Entfernt den Stack-Frame. Ruft pop() auf, was überprüft, dass die Instruktion die Accounting-Regeln der Runtime nicht verletzt hat (Lamport-Guthaben sind ausgeglichen, schreibgeschützte Konten wurden nicht modifiziert, Kontodatengrößen liegen innerhalb der Grenzen).

  7. Akkumuliert Compute Units. Die von der Instruktion verbrauchten Compute Units werden über saturating_add zur Transaktionssumme hinzugefügt.

Programm-Cache

Die Runtime verwaltet einen globalen ProgramCache, der verifizierte und kompilierte Programme speichert. Er ist Fork-Graph-bewusst und verarbeitet Deployment-Sichtbarkeitsregeln, Eviction und Neukompilierung an Epoch-Grenzen.

Cache-Eintragstypen

Jedes gecachte Programm hat einen ProgramCacheEntryType, der sein Laufzeitverhalten bestimmt:

TypBeschreibung
LoadedVerifiziertes und kompiliertes Programm, bereit zur Ausführung.
BuiltinNatives Programm, das in die Validator-Binärdatei kompiliert wurde (System, Stake, Vote usw.). Nicht on-chain gespeichert.
UnloadedZuvor verifiziertes Programm, dessen kompilierte ausführbare Datei aus dem Speicher entfernt wurde, um Platz freizugeben. Verfolgt weiterhin Nutzungsstatistiken. Kann ohne erneute Verifizierung neu geladen werden.
FailedVerificationTombstone für Programme, die den sBPF-Verifier unter dem aktuellen Feature-Set nicht bestanden haben. Kann zu Loaded werden, wenn Feature-Aktivierungen die Verifizierungsregeln ändern.
ClosedTombstone für Programme, die explizit geschlossen oder nie deployed wurden. Wird auch für Accounts (wie Buffer-Accounts) verwendet, die zu einem Loader gehören, aber keinen ausführbaren Code enthalten.
DelayVisibilitySynthetischer Tombstone, der von ProgramCacheForTxBatch::find() zurückgegeben wird, wenn ein Loaded-Eintrag existiert, aber noch nicht wirksam ist (sein effective_slot liegt in der Zukunft). Wird nie direkt im Cache gespeichert.

Sichtbarkeitsverzögerung

Neu deployete oder aktualisierte Programme sind nicht sofort wirksam. Die DELAY_VISIBILITY_SLOT_OFFSET-Konstante beträgt 1, was bedeutet, dass ein in Slot N deployetes Programm in Slot N+1 wirksam wird. Während des Deployment-Slots gibt jeder Versuch, die neue Version aufzurufen, DelayVisibility zurück, wodurch die Runtime "Program is not deployed" meldet.

Eviction-Richtlinie

Der Cache enthält bis zu MAX_LOADED_ENTRY_COUNT (512) kompilierte Programmeinträge. Wenn das Limit erreicht ist, werden die am wenigsten genutzten Programme in den Unloaded-Zustand entfernt. Die Nutzung wird durch tx_usage_counter (wird jedes Mal erhöht, wenn eine Transaktion auf das Programm verweist) und latest_access_slot nachverfolgt.

Neukompilierung an Epoch-Grenzen

Wenn eine Feature-Aktivierung den ProgramRuntimeEnvironments an einer Epoch-Grenze ändert, werden alle gecachten Programme neu kompiliert gegen die neue Umgebung.

Rückgabedaten

Programme können Rückgabedaten über den sol_set_return_data-Syscall setzen. Die Daten werden in einer transaktionsweiten TransactionReturnData-Struktur gespeichert, die die Datenbytes und die program_id des Programms enthält, dessen Instruktion den Syscall aufgerufen hat. Die maximale Größe beträgt 1.024 Bytes (MAX_RETURN_DATA).

Is this page helpful?

Inhaltsverzeichnis

Seite bearbeiten

Verwaltet von

© 2026 Solana Foundation.
Alle Rechte vorbehalten.
Verbinden Sie sich