Transactions versionnées

Résumé

Solana propose trois formats de transaction : legacy, v0 et v1. v0 ajoute des tables de recherche d'adresses (ALTs) pour référencer les comptes via des indices d'1 octet. v1 porte la limite de taille à 4 096 octets, déplace les limites de ressources dans le message lui-même et supprime les ALTs.

Solana prend en charge trois formats de transaction : legacy, v0 et v1. Chacun est décrit ci-dessous selon les mêmes trois aspects : la disposition des octets sur le réseau, la façon dont les comptes sont référencés, et l'origine des limites de ressources.

Statut d'activation de v1

Le format v1 n'est pas encore actif sur aucun cluster. L'activation est prévue avec Agave v4.2. solana-test-validator 4.2+ vous permet de tester les transactions v1 en local. Les applications existantes doivent consulter la préparation pour v1.

Comparaison des formats

Limitelegacyv0v1
Taille maximale de la transaction1 232 octets1 232 octets4 096 octets
Adresses de comptes~32, limité par la taille64, via tables de recherche64, inline
Tables de recherche d'adressesnon supportésupporténon supporté
Limites de ressourcesInstructions ComputeBudgetInstructions ComputeBudgetconfiguration du message

Aller à : Legacy · v0 · v1

Format legacy

Le format d'origine, et toujours le format par défaut dans la plupart des outils. Il ne comporte aucun préfixe de version : le premier octet de la transaction est le compteur compact-u16 du tableau de signatures, et le premier octet du message est num_required_signatures, dont le bit de poids fort est toujours non défini.

Disposition binaire du format legacy

ChampTailleDescription
num_signaturescompact-u16Nombre de signatures
signaturesnum_signatures x 64 octetsSignatures Ed25519
header3 octetsMessageHeader — le premier octet a le bit de version non défini
num_account_keyscompact-u16Nombre de clés de compte
account_keysnum_account_keys x 32 octetsClés publiques, toutes inline
recent_blockhash32 octetsSpécificateur de durée de vie
num_instructionscompact-u16Nombre d'instructions
instructionsvariableChaque instruction sérialisée de manière contiguë

Chaque tableau de longueur variable est préfixé d'une longueur compact-u16 : 1 octet pour les valeurs 0–127, 2–3 octets pour les valeurs plus grandes. Pour la disposition par instruction et un exemple de calcul de taille, voir le format binaire des transactions.

Comptes dans le format legacy

Chaque compte est écrit en tant que clé publique complète de 32 octets dans account_keys, et les instructions les référencent par un index d'1 octet dans ce tableau. Il n'existe aucun moyen de référencer un compte qui n'est pas explicitement inscrit dans la transaction, ce qui limite une transaction legacy à environ 32 comptes avant d'épuiser ses 1 232 octets.

Limites de ressources dans le format legacy

La limite d'unités de calcul, la limite de taille des données de comptes chargés, la taille du tas et les frais de priorité sont tous demandés en incluant des instructions du programme ComputeBudget dans la transaction. Chacune coûte un slot d'instruction et 150 unités de calcul. Les omettre est sans danger : le runtime revient aux valeurs par défaut de 200 000 CU par instruction (plafonné à 1,4M), une limite de taille de données de 64 Mio, un tas de 32 Kio et des frais de priorité nuls.

Format V0

v0 est un message legacy auquel s'ajoutent deux éléments : un octet de préfixe de version 0x80 et un tableau address_table_lookups ajouté après les instructions. Tout ce qui précède ces éléments est identique octet pour octet au format legacy.

Disposition binaire du format V0

ChampTailleDescription
num_signaturescompact-u16Nombre de signatures
signaturesnum_signatures x 64 octetsSignatures Ed25519
0x801 octetOctet de préfixe de version — premier octet du message
header3 octetsMessageHeader (identique au legacy)
num_account_keyscompact-u16Nombre de clés de compte statiques
static_account_keysnum_account_keys x 32 octetsClés qui apparaissent littéralement dans la transaction
recent_blockhash32 octetsSpécificateur de durée de vie
num_instructionscompact-u16Nombre d'instructions
instructionsvariableMême format que legacy
address_table_lookupscompact-u16 + variableRéférences ALT (voir ci-dessous)

