Transazioni con versione

Riepilogo

Solana dispone di tre formati di transazione: legacy, v0 e v1. v0 aggiunge le Address Lookup Table (ALT) per referenziare gli account tramite indici a 1 byte. v1 porta il limite di dimensione a 4.096 byte, sposta i limiti delle risorse nel messaggio stesso e rimuove le ALT.

Solana supporta tre formati di transazione: legacy, v0 e v1. Ciascuno viene descritto di seguito con le stesse tre parti: come dispone i byte sul canale di trasmissione, come referenzia gli account e da dove derivano i limiti delle risorse.

Stato di attivazione di v1

Il formato v1 non è ancora attivo su nessun cluster. L'attivazione è prevista con Agave v4.2. solana-test-validator 4.2+ consente di testare le transazioni v1 in locale. Le app esistenti dovrebbero consultare la preparazione per v1.

Confronto tra formati

Limitelegacyv0v1
Dimensione massima della transazione1.232 byte1.232 byte4.096 byte
Indirizzi degli account~32, limitato dalla dimensione64, tramite lookup table64, inline
Address lookup tablenon supportatosupportatonon supportato
Limiti delle risorseIstruzioni ComputeBudgetIstruzioni ComputeBudgetmessage config

Vai a: Legacy · v0 · v1

Formato legacy

Il formato originale, ancora predefinito nella maggior parte degli strumenti. Non ha alcun prefisso di versione: il primo byte della transazione è il conteggio compact-u16 dell'array delle firme, e il primo byte del messaggio è num_required_signatures, il cui bit più significativo è sempre non impostato.

Layout wire del formato legacy

CampoDimensioneDescrizione
num_signaturescompact-u16Numero di firme
signaturesnum_signatures x 64 byteFirme Ed25519
header3 byteMessageHeader — il primo byte ha il bit di versione non impostato
num_account_keyscompact-u16Numero di chiavi account
account_keysnum_account_keys x 32 byteChiavi pubbliche, tutte inline
recent_blockhash32 byteSpecificatore di durata
num_instructionscompact-u16Numero di istruzioni
instructionsvariabileOgni istruzione serializzata in modo contiguo

Ogni array a lunghezza variabile è preceduto da una lunghezza compact-u16: 1 byte per valori da 0 a 127, 2–3 byte per valori più grandi. Per il layout per istruzione e un calcolo della dimensione effettivo, vedere il formato binario delle transazioni.

Account nel formato legacy

Ogni account è scritto come una chiave pubblica completa di 32 byte in account_keys, e le istruzioni vi fanno riferimento tramite un indice a 1 byte in quell'array. Non è possibile referenziare un account non esplicitato nella transazione, il che è ciò che limita una transazione legacy a circa 32 account prima di esaurire i 1.232 byte disponibili.

Limiti delle risorse nel formato legacy

Il limite delle unità di calcolo, il limite della dimensione dei dati degli account caricati, la dimensione dell'heap e la commissione di priorità vengono tutti richiesti includendo istruzioni del programma ComputeBudget nella transazione. Ciascuna occupa uno slot istruzione e 150 unità di calcolo. Ometterle è sicuro: il runtime ricade sui valori predefiniti di 200.000 CU per istruzione (con un massimo di 1,4 M), un limite di dimensione dati di 64 MiB, un heap di 32 KiB e una commissione di priorità di zero.

Formato v0

v0 è un messaggio legacy con due aggiunte: un byte prefisso di versione 0x80 e un array address_table_lookups aggiunto dopo le istruzioni. Tutto ciò che precede questi elementi è byte per byte identico al formato legacy.

Layout wire del formato v0

CampoDimensioneDescrizione
num_signaturescompact-u16Numero di firme
signaturesnum_signatures x 64 byteFirme Ed25519
0x801 byteByte prefisso di versione — primo byte del messaggio
header3 byteMessageHeader (uguale al legacy)
num_account_keyscompact-u16Numero di chiavi account statiche
static_account_keysnum_account_keys x 32 byteChiavi che appaiono letteralmente nella transazione
recent_blockhash32 byteSpecificatore di durata
num_instructionscompact-u16Numero di istruzioni
instructionsvariabileStesso formato del legacy
address_table_lookupscompact-u16 + variabileRiferimenti ALT (vedi sotto)

