Transacciones versionadas

Resumen

Solana tiene tres formatos de transacción: legacy, v0 y v1. v0 añade Address Lookup Tables (ALTs) para referenciar cuentas mediante índices de 1 byte. v1 eleva el límite de tamaño a 4.096 bytes, mueve los límites de recursos al propio mensaje y elimina las ALTs.

Solana admite tres formatos de transacción: legacy, v0 y v1. Cada uno se describe a continuación con los mismos tres aspectos: cómo organiza sus bytes en la red, cómo referencia las cuentas y de dónde provienen sus límites de recursos.

Estado de activación de v1

El formato v1 aún no está activo en ningún clúster. La activación está prevista con Agave v4.2. solana-test-validator 4.2+ te permite probar transacciones v1 localmente. Las aplicaciones existentes deben revisar la preparación para v1.

Comparación de formatos

Límitelegacyv0v1
Tamaño máximo de transacción1.232 bytes1.232 bytes4.096 bytes
Direcciones de cuenta~32, limitado por tamaño64, mediante tablas de búsqueda64, en línea
Tablas de búsqueda de direccionesno compatiblecompatibleno compatible
Límites de recursosInstrucciones ComputeBudgetInstrucciones ComputeBudgetconfiguración del mensaje

Ir a: Legacy · v0 · v1

Formato legacy

El formato original, y aún el predeterminado en la mayoría de las herramientas. No tiene ningún prefijo de versión: el primer byte de la transacción es el recuento compact-u16 del array de firmas, y el primer byte del mensaje es num_required_signatures, cuyo bit alto siempre está sin establecer.

Estructura de bytes legacy

CampoTamañoDescripción
num_signaturescompact-u16Número de firmas
signaturesnum_signatures x 64 bytesFirmas Ed25519
header3 bytesMessageHeader — el primer byte tiene el bit de versión sin establecer
num_account_keyscompact-u16Número de claves de cuenta
account_keysnum_account_keys x 32 bytesClaves públicas, todas en línea
recent_blockhash32 bytesEspecificador de tiempo de vida
num_instructionscompact-u16Número de instrucciones
instructionsvariableCada instrucción serializada de forma contigua

Cada array de longitud variable va precedido de una longitud compact-u16: 1 byte para valores del 0 al 127, y 2–3 bytes para valores mayores. Para ver la estructura por instrucción y un cálculo de tamaño paso a paso, consulta el formato binario de transacciones.

Cuentas en legacy

Cada cuenta se escribe como una clave pública completa de 32 bytes en account_keys, y las instrucciones las referencian mediante un índice de 1 byte en ese array. No hay forma de referenciar una cuenta que no esté incluida explícitamente en la transacción, lo cual limita una transacción legacy a aproximadamente 32 cuentas antes de agotar sus 1.232 bytes.

Límites de recursos en legacy

El límite de unidades de cómputo, el límite de tamaño de datos de cuentas cargadas, el tamaño del heap y la tarifa de prioridad se solicitan incluyendo instrucciones del programa ComputeBudget en la transacción. Cada una consume un slot de instrucción y 150 unidades de cómputo. Omitirlas es seguro: el entorno de ejecución recurre a los valores predeterminados de 200.000 CU por instrucción (con un máximo de 1,4 M), un límite de tamaño de datos de 64 MiB, un heap de 32 KiB y una tarifa de prioridad de cero.

Formato v0

v0 es un mensaje legacy con dos añadidos: un byte de prefijo de versión 0x80 y un array address_table_lookups anexado tras las instrucciones. Todo lo anterior a estos elementos es idéntico byte a byte al formato legacy.

Estructura de bytes v0

CampoTamañoDescripción
num_signaturescompact-u16Número de firmas
signaturesnum_signatures x 64 bytesFirmas Ed25519
0x801 byteByte de prefijo de versión — primer byte del mensaje
header3 bytesMessageHeader (igual que legacy)
num_account_keyscompact-u16Número de claves de cuenta estáticas
static_account_keysnum_account_keys x 32 bytesClaves que aparecen literalmente en la transacción
recent_blockhash32 bytesEspecificador de tiempo de vida
num_instructionscompact-u16Número de instrucciones
instructionsvariableMismo formato que legacy
address_table_lookupscompact-u16 + variableReferencias ALT (ver abajo)

