Versioned transactions

Samenvatting

Solana heeft drie transactieformaten: legacy, v0 en v1. v0 voegt Address Lookup Tables (ALTs) toe voor het verwijzen naar accounts via 1-byte-indices. v1 verhoogt de groottelimiet naar 4.096 bytes, verplaatst resourcelimieten naar het bericht zelf en verwijdert ALTs.

Solana ondersteunt drie transactieformaten: legacy, v0 en v1. Elk formaat wordt hieronder beschreven aan de hand van dezelfde drie onderdelen: hoe de bytes op de wire worden ingedeeld, hoe accounts worden gerefereerd en waar de resourcelimieten vandaan komen.

v1-activeringsstatus

Het v1-formaat is nog niet actief op enig cluster. Activering is gepland met Agave v4.2. solana-test-validator 4.2+ stelt je in staat v1-transacties lokaal te testen. Bestaande apps dienen voorbereiden op v1 te bekijken.

Formaatoverzicht

Limietlegacyv0v1
Max. transactiegrootte1.232 bytes1.232 bytes4.096 bytes
Accountadressen~32, groottegebonden64, via lookup-tabellen64, inline
Address lookup-tabellenniet ondersteundondersteundniet ondersteund
ResourcelimietenComputeBudget-instructiesComputeBudget-instructiesberichtconfiguratie

Ga naar: Legacy · v0 · v1

Legacy-formaat

Het originele formaat, en nog steeds de standaard in de meeste tooling. Het heeft helemaal geen versieprefix: de eerste byte van de transactie is de compact-u16-teller van de handtekeningenarray, en de eerste byte van het bericht is num_required_signatures, waarvan het hoogste bit altijd niet is ingesteld.

Legacy wire-indeling

VeldGrootteBeschrijving
num_signaturescompact-u16Aantal handtekeningen
signaturesnum_signatures x 64 bytesEd25519-handtekeningen
header3 bytesMessageHeader — eerste byte heeft versiebit niet ingesteld
num_account_keyscompact-u16Aantal accountsleutels
account_keysnum_account_keys x 32 bytesPublieke sleutels, allemaal inline
recent_blockhash32 bytesLevensduurspecificatie
num_instructionscompact-u16Aantal instructies
instructionsvariabelElke instructie aaneengesloten geserialiseerd

Elke array met variabele lengte wordt voorafgegaan door een compact-u16-lengte: 1 byte voor waarden 0–127, 2–3 bytes voor grotere waarden. Zie voor de indeling per instructie en een uitgewerkte grootteberekening binair transactieformaat.

Accounts in legacy

Elk account wordt als volledige 32-byte publieke sleutel in account_keys opgeschreven, en instructies verwijzen ernaar via een 1-byte-index in die array. Er is geen manier om te verwijzen naar een account dat niet expliciet in de transactie is opgenomen, wat bewerkstelligt dat een legacy-transactie beperkt blijft tot ongeveer 32 accounts voordat de 1.232 bytes zijn opgebruikt.

Resourcelimieten in legacy

De limiet voor rekeneenheden, de datalimiet voor geladen accounts, de heapgrootte en de prioriteitstoeslag worden allemaal aangevraagd door ComputeBudget-programma-instructies in de transactie op te nemen. Elk kost een instructie-slot en 150 rekeneenheden. Weglaten is veilig: de runtime valt terug op standaardwaarden van 200.000 CU per instructie (maximaal 1,4M), een datalimiet van 64 MiB, een heap van 32 KiB en een prioriteitstoeslag van nul.

V0-formaat

v0 is een legacy-bericht plus twee zaken: een versieprefix-byte 0x80 en een address_table_lookups-array die na de instructies wordt toegevoegd. Alles daarvoor is byte-identiek aan legacy.

V0-wire-indeling

VeldGrootteBeschrijving
num_signaturescompact-u16Aantal handtekeningen
signaturesnum_signatures x 64 bytesEd25519-handtekeningen
0x801 byteVersieprefix-byte — eerste byte van het bericht
header3 bytesMessageHeader (hetzelfde als legacy)
num_account_keyscompact-u16Aantal statische accountsleutels
static_account_keysnum_account_keys x 32 bytesSleutels die letterlijk in de transactie verschijnen
recent_blockhash32 bytesLevensduurspecificatie
num_instructionscompact-u16Aantal instructies
instructionsvariabelHetzelfde formaat als legacy
address_table_lookupscompact-u16 + variabelALT-referenties (zie hieronder)