Chaque entrée de table de recherche d'adresses contient :

ChampTailleDescription
account_key32 octetsLa clé publique du compte ALT
writable_indexescompact-u16 + N x 1 octetIndices dans l'ALT pour les comptes modifiables
readonly_indexescompact-u16 + N x 1 octetIndices dans l'ALT pour les comptes en lecture seule

Tables de recherche d'adresses

Une ALT est un compte onchain qui stocke jusqu'à 256 clés publiques. En référençant une ALT, une transaction peut inclure des comptes supplémentaires en utilisant des indices de 1 octet au lieu de clés publiques de 32 octets, réduisant ainsi considérablement la surcharge par compte.

Au moment de l'exécution, avant le début de l'exécution, le validateur résout toutes les références ALT en clés publiques complètes. Les adresses résolues sont ajoutées aux clés de compte statiques pour former la liste complète des clés de compte. Les comptes résolus par ALT suivent le même ordre que les comptes statiques : les recherches modifiables viennent avant les recherches en lecture seule.

Les tables de recherche d'adresses n'affectent que la manière dont les comptes sont référencés dans la transaction sur le réseau. Au moment de l'exécution, le runtime résout tous les indices en adresses de compte complètes. Les comptes résolus par ALT ne peuvent être que modifiables ou en lecture seule (non-signataires) ; ils ne peuvent pas être signataires.

Limites de ressources dans v0

Inchangées par rapport au format legacy : instructions ComputeBudget, avec les mêmes valeurs par défaut lorsqu'elles sont omises.

Format V1

v1 porte la limite de taille à 4 096 octets et restructure le message autour d'une configuration de transaction : les limites de ressources quittent les instructions ComputeBudget pour rejoindre des champs à position fixe dans le message lui-même. Cela permet au réseau de classer une transaction par frais de priorité avec une simple lecture à offset fixe, sans avoir à parcourir et désérialiser la liste d'instructions.

Disposition binaire du format V1

ChampTailleDescription
0x811 octetOctet de préfixe de version — le premier octet de la transaction
header3 octetsMessageHeader (identique au format legacy)
config_mask4 octetsMasque de bits u32 LE indiquant quelles valeurs de configuration sont présentes
recent_blockhash32 octetsSpécificateur de durée de vie
num_instructions1 octetCompteur de largeur fixe, max 64
num_addresses1 octetCompteur de largeur fixe, max 64
addressesN x 32 octetsAdresses de comptes, toutes inline — aucune référence à des tables de recherche
config_values0–20 octetsUne valeur par bit de masque défini, dans l'ordre des bits (voir ci-dessous)
instruction_headersN x 4 octetsPar instruction : program_id_index (u8), num_accounts (u8), data_len (u16 LE)
instruction_payloadsvariablePar instruction : indices de comptes, puis instruction data
signaturesN x 64 octetsEn queue, sans préfixe de longueur — le compteur provient du header

Deux différences structurelles par rapport aux formats legacy et v0 méritent d'être notées lors de l'écriture d'un décodeur. Les compteurs sont des champs u8 de largeur fixe plutôt que compact-u16, et les instructions sont divisées en deux séquences : d'abord tous les headers de taille fixe, puis tous les payloads de longueur variable, au lieu que chaque instruction soit contiguë.

Comptes dans v1 : pas de tables de recherche d'adresses

v1 supprime délibérément la prise en charge des ALTs. 64 adresses brutes représentent 2 048 octets, ce qui reste confortablement en dessous de la limite de 4 096 octets, donc chaque adresse est inline comme dans le format legacy. Si votre application dépend des tables de recherche, passer à v1 implique d'intégrer ces adresses directement.

Limites de ressources dans v1 : la configuration de transaction

La configuration est un masque de bits u32 suivi de valeurs de largeur fixe pour chaque champ dont le bit est défini :

Bit(s)ChampLargeurNotes
0–1Frais de prioritéu64Total en lamports — les deux bits définis ensemble
2Limite d'unités de calculu32
3Limite de taille des données de comptes chargésu32
4Taille de tas demandéeu32

Les bits inconnus sont rejetés. Le message étant signé, les champs de configuration non reconnus ne peuvent pas être silencieusement ignorés.