Cada entrada de la tabla de búsqueda de direcciones contiene:

CampoTamañoDescripción
account_key32 bytesLa clave pública de la cuenta ALT
writable_indexescompact-u16 + N x 1 byteÍndices en la ALT para cuentas con permisos de escritura
readonly_indexescompact-u16 + N x 1 byteÍndices en la ALT para cuentas de solo lectura

Tablas de búsqueda de direcciones

Un ALT es una cuenta onchain que almacena hasta 256 claves públicas. Al hacer referencia a un ALT, una transacción puede incluir cuentas adicionales usando índices de 1 byte en lugar de claves públicas de 32 bytes, reduciendo significativamente la sobrecarga por cuenta.

En tiempo de ejecución, antes de que comience la ejecución, el validador resuelve todas las referencias de ALT en claves públicas completas. Las direcciones resueltas se añaden a las claves de cuenta estáticas para formar la lista completa de claves de cuenta. Las cuentas resueltas por ALT siguen el mismo orden que las cuentas estáticas: las búsquedas con permisos de escritura vienen antes que las búsquedas de solo lectura.

Las tablas de búsqueda de direcciones solo afectan cómo se referencian las cuentas en la transacción transmitida. En tiempo de ejecución, el runtime resuelve todos los índices a direcciones de cuenta completas. Las cuentas resueltas por ALT solo pueden tener permisos de escritura o ser de solo lectura (no firmantes); no pueden ser firmantes.

Límites de recursos en v0

Sin cambios respecto a legacy: instrucciones ComputeBudget, con los mismos valores predeterminados cuando se omiten.

Formato v1

v1 eleva el límite de tamaño a 4.096 bytes y reestructura el mensaje en torno a una configuración de transacción: los límites de recursos salen de las instrucciones ComputeBudget y pasan a campos de posición fija en el propio mensaje. Esto permite que la red clasifique una transacción por tarifa de prioridad con una sola lectura en un desplazamiento fijo, en lugar de escanear y deserializar su lista de instrucciones.

Estructura de bytes v1

CampoTamañoDescripción
0x811 byteByte de prefijo de versión — el primer byte de la transacción
header3 bytesMessageHeader (igual que en legacy)
config_mask4 bytesMáscara de bits u32 LE que indica qué valores de configuración están presentes
recent_blockhash32 bytesEspecificador de tiempo de vida
num_instructions1 byteRecuento de ancho fijo, máximo 64
num_addresses1 byteRecuento de ancho fijo, máximo 64
addressesN x 32 bytesDirecciones de cuenta, todas en línea — sin referencias a tablas de búsqueda
config_values0–20 bytesUn valor por bit de máscara establecido, en orden de bit (ver más abajo)
instruction_headersN x 4 bytesPor instrucción: program_id_index (u8), num_accounts (u8), data_len (u16 LE)
instruction_payloadsvariablePor instrucción: índices de cuenta y, a continuación, instruction data
signaturesN x 64 bytesAl final, sin prefijo de longitud — el recuento proviene del encabezado

Al escribir un decodificador, vale la pena señalar dos diferencias estructurales respecto a legacy y v0. Los recuentos son campos u8 de ancho fijo en lugar de compact-u16, y las instrucciones se dividen en dos bloques: primero todos los encabezados de tamaño fijo y, después, todos los payloads de longitud variable, en lugar de que cada instrucción sea contigua.

Cuentas en v1: sin tablas de búsqueda de direcciones

v1 elimina el soporte de ALT de forma deliberada. 64 direcciones sin comprimir equivalen a 2.048 bytes, lo que cabe holgadamente dentro del límite de 4.096 bytes, por lo que cada dirección está en línea, igual que en legacy. Si tu aplicación depende de tablas de búsqueda, migrar a v1 implica incluir esas direcciones directamente.

Límites de recursos en v1: la configuración de transacción

La configuración es una máscara de bits u32 seguida de valores de ancho fijo para cada campo cuyo bit está establecido:

Bit(s)CampoAnchoNotas
0–1Tarifa de prioridadu64Total en lamports — ambos bits establecidos juntos
2Límite de unidades de cómputou32
3Límite de tamaño de datos de cuentas cargadasu32
4Tamaño de heap solicitadou32