Ogni voce della tabella di ricerca degli indirizzi contiene:

CampoDimensioneDescrizione
account_key32 byteLa chiave pubblica dell'account ALT
writable_indexescompact-u16 + N x 1 byteIndici nell'ALT per gli account scrivibili
readonly_indexescompact-u16 + N x 1 byteIndici nell'ALT per gli account di sola lettura

Address lookup table

Un ALT è un account onchain che memorizza fino a 256 chiavi pubbliche. Facendo riferimento a un ALT, una transazione può includere account aggiuntivi utilizzando indici a 1 byte anziché chiavi pubbliche a 32 byte, riducendo significativamente l'overhead per account.

Durante l'esecuzione, prima che inizi l'elaborazione, il validator risolve tutti i riferimenti ALT in chiavi pubbliche complete. Gli indirizzi risolti vengono aggiunti alle chiavi account statiche per formare l'elenco completo delle chiavi account. Gli account risolti tramite ALT seguono lo stesso ordinamento degli account statici: le ricerche scrivibili precedono quelle di sola lettura.

Le tabelle di ricerca degli indirizzi influenzano solo il modo in cui gli account vengono referenziati nella transazione on-wire. Durante l'esecuzione, il runtime risolve tutti gli indici in indirizzi account completi. Gli account risolti tramite ALT possono essere solo scrivibili o di sola lettura (non firmatari); non possono essere firmatari.

Limiti delle risorse in v0

Invariati rispetto al formato legacy: istruzioni ComputeBudget, con gli stessi valori predefiniti quando vengono omesse.

Formato v1

v1 porta il limite di dimensione a 4.096 byte e ristruttura il messaggio attorno a una transaction config: i limiti delle risorse escono dalle istruzioni ComputeBudget e vengono inseriti in campi a posizione fissa nel messaggio stesso. Questo consente alla rete di classificare una transazione per commissione di priorità con una singola lettura a offset fisso, invece di scansionare e deserializzare l'elenco delle istruzioni.

Layout wire del formato v1

CampoDimensioneDescrizione
0x811 byteByte prefisso di versione — il primo byte della transazione
header3 byteMessageHeader (uguale al formato legacy)
config_mask4 byteBitmask u32 LE che indica quali valori di configurazione sono presenti
recent_blockhash32 byteSpecificatore di durata
num_instructions1 byteConteggio a larghezza fissa, max 64
num_addresses1 byteConteggio a larghezza fissa, max 64
addressesN x 32 byteIndirizzi degli account, tutti inline — nessun riferimento a lookup table
config_values0–20 byteUn valore per ogni bit della maschera impostato, nell'ordine dei bit (vedi sotto)
instruction_headersN x 4 bytePer istruzione: program_id_index (u8), num_accounts (u8), data_len (u16 LE)
instruction_payloadsvariabilePer istruzione: indici degli account, poi instruction data
signaturesN x 64 byteIn coda, senza prefisso di lunghezza — il conteggio proviene dall'header

Due differenze strutturali rispetto ai formati legacy e v0 meritano attenzione durante la scrittura di un decoder. I conteggi sono campi u8 a larghezza fissa anziché compact-u16, e le istruzioni sono suddivise in due sequenze: prima tutti gli header a dimensione fissa, poi tutti i payload a lunghezza variabile, invece di ogni istruzione essere contigua.

Account in v1: nessuna address lookup table

v1 rimuove deliberatamente il supporto per le ALT. 64 indirizzi grezzi occupano 2.048 byte, comodamente entro il limite di 4.096 byte, quindi ogni indirizzo è inline come nel formato legacy. Se la tua applicazione dipende dalle lookup table, il passaggio a v1 comporta l'inserimento inline di quegli indirizzi.

Limiti delle risorse in v1: la transaction config

La configurazione è una bitmask u32 seguita da valori a larghezza fissa per ogni campo il cui bit è impostato:

BitCampoLarghezzaNote
0–1Commissione di prioritàu64lamport totali — entrambi i bit impostati insieme
2Limite unità di calcolou32
3Limite dimensione dati account caricatiu32
4Dimensione heap richiestau32

I bit sconosciuti vengono rifiutati. Poiché il messaggio è firmato, i campi di configurazione non riconosciuti non possono essere eliminati silenziosamente.

