Samenvatting
Transacties doorlopen 8 fasen: ontvangen, sigverify, sanitize, budget/leeftijdscontroles, validatie van de fee payer, laden van accounts, uitvoering van instructies en commit.
Transactieverwerkingspijplijn
Wanneer een transactie bij een validator aankomt, doorloopt deze een reeks validatie- en uitvoeringsfasen. Het volgende beschrijft de volledige pijplijn van ontvangst tot commit, met verwijzingen naar bronbestanden in de agave validator-client.
1. Ontvangen en deserialiseren
De validator ontvangt transactiebytes via UDP/QUIC. De ruwe bytes moeten binnen
één enkel pakket passen (PACKET_DATA_SIZE = 1.232 bytes). De bytes worden
gedeserialiseerd naar een VersionedTransaction, die de handtekeningenarray
en een VersionedMessage (legacy of v0) bevat.
2. Handtekeningverificatie (sigverify)
Handtekeningen worden geverifieerd in de
sigverify-fase
voordat de transactie de banking-fase ingaat. Voor elke handtekening op index
i controleert de verifier Ed25519(signatures[i], account_keys[i],
message_bytes). Als een handtekening ongeldig is, wordt het pakket verwijderd.
Verificatie wordt geparallelliseerd: de validator splitst pakketbatches in
chunks van
VERIFY_PACKET_CHUNK_SIZE
(128) en verwerkt deze parallel.
3. Sanitize
De gedeserialiseerde transactie wordt gesanitized om een
SanitizedTransaction (of
RuntimeTransaction)
te produceren. Sanitization valideert structurele invarianten:
- Aantal handtekeningen komt overeen met
num_required_signaturesin de header - Alle instructie
program_id_indexenaccount_indicesvallen binnen de grenzen - De fee payer (accountindex 0) is een schrijfbare ondertekenaar
De RuntimeTransaction wrapper cachet vooraf berekende metadata van
TransactionMeta:
de berichthash, vote-transactievlag, precompile-handtekeningaantallen
(Ed25519/secp256k1/secp256r1), compute budget-instructiedetails en totale
instructiedatalengte.
4. Controleer compute budget, leeftijd en statuscache
De
check_transactions
methode voert verschillende controles per transactie uit:
Compute budget: De compute budget-instructies van de transactie worden eerst
geparseerd en gevalideerd. Kostendetails worden berekend op basis van de
budgetlimieten en prioriteringskosten. Als het compute budget ongeldig of
tegenstrijdig is, mislukt de transactie met compute-budget parsefouten zoals
DuplicateInstruction, InstructionError(..., InvalidInstructionData), of
InvalidLoadedAccountsDataSizeLimit.
Blockhash-leeftijd: De recent_blockhash van de transactie wordt opgezocht
in de
BlockhashQueue.
Als de hash wordt gevonden en de leeftijd binnen MAX_PROCESSING_AGE (150
slots) valt, gaat de transactie door. Indien niet gevonden, controleert de
validator op een geldige
durable nonce.
Statuscache: De message hash van de transactie wordt gecontroleerd tegen een
statuscache. Indien gevonden, wordt de transactie afgewezen met
AlreadyProcessed.
5. Valideer nonce en fee payer
De
validate_transaction_nonce_and_fee_payer
methode in de SVM behandelt twee validaties:
Nonce-validatie (indien van toepassing): Voor nonce-transacties laadt de validator het nonce-account en verifieert:
- Het account is eigendom van het System Program
- Het parseert als
State::Initialized - De opgeslagen durable nonce komt overeen met de
recent_blockhashvan de transactie - De nonce kan worden verhoogd (de huidige durable nonce verschilt van de volgende durable nonce, d.w.z. de nonce is nog niet gebruikt in het huidige blok)
- De nonce-autoriteit heeft de transactie ondertekend
Indien geldig, wordt de nonce verhoogd naar de volgende durable nonce-waarde.
Zie
validate_transaction_nonce.
Fee payer-validatie: Het fee payer-account (altijd index 0) wordt geladen en
gecontroleerd door
validate_fee_payer:
- Account moet bestaan (lamports > 0), anders
AccountNotFound - Account moet een systeemaccount of nonce-account zijn, anders
InvalidAccountForFee - Lamports moeten
min_balance + total_feedekken, waarbijmin_balance0 is voor systeemaccounts ofrent.minimum_balance(NonceState::size())voor nonce- accounts; andersInsufficientFundsForFee - Na aftrek van de kosten moet het account rent-exempt blijven (kan niet overgaan van rent-exempt naar rent-paying)
De vergoeding wordt in deze fase afgetrokken van de vergoedingsbetaler. Een
momentopname van de vergoedingsbetaler na aftrek van de vergoeding (en
geavanceerde nonce, indien van toepassing) wordt opgeslagen als
RollbackAccounts, dit zijn de accounts die worden vastgelegd zelfs als de
uitvoering mislukt.
6. Accounts laden
load_transaction
laadt alle accounts waarnaar de transactie verwijst. De
AccountLoader
verpakt de externe accountopslag en onderhoudt een batch-lokale cache zodat
accounts die zijn gewijzigd door eerdere transacties in dezelfde batch zichtbaar
zijn voor latere transacties.
Voor elk account dat geen vergoedingsbetaler is, doet de loader het volgende:
- Haalt het account op uit de cache of accounts-db
- Werkt de huurvrijstellingsstatus bij indien nodig
- Accumuleert de gegevensgrootte van het account naar de
loaded_accounts_data_size_limit(standaard 64 MiB). Elk account brengt een basis-overhead met zich mee vanTRANSACTION_ACCOUNT_BASE_SIZE(64 bytes) plus de lengte van de gegevens
Voor elk programma dat wordt aangeroepen door de instructies van de transactie,
verifieert de loader dat het program account bestaat en eigendom is van een
geldige loader (NativeLoader of een van de PROGRAM_OWNERS). Ongeldige
programma's mislukken met ProgramAccountNotFound of
InvalidProgramForExecution.
LoaderV3 (upgradeable) programma's laden impliciet hun bijbehorende programdata account, wat ook meetelt voor de limiet van geladen gegevensgrootte.
Als het laden van accounts mislukt maar de vergoedingsbetaler succesvol is
gevalideerd, wordt de transactie een
FeesOnly
resultaat: de vergoeding wordt nog steeds geïnd maar er worden geen instructies
uitgevoerd.
7. Instructies uitvoeren
execute_loaded_transaction
creëert een TransactionContext met alle geladen accounts en roept
process_message
aan. Instructies worden sequentieel uitgevoerd in de volgorde waarin ze in het
bericht verschijnen. Elke instructie-aanroep creëert een InvokeContext en
roept het doelprogramma aan.
Details van instructieverwerking
De
process_message
functie van de runtime itereert door elke instructie en roept het doelprogramma
aan:
- Voor elke instructie roept de runtime
prepare_next_top_level_instructionaan, die deInstructionContextopbouwt. Deze context bevat verwijzingen naar de accounts van de instructie (opgelost uit de gecompileerde indices), de instruction data en de program account index. - De runtime controleert of het programma een precompile is (Ed25519, Secp256k1, Secp256r1). Precompiles worden direct geverifieerd zonder de BPF VM aan te roepen.
- Voor alle andere programma's roept de runtime
process_instructionaan, die het programma uit de cache laadt en uitvoert in de BPF virtual machine. - Nadat de instructie is voltooid,
verifieert
de runtime dat het totale lamport-saldo over alle instruction accounts niet
is veranderd (
UnbalancedInstruction-controle). - Als een instructie mislukt, wordt de gehele transactie teruggedraaid. Geen tussentijdse statuswijzigingen worden vastgelegd.
Elke instructie verhoogt de instruction trace. De trace bevat zowel top-level
instructies als alle CPI's die ze aanroepen. De totale
trace-lengte (top-level instructies plus alle geneste CPI's) mag niet groter
zijn dan 64 (MAX_INSTRUCTION_TRACE_LENGTH). Het overschrijden van deze
limiet retourneert InstructionError::MaxInstructionTraceLengthExceeded.
Na uitvoering verifieert de runtime dat:
- De som van lamports over alle accounts niet is veranderd
- Geen enkel account is overgegaan van rent-exempt naar rent-paying
8. Vastleggen of terugdraaien
Als de uitvoering slaagt, worden de gewijzigde accountstatussen uit de
TransactionContext teruggeschreven naar de batch-lokale cache van de
AccountLoader. Als de uitvoering mislukt, worden alleen de
RollbackAccounts (fee payer met ingehouden fee en gevorderde nonce)
teruggeschreven. De fee wordt nog steeds geïnd, maar alle andere
accountwijzigingen worden verworpen.
Pijplijn-overzicht
Receive packet (UDP/QUIC)--> Deserialize into VersionedTransaction--> Sigverify (parallel Ed25519 verification)--> Sanitize (structural validation, metadata extraction)--> Parse compute budget, calculate fees--> Check blockhash age (or verify nonce account)--> Check status cache (dedup)--> Validate nonce authority and advanceability (if nonce transaction)--> Validate fee payer (load, check balance, deduct fee)--> Load all accounts (with data size limits)--> Load programs (verify loaders)--> Execute instructions sequentially--> Verify post-conditions (lamport balance, rent state)--> Commit account changes (or rollback on failure)
Transactiefout-referentie
De volgende tabel toont alle
TransactionError-varianten
en in welke pijplijnfase ze optreden:
| Fout | Fase | Oorzaak |
|---|---|---|
AccountInUse | Scheduling | Account is al vergrendeld door een andere transactie in dezelfde batch |
AccountLoadedTwice | Scheduling | Een pubkey verschijnt twee keer in de account_keys van de transactie |
AccountNotFound | Fee payer validatie | Fee payer account bestaat niet |
ProgramAccountNotFound | Account laden | Een aangeroepen programma bestaat niet |
InsufficientFundsForFee | Fee payer validatie | Fee payer kan fee + rent-exempt minimum niet dekken |
InvalidAccountForFee | Fee payer validatie | Fee payer is geen system of nonce account |
AlreadyProcessed | Status cache | Transactie is al verwerkt |
BlockhashNotFound | Leeftijdscontrole | Blockhash niet in wachtrij en geen geldige nonce |
InstructionError | Uitvoering | Er is een fout opgetreden tijdens het verwerken van een instructie (bevat instructie-index en specifieke InstructionError) |
CallChainTooDeep | Account laden | Loader call chain is te diep |
MissingSignatureForFee | Sanitize | Transactie vereist een fee maar heeft geen handtekening |
InvalidAccountIndex | Sanitize | Transactie bevat een ongeldige accountreferentie |
SignatureFailure | Sigverify | Ed25519-handtekening kan niet worden geverifieerd (pakket wordt verwijderd) |
InvalidProgramForExecution | Account laden | Programma is niet eigendom van een geldige loader |
SanitizeFailure | Sanitize | Transactie kon accounts offsets niet correct sanitizen |
ClusterMaintenance | Scheduling | Transacties zijn momenteel uitgeschakeld vanwege clusteronderhoud |
AccountBorrowOutstanding | Uitvoering | Transactieverwerking heeft een account achtergelaten met een openstaande geleende referentie |
WouldExceedMaxBlockCostLimit | Scheduling | Transactie zou de maximale blokkostenlimiet overschrijden |
UnsupportedVersion | Sanitize | Transactieversie wordt niet ondersteund |
InvalidWritableAccount | Account laden | Transactie laadt een schrijfbaar account dat niet kan worden geschreven |
WouldExceedMaxAccountCostLimit | Scheduling | Transactie zou de maximale accountkostenlimiet binnen het blok overschrijden |
WouldExceedAccountDataBlockLimit | Scheduling | Transactie zou de accountdatalimiet binnen het blok overschrijden |
TooManyAccountLocks | Scheduling | Transactie heeft te veel accounts vergrendeld |
AddressLookupTableNotFound | Account laden | Address lookup table account bestaat niet |
InvalidAddressLookupTableOwner | Account laden | Address lookup table is eigendom van het verkeerde programma |
InvalidAddressLookupTableData | Account laden | Address lookup table bevat ongeldige data |
InvalidAddressLookupTableIndex | Account laden | Address table lookup gebruikt een ongeldige index |
InvalidRentPayingAccount | Post-execution check | Account is overgegaan van rent-exempt naar rent-paying |
WouldExceedMaxVoteCostLimit | Scheduling | Transactie zou de maximale vote kostenlimiet overschrijden |
WouldExceedAccountDataTotalLimit | Scheduling | Transactie zou de totale accountdatalimiet overschrijden |
DuplicateInstruction | Compute budget parsing | Dubbele compute budget instructievariant in dezelfde transactie |
InsufficientFundsForRent | Post-execution check | Account heeft niet genoeg lamports om rent voor zijn datagrootte te dekken |
MaxLoadedAccountsDataSizeExceeded | Account laden | Totaal geladen data overschrijdt 64 MiB limiet |
InvalidLoadedAccountsDataSizeLimit | Compute budget parsing | SetLoadedAccountsDataSizeLimit ingesteld op 0 |
ResanitizationNeeded | Sanitize | Transactie verschilde voor/na feature-activatie en vereist hersanitisatie |
ProgramExecutionTemporarilyRestricted | Account laden | Programma-uitvoering is tijdelijk beperkt op het gerefereerde account |
UnbalancedTransaction | Post-execution check | Totaal lamport-saldo voor de transactie is niet gelijk aan het saldo erna |
ProgramCacheHitMaxLimit | Account laden | Programma-cache heeft maximale limiet bereikt |
CommitCancelled | Commit | Commit intern geannuleerd |
Is this page helpful?