Los bits desconocidos son rechazados. Dado que el mensaje está firmado, los campos de configuración no reconocidos no pueden descartarse silenciosamente.

La tarifa de prioridad es el total en lamports, no un precio

En legacy y v0, la tarifa de prioridad se establece mediante SetComputeUnitPrice como micro-lamports por unidad de cómputo, multiplicados por el límite de unidades de cómputo. En v1 es un total absoluto en lamports — sin multiplicación ni redondeo. No traslades la aritmética por CU. La fórmula total de la tarifa no cambia en lo demás: (signatures × lamports_per_signature) + priority_fee.

Las instrucciones ComputeBudget son no-ops en v1

Una transacción v1 no rechaza las instrucciones ComputeBudget — las ignora para la configuración. Siguen ejecutándose como no-ops exitosas, consumiendo 150 unidades de cómputo y uno de los 64 slots de instrucción sin tener ningún efecto sobre el presupuesto. Elimínalas al construir transacciones v1, y deja de escanearlas al leer transacciones v1: los valores residen en la configuración del mensaje.

Los campos de configuración deben establecerse explícitamente

El cambio de comportamiento más importante para los emisores: a diferencia de legacy y v0, las transacciones v1 deben establecer explícitamente el límite de unidades de cómputo y el límite de tamaño de datos de cuentas cargadas; de lo contrario, la transacción fallará.

Campo no establecidolegacy / v0v1Consecuencia si se omite
Límite de unidades de cómputo200k por instrucción, máx. 1,4 M0 CUFalla inmediatamente, presupuesto agotado
Tamaño de datos de cuentas cargadas64 MiB0 bytesMaxLoadedAccountsDataSizeExceeded en la primera cuenta cargada
Tarifa de prioridad00
Tamaño de heap32 KiB32 KiB

El enfoque recomendado es simular una vez con ambos límites al máximo, y luego escribir los valores devueltos unitsConsumed y loadedAccountsDataSize de vuelta en la configuración, redondeando el tamaño de datos hacia arriba hasta la siguiente página de 32 KiB para tener margen (el modelo de coste de bloque cobra en páginas de 32 KiB, por lo que el margen por debajo del límite de la siguiente página es gratuito).

Preparación para v1

v1 cambia la lectura de transacciones, no solo el envío. Cuando v1 se active, cualquier cliente que llame a getTransaction o getBlock sin habilitarlo empezará a fallar con transacciones v1:

  • Pasa maxSupportedTransactionVersion: 1 — el entero JSON 1, no la cadena "1" — a getTransaction y getBlock. Pasar 0 falla con transacciones v1 exactamente igual que omitir el parámetro, por lo que una base de código actualizada durante el despliegue de v0 aún necesita que se cambie el valor.
  • getTransaction falla con una transacción v1 con el error -32015, y una sola transacción v1 hace fallar toda la respuesta de getBlock con el mismo error — no hay resultado parcial.
  • blockSubscribe emite block: null y deja de avanzar, por lo que un consumidor que interprete eso como un bloque vacío se quedará silenciosamente atrás a partir del primer slot v1 en adelante.
  • getSignaturesForAddress nunca inspecciona los cuerpos de las transacciones, por lo que las firmas v1 se listan con normalidad.
  • Las respuestas habilitadas incluyen un objeto transactionConfig en el mensaje para las transacciones v1 (completamente ausente en legacy y v0). Los pipelines que derivan tarifas de prioridad o límites de cómputo escaneando instrucciones ComputeBudget reportarán silenciosamente cero para cada transacción v1.
  • Usa encoding: 'base64' cuando decodifiques transacciones en el cliente, y para sendTransaction/simulateTransaction con transacciones de más de 1.232 bytes — la codificación base58 sigue estando limitada al tamaño antiguo.
  • El soporte en las bibliotecas cliente requiere versiones recientes: @solana/kit 8.0+, los crates de Rust de la generación Agave 4.2.x, o web3.js v3. web3.js v1 lee v1 a partir de 1.99.0 en adelante, pero no puede construirlo ni enviarlo.

Para la guía de migración completa — incluido el soporte de bibliotecas cliente, la detección de versión en streaming (Geyser/gRPC) y el comportamiento de simulación — consulta la página de actualización al formato de transacción v1.

Is this page helpful?