Elke adrestabel-opzoekvermelding bevat:

VeldGrootteBeschrijving
account_key32 bytesDe publieke sleutel van het ALT-account
writable_indexescompact-u16 + N x 1 byteIndices in de ALT voor schrijfbare accounts
readonly_indexescompact-u16 + N x 1 byteIndices in de ALT voor alleen-lezen accounts

Address lookup-tabellen

Een ALT is een onchain-account dat tot 256 publieke sleutels opslaat. Door naar een ALT te verwijzen, kan een transactie aanvullende accounts opnemen met behulp van 1-byte indices in plaats van 32-byte publieke sleutels, waardoor de overhead per account aanzienlijk wordt verminderd.

Tijdens runtime, voordat de uitvoering begint, lost de validator alle ALT-verwijzingen op naar volledige publieke sleutels. De opgeloste adressen worden toegevoegd aan de statische account sleutels om de volledige lijst met accountsleutels te vormen. ALT-opgeloste accounts volgen dezelfde volgorde als statische accounts: schrijfbare opzoekingen komen vóór alleen-lezen opzoekingen.

Adrestabel-opzoektabellen beïnvloeden alleen hoe accounts worden gerefereerd in de on-wire transactie. Tijdens uitvoering lost de runtime alle indices op naar volledige accountadressen. ALT-opgeloste accounts kunnen alleen schrijfbaar of alleen-lezen (niet-ondertekenaar) zijn; ze kunnen geen ondertekenaars zijn.

Resourcelimieten in v0

Ongewijzigd ten opzichte van legacy: ComputeBudget-instructies, met dezelfde standaardwaarden wanneer ze worden weggelaten.

V1-formaat

v1 verhoogt de groottelimiet naar 4.096 bytes en herstructureert het bericht rond een transactieconfiguratie: resourcelimieten verhuizen uit ComputeBudget-instructies naar velden op vaste posities in het bericht zelf. Hierdoor kan het netwerk een transactie rangschikken op prioriteitstoeslag met één read op een vast offset, in plaats van de instructielijst te scannen en te deserialiseren.

V1-wire-indeling

VeldGrootteBeschrijving
0x811 byteVersieprefix-byte — de eerste byte van de transactie
header3 bytesMessageHeader (zelfde als legacy)
config_mask4 bytesu32 LE-bitmasker dat aangeeft welke configuratiewaarden aanwezig zijn
recent_blockhash32 bytesLevensduurspecificatie
num_instructions1 byteTeller met vaste breedte, max. 64
num_addresses1 byteTeller met vaste breedte, max. 64
addressesN x 32 bytesAccountadressen, allemaal inline — geen lookup-tabelverwijzingen
config_values0–20 bytesÉén waarde per ingesteld maskerbit, in bitvolgorde (zie hieronder)
instruction_headersN x 4 bytesPer instructie: program_id_index (u8), num_accounts (u8), data_len (u16 LE)
instruction_payloadsvariabelPer instructie: accountindices, dan instruction data
signaturesN x 64 bytesAan het einde, zonder lengteprefix — de teller komt uit de header

Twee structurele verschillen ten opzichte van legacy en v0 zijn het vermelden waard bij het schrijven van een decoder. De tellers zijn u8-velden met vaste breedte in plaats van compact-u16, en de instructies zijn opgesplitst in twee reeksen: eerst alle headers met vaste grootte, dan alle payloads met variabele lengte, in plaats van elke instructie aaneengesloten.

Accounts in v1: geen address lookup-tabellen

v1 verwijdert ALT-ondersteuning bewust. 64 ruwe adressen is 2.048 bytes, ruimschoots binnen de limiet van 4.096 bytes, dus elk adres is inline zoals in legacy. Als je applicatie afhankelijk is van lookup-tabellen, betekent overstappen naar v1 dat je die adressen inline moet opnemen.

Resourcelimieten in v1: de transactieconfiguratie

De configuratie is een u32-bitmasker gevolgd door waarden met vaste breedte voor elk veld waarvan het bit is ingesteld:

Bit(s)VeldBreedteOpmerkingen
0–1Prioriteitstoeslagu64Totaal lamports — beide bits samen ingesteld
2Limiet voor rekeneenhedenu32
3Datalimiet voor geladen accountsu32
4Gevraagde heapgrootteu32

Onbekende bits worden afgewezen. Omdat het bericht ondertekend is, kunnen niet-herkende configuratievelden niet stilzwijgend worden weggelaten.

