La Transacción
Una transacción de Solana no es un script libre que envías a un contrato inteligente.
Es un mensaje firmado y con límite de tiempo que lista cada cuenta que tocará, cada programa que llamará y cada firma requerida; luego aplica todas sus instrucciones o ninguna de ellas.
Conceptos Básicos de Transacciones muestra pasos concretos de construcción y envío; Instrucciones y Cuentas, Tarifas de Prioridad y Blockhashes y Caducidad se centran en una pieza cada uno.
Esta página es la capa subyacente: el modelo único que hace que esas páginas se sientan como un sistema en lugar de una lista de verificación de APIs.
Resumen
- Una transacción es un mensaje (instrucciones, metadatos de cuenta, blockhash reciente o durable nonce, pagador de tarifas) más firmas sobre ese mensaje, ejecutado atómicamente por el runtime.
- Por Qué Importa: Casi todas las fallas de aterrizaje, tarifas y "tx eliminada" son un malentendido de las cuentas, la caducidad o los mercados de tarifas, no de la lógica de negocio del programa.
- Conceptos Clave: instrucción, AccountMeta, signer, fee payer (pagador de tarifas), recent blockhash (blockhash reciente), atomicity (atomicidad), compute units (CU) (unidades de cómputo), priority fee (tarifa de prioridad), versioned transaction (v0) (transacción versionada v0), address lookup table (ALT) (tabla de búsqueda de direcciones), simulation (simulación).
- Cuándo Usar: Diseñar rutas de envío de clientes, depurar eliminaciones silenciosas frente a errores en la cadena, elegir entre tarifas base solamente, tarifas de prioridad o aterrizaje avanzado, o enseñar cómo funcionan los paquetes de Solana antes de escribir programas.
- Limitaciones / Compensaciones: Las listas explícitas de cuentas y los tiempos de vida cortos obtienen programación paralela y seguridad de repetición, a costa de una mayor complejidad del cliente (actualizar blockhashes, establecer presupuestos de CU, manejar la congestión local).
- Temas Relacionados: Bloqueos de cuentas de Sealevel, programa Compute Budget, durable nonces, propinas y paquetes de Jito.
Fundamentos
Una transacción tiene dos partes principales: el mensaje (qué debería suceder) y las firmas (quién autorizó esa cadena de bytes exacta).
El runtime no inventa cuentas o programas en tu nombre; todo lo que una instrucción necesita debe estar ya nombrado en el mensaje.
Una instrucción es la unidad de trabajo más pequeña: un program_id, una lista de cuentas y datos opacos (data) que el programa entiende (a menudo un discriminador más codificación Borsh o personalizada).
Una transacción es una lista ordenada de tales instrucciones que comparten un único pagador de tarifas, un único tiempo de vida y un único conjunto de firmas.
Cada entrada de cuenta es un AccountMeta: una clave pública más dos booleanos, is_signer y is_writable.
Esas banderas no son pistas para la documentación; son la superficie de bloqueo y autoridad que el runtime aplica antes de que se ejecute cualquier bytecode del programa.
is_signer significa que una firma coincidente debe aparecer en la transacción (o una ruta válida de CPI firmada por programa para PDAs).
is_writable significa que la cuenta puede tener sus datos o lamports mutados y está bloqueada para escritura exclusiva durante la ejecución de esta transacción.
Las cuentas que solo son legibles pueden programarse en paralelo con otras transacciones que también solo las leen; dos escritores en la misma cuenta compiten.
El fee payer (pagador de tarifas) es típicamente la primera cuenta marcada como firmante requerida y debe tener suficientes SOL (lamports) para cubrir las tarifas de toda la transacción.
La atomicidad significa que la lista completa de instrucciones tiene éxito o el estado del ledger de esas instrucciones se revierte; no obtienes "instrucción 1 confirmada, instrucción 2 falló a medias".
La ejecución fallida aún puede costar tarifas, porque los validadores gastaron cómputo intentando el trabajo; no trates el fallo como gratuito.
Una analogía útil es un formulario de transferencia bancaria de varios pasos: cada número de cuenta está escrito en el formulario por adelantado, cada firma requerida está en el mismo papel, el formulario caduca después de una breve ventana de validez, y el banco o bien registra todo el paquete o lo rechaza; nunca deja la mitad de las líneas aplicadas.
Eso está más cerca de Solana que de una "llamada a este contrato y deja que descubra el almacenamiento" de final abierto.
Mecánicas e Interacciones
Construir y aterrizar una transacción es un bucle cerrado de componer, autorizar, (opcionalmente) simular, enviar y confirmar, siempre contra una vida útil fresca.
componer mensaje autorizar decidir
--------------- --------- ------
instrucciones[] ──► mensaje ──► firmas[] ──► simular? ──► enviar
metadatos de cuenta ▲ │
pagador de tarifas │ │ error / CU
blockhash reciente──────┘ ▼
(o durable nonce) ajustar y reconstruir
│
▼
RPC / líder
│
▼
ejecutar atómicamente
(todo ok o nada)
Componer: Recopila cada instrucción que tu flujo necesita (transferencia del Sistema, SPL Token, tu programa Anchor, Compute Budget, etc.) y une todas las cuentas que esas instrucciones requieren en la lista de cuentas del mensaje con las banderas correctas de firmante/escritura.
Tiempo de Vida: Adjunta un blockhash reciente de getLatestBlockhash (o equivalente en @solana/kit 7.0.0) para que el mensaje sea único y solo válido mientras ese blockhash permanezca reciente, típicamente en el orden de 60-90 segundos, dependiendo del tiempo del clúster y cómo los clientes interpreten la "última altura de bloque válida".
Sin un blockhash cambiante, cargas idénticas podrían repetirse indefinidamente; con uno, los reintentos después de la caducidad deben reconstruir y volver a firmar con un nuevo hash.
Los durable nonces son la alternativa cuando necesitas una transacción que pueda permanecer sin firmar o sin enviar por más tiempo que una ventana normal de blockhash (multisig, firma offline, lanzamiento programado), el mismo modelo de mensaje y firmas, pero con un mecanismo de tiempo de vida diferente. Ver Blockhashes y Caducidad.
Autorizar: Cada cuenta con is_signer: true debe contribuir con una firma sobre el mensaje serializado (billetera, clave de backend, firmante de hardware).
Faltar una firma requerida falla antes de un trabajo de programa significativo; firmas extra desperdician la tarifa base sin comprar autoridad que no declaraste.
Tarifas: La tarifa base escala con el número de firmas en la transacción.
La tarifa de prioridad opcional se establece incluyendo instrucciones del programa Compute Budget: típicamente setComputeUnitLimit (cuántas CUs permites) y setComputeUnitPrice (microlamports por CU), por lo que la prioridad rastrea aproximadamente CU_limit × CU_price más el costo base de la firma. Los detalles se encuentran en El Programa Compute Budget y Tarifas de Prioridad.
Simular: La simulación RPC ejecuta la transacción contra el estado actual del banco sin confirmarla, devolviendo errores, registros y a menudo unidades de cómputo consumidas.
Usa la simulación para pre-vuelo (cuentas incorrectas, restricciones fallidas, fondos insuficientes) y para dimensionar el límite de CU ligeramente por encima del consumo medido en lugar de solicitar siempre el máximo.
Enviar y confirmar: El envío entrega los bytes firmados a un RPC (o a una ruta de aterrizaje especializada); los líderes ordenan y ejecutan bajo Sealevel usando los bloqueos de cuenta declarados.
Tu cliente debe tratar "enviado" como distinto de "confirmado": actualiza el blockhash y vuelve a firmar al caducar, y prefiere la suscripción de firma o el sondeo con un nivel de confirmación que coincida con tu riesgo (confirmed para muchas acciones de la aplicación, finalized para liquidación de alto valor).
Bajo congestión, se forman mercados de tarifas locales alrededor de cuentas de escritura activas: dos intercambios que luchan por la misma cuenta de pool no compiten con toda la cadena por igual; compiten entre sí por el bloqueo de escritura de esa cuenta y las elecciones de empaquetado del líder.
Aumentar la tarifa de prioridad ayuda cuando te quedas sin inclusión; no soluciona una bandera de firmante incorrecta o un blockhash caducado.
Consideraciones Avanzadas y Aplicaciones
Los mensajes legacy vs versioned (v0) comparten el mismo modelo mental: instrucciones, cuentas, firmas, atomicidad; pero difieren en cuántas cuentas puedes encajar dentro del límite de tamaño serializado.
Las transacciones legacy incrustan cada clave pública de cuenta en línea en el mensaje.
Las transacciones versionadas (v0) pueden referenciar tablas de búsqueda de direcciones (ALTs): tablas en cadena de direcciones en las que el mensaje se indexa, por lo que caben más cuentas sin repetir claves completas de 32 bytes para cada entrada. Inmersión conceptual: Transacciones Versionadas (v0) y Tablas de Búsqueda de Direcciones.
Usa v0 + ALTs al componer grandes gráficos de CPI (enrutadores DeFi, intercambios de varios saltos, pipelines de acuñación complejos); mantente simple con menos cuentas cuando no necesites el espacio.
Los límites de CU basados en simulación superan las conjeturas estáticas: simula, lee las CU consumidas, establece el límite con un pequeño margen de seguridad, luego establece el precio según tu urgencia y la competencia observada.
Las propinas y paquetes de Jito son una ruta de aterrizaje avanzada: puedes pagar una propina y/o enviar un paquete atómico para inclusión consciente de MEV, todavía bajo las mismas reglas de instrucción y cuenta, pero a través de infraestructura especializada en lugar de solo tarifas de prioridad en la ruta pública. Mantén esto conceptual hasta que lo necesites; consulta Propinas y Paquetes de Jito.
| Estrategia | Lo que pagas | Fortaleza | Debilidad | Mejor ajuste |
|---|---|---|---|---|
| Solo tarifa base | Costo base por firma | Más barato; bien cuando la red está tranquila | Fácil perder inclusión bajo carga o en cuentas activas | Devnet, transferencias de baja contención, administración no urgente |
| Tarifa de prioridad (Compute Budget) | Base + precio_CU × CU usada/límite | Funciona con RPC normal; urgencia ajustable | Pagar de más desperdicia SOL; pagar de menos aún se cae | La mayoría de las dapps de producción, acuñaciones de NFT, intercambios minoristas |
| Propina / paquetes de Jito | Propina (+ prioridad opcional) a través de ruta especializada | Mayor aterrizaje y paquetes atómicos de varias transacciones | Complejidad de operaciones adicional; no sustituye a transacciones correctas | Flujos competitivos sensibles a MEV, conjuntos atómicos de varios pasos |
Ninguna de estas estrategias cambia la atomicidad o las reglas de AccountMeta; solo cambian cuánto pujas por la inclusión una vez que el mensaje es válido.
Los clientes en @solana/kit 7.0.0 deben preferir constructores de mensajes v0, pagador de tarifas explícito y ayudantes de tiempo de vida, y simulación antes de las rutas de envío de mainnet.
Los programas en Anchor 0.32.1 todavía ejecutan solo las cuentas que el cliente declaró; las macros del framework generan datos de instrucción y listas de cuentas, pero el modelo de runtime anterior sigue siendo la fuente de verdad.
Conceptos Erróneos Comunes
- "Una transacción es solo una llamada a mi programa." Es un mensaje de múltiples instrucciones con una lista global de cuentas, un pagador de tarifas, un tiempo de vida y firmas; tu programa es uno (o más) de los llamados, no el contenedor.
- "Si la lógica del programa es correcta, la transacción aterrizará." Los programas correctos aún fallan al aterrizar cuando los blockhashes caducan, los presupuestos de CU son demasiado bajos, las tarifas no son competitivas o las cuentas están mal marcadas.
- "Writable significa que el programa siempre puede escribir." Writable solo otorga el bloqueo del runtime; solo el programa propietario puede mutar los datos de la cuenta, y tu instrucción aún debe pasar todas las restricciones.
- "Los reintentos pueden reenviar los mismos bytes firmados para siempre." Una vez que el blockhash está obsoleto, esas firmas autorizan un mensaje caducado; reconstruye con un nuevo blockhash y vuelve a firmar (a menos que uses un diseño de durable nonce).
- "La tarifa de prioridad reemplaza la simulación." La tarifa de prioridad compra preferencia de programación; la simulación detecta fallos semánticos y dimensiona las CU; necesitas ambas bajo carga real.
- "Más cuentas siempre significa una tarifa más grande." La tarifa base sigue a las firmas, no al recuento de cuentas; el recuento de cuentas afecta los límites de tamaño y la contención de bloqueos más que la tarifa base directamente.
- "El éxito parcial es posible si falla la última instrucción." Dentro de una transacción, la ejecución es atómica para la lista de instrucciones; diseña flujos de usuario de varios pasos como una sola tx cuando necesites todo o nada.
Preguntas Frecuentes
¿Qué es una transacción de Solana en una oración?
Un mensaje firmado que lista instrucciones ordenadas y todas las cuentas que tocan, ejecutado atómicamente dentro de un corto tiempo de vida establecido por un blockhash reciente (o durable nonce).
¿Cuál es la diferencia entre un mensaje y una transacción?
El mensaje es la intención sin firmar (cuentas, instrucciones, tiempo de vida, pagador de tarifas); la transacción es ese mensaje más las firmas que lo autorizan.
¿Qué contiene una instrucción?
Un ID de programa para invocar, una lista ordenada de AccountMetas y un array de bytes de datos de instrucción para que ese programa lo decodifique.
¿Qué controlan realmente is_signer e is_writable?
is_signer requiere una firma coincidente (autoridad); is_writable permite la mutación y toma un bloqueo de escritura utilizado para la programación paralela y la seguridad.
¿Quién paga las tarifas y cómo se elige el pagador de tarifas?
El pagador de tarifas es un firmante requerido en el mensaje (comúnmente el primero) cuyo saldo de lamports se debita por las tarifas base y de prioridad de toda la transacción.
¿Por qué las transacciones necesitan un blockhash reciente?
Hace que cada mensaje sea único (protección contra repetición) y limita cuánto tiempo sigue siendo válido la carga útil firmada, obligando a los clientes a actualizar la intención en el orden de aproximadamente 60-90 segundos.
¿Qué sucede cuando caduca un blockhash?
Los validadores rechazan o descartan la transacción por ser demasiado antigua; debes obtener un nuevo blockhash, reconstruir el mensaje si es necesario, volver a firmar y reenviar.
¿Cuándo debería usar un durable nonce en lugar de un blockhash reciente?
Cuando el proceso de firma y envío no puede completarse dentro de una ventana normal de blockhash (firma offline, aprobación multipartidista o lanzamiento retrasado), aceptando la maquinaria adicional de la cuenta nonce.
¿Las transacciones fallidas son gratuitas?
No. Las tarifas aún pueden cobrarse por el trabajo que la red realizó; considera la simulación como la forma económica de detectar fallos antes de pagar por una ruta de envío completa.
¿Cómo difieren las tarifas base y las tarifas de prioridad?
La tarifa base está ligada a las firmas en la transacción; la tarifa de prioridad es un precio de CU opcional (a través de Compute Budget) que aumenta la competitividad de inclusión bajo carga.
¿Por qué establecer tanto el límite de unidades de cómputo como el precio de las unidades de cómputo?
El límite limita la cantidad de cómputo que permites (y alimenta el cálculo de tarifas); el precio es tu oferta por CU; juntos definen cuánto presupuesto de prioridad pones sobre la mesa sin excederte ciegamente.
¿Qué problema resuelven las transacciones versionadas v0 y las ALTs?
Permiten que los mensajes referencien cuentas a través de tablas de búsqueda en cadena para que las listas de cuentas grandes quepan en el límite de tamaño de la transacción sin incrustar cada clave pública completa en línea.
¿Para qué sirve la simulación si ya he probado unitariamente mi programa?
La simulación verifica este mensaje exacto contra el estado actual del clúster (cuentas, saldos, CU y registros), lo que las pruebas unitarias en una VM local no reemplazan completamente para el aterrizaje en devnet o mainnet-beta.
¿Por qué mi tx falla solo cuando el mercado está ocupado?
Las cuentas de escritura activas crean contención local; bajo carga, las tarifas de prioridad bajas o cero pierden las carreras de empaquetado incluso cuando los mismos bytes tienen éxito en períodos tranquilos.
¿Las propinas de Jito reemplazan las tarifas de prioridad?
No como sustituto mental: las propinas y los paquetes son una ruta de aterrizaje alternativa o complementaria para flujos competitivos; tu mensaje aún debe ser válido, firmado y contabilizado correctamente.
Relacionados
- Conceptos Básicos de Transacciones - patrones de construcción, firma y envío
- Instrucciones y Cuentas - AccountMeta, IDs de programa y datos
- Transacciones Versionadas (v0) - formato de mensaje v0
- Tarifas de Prioridad - mercados de tarifas locales y precio de CU
- El Programa Compute Budget - setComputeUnitLimit y setComputeUnitPrice
- Blockhashes y Caducidad - tiempos de vida, reintentos y durable nonces
Versiones de Pila: Esta página fue escrita para Agave 4.1.1, Solana CLI 3.0.10, Anchor 0.32.1, anchor-lang 0.32.1, Rust 1.91.1, @solana/kit 7.0.0, Surfpool 0.12.0 y LiteSVM 0.6.x.