La commissione di priorità è in lamport totali, non un prezzo

In legacy e v0, la commissione di priorità viene impostata tramite SetComputeUnitPrice come micro-lamport per unità di calcolo, moltiplicato per il limite di unità di calcolo. In v1 è un totale assoluto in lamport — nessuna moltiplicazione, nessun arrotondamento. Non trasportare l'aritmetica per-CU. La formula della commissione totale rimane invariata: (signatures × lamports_per_signature) + priority_fee.

Le istruzioni ComputeBudget sono no-op in v1

Una transazione v1 non rifiuta le istruzioni ComputeBudget — le ignora ai fini della configurazione. Vengono comunque eseguite come no-op con esito positivo, consumando 150 unità di calcolo e uno dei 64 slot istruzione senza alcun effetto sul budget. Rimuovile quando costruisci transazioni v1 e smetti di scansionarle quando leggi transazioni v1: i valori risiedono nella message config.

I campi di configurazione devono essere impostati esplicitamente

Il cambiamento comportamentale più importante per i mittenti: a differenza di legacy e v0, le transazioni v1 devono impostare esplicitamente il limite di unità di calcolo e il limite della dimensione dei dati degli account caricati, altrimenti la transazione fallirà.

Campo non impostatolegacy / v0v1Sintomo se omesso
Limite unità di calcolo200k per istruzione, max 1,4M0 CUFallisce immediatamente, budget esaurito
Dimensione dati account caricati64 MiB0 byteMaxLoadedAccountsDataSizeExceeded al primo account caricato
Commissione di priorità00
Dimensione heap32 KiB32 KiB

L'approccio consigliato è simulare una volta con entrambi i limiti al massimo, poi scrivere unitsConsumed e loadedAccountsDataSize restituiti nella configurazione, arrotondando la dimensione dei dati alla pagina di 32 KiB successiva per margine di sicurezza (il modello di costo del blocco calcola in pagine da 32 KiB, quindi il margine al di sotto del limite della pagina successiva è gratuito).

Preparazione per v1

v1 modifica la lettura delle transazioni, non solo il loro invio. Quando v1 sarà attivo, qualsiasi client che chiama getTransaction o getBlock senza esplicitare il supporto inizia a fallire sulle transazioni v1:

  • Passa maxSupportedTransactionVersion: 1 — l'intero JSON 1, non la stringa "1" — a getTransaction e getBlock. Passare 0 fallisce sulle transazioni v1 esattamente come omettere il parametro, quindi una base di codice aggiornata durante il rollout di v0 ha comunque bisogno del valore aggiornato.
  • getTransaction fallisce su una transazione v1 con errore -32015, e una singola transazione v1 fa fallire l'intera risposta getBlock con lo stesso errore — non esiste un risultato parziale.
  • blockSubscribe emette block: null e smette di avanzare, quindi un consumer che interpreta questo come un blocco vuoto rimane silenziosamente indietro a partire dal primo slot v1 in avanti.
  • getSignaturesForAddress non ispeziona mai i corpi delle transazioni, quindi le firme v1 vengono elencate normalmente.
  • Le risposte con opt-in includono un oggetto transactionConfig nel messaggio per le transazioni v1 (del tutto assente per legacy e v0). Le pipeline che derivano commissioni di priorità o limiti di calcolo scansionando le istruzioni ComputeBudget riporteranno silenziosamente zero per ogni transazione v1.
  • Usa encoding: 'base64' quando decodifichi le transazioni lato client e per sendTransaction/simulateTransaction con transazioni superiori a 1.232 byte — la codifica base58 rimane limitata alla vecchia dimensione.
  • Il supporto delle librerie client richiede versioni recenti: @solana/kit 8.0+, crate Rust della generazione Agave 4.2.x, o web3.js v3. web3.js v1 legge v1 dalla versione 1.99.0 in poi, ma non può costruirlo né inviarlo.

Per la guida completa alla migrazione — incluso il supporto delle librerie client, il rilevamento della versione in streaming (Geyser/gRPC) e il comportamento della simulazione — consulta la pagina di aggiornamento al formato di transazione v1.

Is this page helpful?

© 2026 Solana Foundation. Tutti i diritti riservati.