Les frais de priorité sont un total en lamports, pas un prix unitaire

Dans les formats legacy et v0, les frais de priorité sont définis via SetComputeUnitPrice en micro-lamports par unité de calcul, multiplié par la limite d'unités de calcul. Dans v1, il s'agit d'un total absolu en lamports — sans multiplication, sans arrondi. N'appliquez pas le calcul par CU. La formule totale des frais reste par ailleurs inchangée : (signatures × lamports_per_signature) + priority_fee.

Les instructions ComputeBudget sont des no-ops dans v1

Une transaction v1 ne rejette pas les instructions ComputeBudget — elle les ignore pour la configuration. Elles s'exécutent toujours comme des no-ops réussis, consommant 150 unités de calcul et un des 64 slots d'instruction sans aucun effet sur le budget. Supprimez-les lors de la construction de transactions v1, et cessez de les rechercher lors de la lecture de transactions v1 : les valeurs se trouvent dans la configuration du message.

Les champs de configuration doivent être définis explicitement

Le changement de comportement le plus important pour les émetteurs : contrairement aux formats legacy et v0, les transactions v1 doivent définir explicitement la limite d'unités de calcul et la limite de taille des données de comptes chargés, sinon votre transaction échouera.

Champ non définilegacy / v0v1Symptôme si omis
Limite d'unités de calcul200k par instruction, max 1,4M0 CUÉchec immédiat, budget épuisé
Taille des données de comptes chargés64 Mio0 octetMaxLoadedAccountsDataSizeExceeded au premier compte chargé
Frais de priorité00
Taille du tas32 Kio32 Kio

L'approche recommandée consiste à simuler une fois avec les deux limites au maximum, puis à réinjecter les valeurs unitsConsumed et loadedAccountsDataSize retournées dans la configuration, en arrondissant la taille des données à la page de 32 Kio supérieure pour disposer d'une marge (le modèle de coût du bloc facture par pages de 32 Kio, donc la marge en dessous de la prochaine limite de page est gratuite).

Préparation pour v1

v1 modifie la lecture des transactions, pas seulement leur envoi. Lorsque v1 sera activé, tout client qui appelle getTransaction ou getBlock sans y souscrire commencera à échouer sur les transactions v1 :

  • Passez maxSupportedTransactionVersion: 1 — l'entier JSON 1, et non la chaîne "1" — à getTransaction et getBlock. Passer 0 échoue sur les transactions v1 exactement comme l'omission du paramètre, donc une base de code mise à jour lors du déploiement de v0 doit toujours changer cette valeur.
  • getTransaction échoue sur une transaction v1 avec l'erreur -32015, et une seule transaction v1 fait échouer toute la réponse getBlock avec la même erreur — il n'y a pas de résultat partiel.
  • blockSubscribe émet block: null et cesse d'avancer ; un consommateur qui interprète cela comme un bloc vide prend silencieusement du retard à partir du premier slot v1.
  • getSignaturesForAddress n'inspecte jamais le contenu des transactions, donc les signatures v1 apparaissent normalement dans la liste.
  • Les réponses avec souscription incluent un objet transactionConfig dans le message pour les transactions v1 (absent pour les formats legacy et v0). Les pipelines qui déduisent les frais de priorité ou les limites de calcul en recherchant les instructions ComputeBudget signaleront silencieusement zéro pour chaque transaction v1.
  • Utilisez encoding: 'base64' lorsque vous décodez des transactions côté client, et pour sendTransaction/simulateTransaction avec des transactions dépassant 1 232 octets — l'encodage base58 reste plafonné à l'ancienne taille.
  • La prise en charge par les bibliothèques clientes nécessite des versions récentes : @solana/kit 8.0+, les crates Rust de génération Agave 4.2.x, ou web3.js v3. web3.js v1 lit le format v1 à partir de la version 1.99.0, mais ne peut pas le construire ni l'envoyer.

Pour le guide de migration complet — incluant la prise en charge par les bibliothèques clientes, la détection de version en streaming (Geyser/gRPC) et le comportement de simulation — consultez la page de mise à niveau vers le format de transaction v1.

Is this page helpful?

© 2026 Fondation Solana. Tous droits réservés.