Samenvatting
Programma's worden via LLVM gecompileerd naar sBPF en draaien in een sandbox-VM met een budget van 1,4M CU per transactie. De runtime slaat tot 512 gecompileerde programma's op in de cache, biedt syscalls voor logging, CPI, crypto en geheugen, en vertraagt nieuwe implementaties met 1 slot.
Compilatie
Solana gebruikt LLVM om programma's te compileren naar ELF-binaries die het Solana Bytecode Format (sBPF) bevatten. Het ELF-binary wordt onchain opgeslagen in een uitvoerbaar account.
sBPF is Solana's aangepaste variant van eBPF-bytecode, afgestemd op de Solana-runtime. Het is geen standaard eBPF en bevat Solana-specifieke aanpassingen.
Programma's schrijven
Solana-programma's worden voornamelijk geschreven in Rust via een van de drie benaderingen:
Anchor
Een framework dat Rust-macro's gebruikt om boilerplate te verminderen. Aanbevolen voor de meeste ontwikkelaars.
Pinocchio
Een lichtgewicht, zero-copy Rust-bibliotheek geoptimaliseerd voor rekenverbruik en binaire omvang. Bevat programma-specifieke crates voor veelgebruikte CPI's.
Native Rust
Directe Rust zonder frameworks. Biedt volledige controle, maar vereist meer handmatige implementatie.
Zie Cross-Program Invocations voor CPI-concepten en voorbeelden die van toepassing zijn op al deze benaderingen.
Programma-uitvoeringsmodel
Wanneer een transactie wordt verwerkt, voert de runtime elke instructie
sequentieel uit via
process_message().
Voor elke instructie doet de runtime het volgende:
-
Bereidt de instructiecontext voor. Roept
prepare_next_top_level_instruction()aan om de accountindices van de instructie te mappen, ondertekenaar- en schrijfbare vlaggen in te stellen, en deTransactionContextte configureren. -
Controleert precompiles. Als het programma een precompile is, roept de runtime
process_precompile()aan, wat nog steeds een stackframe plaatst en verwijdert (viapush()enpop()) maar de sBPF VM en de zoekopdracht in de programma-cache omzeilt en native code direct uitvoert. -
Plaatst een stackframe. (Stappen 3-6 vinden plaats binnen
InvokeContext::process_instruction()enprocess_executable_chain(), aangeroepen vanuitprocess_message().) Roeptpush()aan opInvokeContext, wat de hoogte van de instructiestack verhoogt en de herintrede-regel handhaaft: een programma mag zichzelf alleen opnieuw betreden als de directe aanroeper (het programma bovenaan de instructiestack) hetzelfde programma is. Diepe zelfrecursie (A -> A -> A) is toegestaan, afhankelijk van de stackdieptelimieten. Andere hrintrede-patronen (bijv. A roept B aan, B roept A aan) retournerenInstructionError::ReentrancyNotAllowed. -
Bepaalt het programma. De runtime roept
process_executable_chain()aan, wat de loader bepaalt. Als de eigenaar van het program account de native loader is, is het programma een builtin en wordt de entrypoint-functie direct opgezocht in deProgramCacheForTxBatch. Als de eigenaar een van de BPF-loaders is (bpf_loader_deprecated,bpf_loader,bpf_loader_upgradeableofloader_v4), wordt in plaats daarvan de eigen builtin-entrypoint van de loader aangeroepen. -
Voert het BPF-programma uit. Voor BPF-programma's zoekt het loader-entrypoint het gecompileerde uitvoerbare bestand op in de programma-cache. De
execute()-functie doet vervolgens het volgende:- Serialiseert accountgegevens naar een platte parameterbuffer
- Maakt de sBPF VM aan met stack, heap en geheugenregio's
- Voert de gecompileerde code uit en verbruikt daarbij compute units. Retourneert
ComputationalBudgetExceededals het budget wordt overschreden. - Deserialiseert accountgegevens van de buffer terug naar de accountstatus
-
Verwijdert het stackframe. Roept
pop()aan, wat verifieert dat de instructie de boekhoudregel van de runtime niet heeft geschonden (lamport-saldi zijn in evenwicht, alleen-lezen accounts zijn niet gewijzigd, de omvang van accountgegevens valt binnen de limieten). -
Accumuleert compute units. De door de instructie verbruikte compute units worden via
saturating_addopgeteld bij het transactietotaal.
Programma-cache
De runtime onderhoudt een globale
ProgramCache
die geverifieerde en gecompileerde programma's opslaat. De cache is fork-graph-bewust en verwerkt
regels voor implementatiezichtbaarheid, verwijdering en hercompilatie bij epoch-grenzen.
Cachegegevenstypen
Elk gecached programma heeft een
ProgramCacheEntryType
die het runtimegedrag bepaalt:
| Type | Beschrijving |
|---|---|
Loaded | Geverifieerd en gecompileerd programma, klaar voor uitvoering. |
Builtin | Natief programma gecompileerd in het validator-binary (System, Stake, Vote, enz.). Niet onchain opgeslagen. |
Unloaded | Eerder geverifieerd programma waarvan het gecompileerde uitvoerbare bestand uit het geheugen is verwijderd om ruimte vrij te maken. Houdt nog steeds gebruiksstatistieken bij. Kan opnieuw worden geladen zonder herverificatie. |
FailedVerification | Tombstone voor programma's die de sBPF-verificator niet hebben doorstaan onder de huidige functieset. Kan Loaded worden als feature-activeringen de verificatieregels wijzigen. |
Closed | Tombstone voor programma's die expliciet zijn gesloten of nooit zijn geïmplementeerd. Ook gebruikt voor accounts (zoals bufferaccounts) die tot een loader behoren maar geen uitvoerbare code bevatten. |
DelayVisibility | Synthetische tombstone die wordt geretourneerd door ProgramCacheForTxBatch::find() wanneer een Loaded-vermelding bestaat maar nog niet van kracht is (de effective_slot ligt in de toekomst). Wordt nooit rechtstreeks in de cache opgeslagen. |
Zichtbaarheidsvertraging
Nieuw geïmplementeerde of bijgewerkte programma's zijn niet onmiddellijk van kracht. De
DELAY_VISIBILITY_SLOT_OFFSET-constante
is 1, wat betekent dat een programma dat in slot N wordt geïmplementeerd van kracht wordt in slot
N+1. Tijdens de implementatie-slot retourneert elke poging om de nieuwe versie aan te roepen
DelayVisibility, waardoor de runtime "Program is not deployed." meldt.
Verwijderingsbeleid
De cache bevat maximaal
MAX_LOADED_ENTRY_COUNT
(512) gecompileerde programma-items. Wanneer de limiet is bereikt, worden de minst gebruikte
programma's verwijderd naar de Unloaded-status. Gebruik wordt bijgehouden via
tx_usage_counter
(verhoogd telkens wanneer een transactie naar het programma verwijst) en
latest_access_slot.
Hercompilatie bij epoch-grens
Als een feature-activering de
ProgramRuntimeEnvironments
wijzigt bij een epoch-grens, worden alle gecachede programma's
hergecompileerd
tegen de nieuwe omgeving.
Retourgegevens
Programma's kunnen retourgegevens instellen via de sol_set_return_data-syscall. De gegevens worden
opgeslagen in een transactieniveau-
TransactionReturnData-struct
die de gegevensbytes en de program_id bevat van het programma waarvan de
instructie de syscall heeft aangeroepen. De maximale grootte is 1.024 bytes
(MAX_RETURN_DATA).
Is this page helpful?