Prioriteitstoeslag is totaal in lamports, geen prijs

In legacy en v0 wordt de prioriteitstoeslag ingesteld via SetComputeUnitPrice als micro-lamports per rekeneenheid, vermenigvuldigd met de limiet voor rekeneenheden. In v1 is het een absoluut totaal in lamports — geen vermenigvuldiging, geen afronding. Gebruik de per-CU-rekenwijze niet over. De totale toeslagformule blijft verder ongewijzigd: (signatures × lamports_per_signature) + priority_fee.

ComputeBudget-instructies zijn no-ops in v1

Een v1-transactie wijst ComputeBudget-instructies niet af — ze worden genegeerd voor configuratie. Ze worden nog steeds uitgevoerd als succesvolle no-ops, verbruiken 150 rekeneenheden en één van de 64 instructie-slots, zonder enig effect op het budget. Verwijder ze bij het bouwen van v1-transacties en stop met het scannen ernaar bij het lezen van v1-transacties: de waarden staan in de berichtconfiguratie.

Configuratievelden moeten expliciet worden ingesteld

De belangrijkste gedragswijziging voor verzenders: in tegenstelling tot legacy en v0 moeten v1-transacties de limiet voor rekeneenheden en de datalimiet voor geladen accounts expliciet instellen, anders mislukt je transactie.

Niet-ingesteld veldlegacy / v0v1Gevolg bij weglaten
Limiet voor rekeneenheden200k per instructie, max. 1,4M0 CUMislukt onmiddellijk, budget uitgeput
Datagrootte geladen accounts64 MiB0 bytesMaxLoadedAccountsDataSizeExceeded bij het eerste geladen account
Prioriteitstoeslag00
Heapgrootte32 KiB32 KiB

De aanbevolen aanpak is om eenmalig te simuleren met beide limieten gemaximaliseerd, vervolgens de teruggegeven unitsConsumed en loadedAccountsDataSize terug te schrijven naar de configuratie, waarbij de datagrootte naar boven wordt afgerond naar de volgende 32 KiB-pagina voor marge (het blokkostenmodel rekent in 32 KiB-pagina's, dus marge onder de volgende paginagrens is gratis).

Voorbereiden op v1

v1 verandert het lezen van transacties, niet alleen het verzenden ervan. Wanneer v1 actief wordt, zal elke client die getTransaction of getBlock aanroept zonder in te schrijven falen op v1-transacties:

  • Geef maxSupportedTransactionVersion: 1 door — het JSON-geheel getal 1, niet de string "1" — aan getTransaction en getBlock. 0 doorgeven mislukt op v1-transacties net als het weglaten van de parameter, dus een codebase die tijdens de v0- uitrol is bijgewerkt, moet de waarde alsnog wijzigen.
  • getTransaction mislukt bij een v1-transactie met fout -32015, en één v1- transactie laat een volledige getBlock-respons mislukken met dezelfde fout — er is geen gedeeltelijk resultaat.
  • blockSubscribe geeft block: null terug en stopt met vooruitgaan, zodat een consumer die dit als een leeg blok leest stilzwijgend achteropraakt vanaf de eerste v1-slot.
  • getSignaturesForAddress inspecteert nooit transactie-inhoud, dus v1-handtekeningen worden normaal weergegeven.
  • Ingeschreven responses bevatten een transactionConfig-object in het bericht voor v1- transacties (volledig afwezig voor legacy en v0). Pipelines die prioriteitstoeslagen of limieten voor rekeneenheden afleiden door te scannen op ComputeBudget-instructies rapporteren stilzwijgend nul voor elke v1-transactie.
  • Gebruik encoding: 'base64' wanneer je transacties aan clientzijde decodeert, en voor sendTransaction/simulateTransaction met transacties groter dan 1.232 bytes — base58-codering blijft beperkt tot de oude grootte.
  • Ondersteuning voor clientbibliotheken vereist recente versies: @solana/kit 8.0+, Agave 4.2.x-generatie Rust-crates, of web3.js v3. web3.js v1 leest v1 vanaf 1.99.0 en hoger, maar kan het niet bouwen of verzenden.

Voor de volledige migratiegids — inclusief ondersteuning voor clientbibliotheken, streaming (Geyser/gRPC) versiedetectie en simulatiegedrag — zie de upgradepagina voor transactieformaat v1.

Is this page helpful?

© 2026 Solana Foundation. Alle rechten voorbehouden.