
Cómo confirmar transacciones en Solana
Tabla de contenido
Compite en cada operación con Sender, un servicio de envío de transacciones con latencia ultrabaja. Lee la documentación para comenzar a confirmar transacciones y obtener una ventaja competitiva.
Últimamente, Solana ha registrado un volumen sin precedentes, lo que provoca una alta tasa de transacciones fallidas o descartadas.
Las transacciones por segundo (TPS) de Solana rondan las 1,000 transacciones sin voto. Quinn (implementación en Rust de la capa de red: QUIC) tiene limitaciones para gestionar eficazmente el spam en escenarios de alta demanda. Esto puede obligar a los líderes de bloque a descartar conexiones de forma selectiva. De todas las transacciones fallidas, aproximadamente el 8 % fue iniciado por usuarios reales, mientras que el resto correspondió a transacciones arbitrarias de bots.
Comprender cómo se envían y procesan las transacciones en Solana es esencial para gestionar las transacciones fallidas. Este artículo analiza las posibles causas de los fallos y recomienda prácticas para aumentar el rendimiento de las transacciones. Se presupone un conocimiento básico del modelo de programación de Solana, así como de la creación y el envío de transacciones.
Transacciones
La ejecución de un programa comienza con una transacción enviada al clúster. Una transacción contiene:
- Un arreglo de todas las cuentas que pretende leer o escribir
- Una o más instrucciones (es decir, la unidad mínima de ejecución)
- Un blockhash reciente
- Una o más firmas
El entorno de ejecución procesará en orden y de forma atómica cada una de las instrucciones incluidas en la transacción. Si falla cualquier parte de una instrucción, fallará toda la transacción.
¿Qué es un blockhash?
Un "blockhash" es el hash más reciente de Proof of History (PoH) para un slot. Como Solana utiliza PoH como reloj confiable, el blockhash reciente de una transacción puede considerarse una marca de tiempo. El blockhash evita duplicados y establece la vigencia de las transacciones. Si una transacción tiene un blockhash demasiado antiguo, se rechazará. La antigüedad máxima de un blockhash es de 150 bloques o ~1 minuto y 19 segundos.
¿Cómo se envían las transacciones?
Solana se mantiene mediante un grupo de validadores que validan las transacciones agregadas al ledger. Se elige un validador líder de este grupo para incorporar las entradas al ledger. Una entrada del ledger puede ser un tick o una entrada de transacción. El ledger contiene una lista de entradas con transacciones firmadas por clientes. Conceptualmente, el ledger se remonta al bloque génesis. Sin embargo, el ledger real de un validador puede conservar solo los bloques más recientes para reducir el almacenamiento, ya que los antiguos no son necesarios para validar bloques futuros.
El validador líder solo puede producir un bloque por slot, y el blockhash es el identificador único de cada bloque. Es un hash de todas las entradas del bloque, incluido el hash del bloque anterior. El calendario de líderes se determina antes de cada época, normalmente unos dos días antes, para decidir qué validador actuará como líder en cada momento. Cuando se inicia una transacción, se reenvía al validador líder actual y al siguiente.
Las transacciones pueden enviarse al líder mediante:
- Servidor RPC: Un proveedor RPC puede enviar transacciones mediante el método JSON-RPC sendTransaction. El nodo RPC receptor intentará enviarla como paquete UDP al líder actual y al siguiente cada dos segundos, hasta que la transacción se finalice o venza su blockhash (después de 150 bloques o ~1 minuto y 19 segundos). Hasta entonces, no existe ningún registro de la transacción fuera de lo que conocen el cliente y los nodos RPC que la retransmiten.
- Cliente TPU: El cliente TPU simplemente envía la transacción. El software cliente debe encargarse de la retransmisión y el reenvío al líder.
Para usar el método sendTransaction, debes pasar el objeto de la transacción codificado como una cadena. Otros parámetros opcionales incluyen:
encoding: La codificación utilizada para los datos de la transacción es base58 o base64.skipPreflight: Las comprobaciones previas incluyen verificar las firmas y simular la transacción en el slot del banco especificado por el compromiso previo. Si la comprobación falla, se devolverá un error. El valor predeterminado de esta opción es false, lo que significa que las comprobaciones previas no se omiten.preflightCommitment: Especifica el nivel de compromiso utilizado durante las comprobaciones previas. El nivel predeterminado es finalized, pero puede cambiarse mediante una cadena. Se recomienda especificar el mismo nivel de compromiso para la transacción y la comprobación previa a fin de evitar comportamientos confusos.maxRetries: El parámetromaxRetriesdetermina el número máximo de veces que el nodo RPC debe reintentar enviar la transacción al líder. Si no se proporciona, el nodo RPC reintentará la transacción hasta que se finalice o venza el blockhash.minContextSlot: El parámetrominContextSlotespecifica el slot mínimo para realizar las comprobaciones previas de la transacción.
¿Cómo se procesan las transacciones?
La Unidad de Procesamiento de Transacciones (TPU) del validador recibe la transacción, verifica la firma, la ejecuta y la comparte con los demás validadores de la red.
La TPU procesa las transacciones en cinco fases distintas:
Etapa de recepción
La etapa de recepción se encarga de recibir transacciones. Clasifica las transacciones entrantes según tres puertos:
tpu: gestiona transacciones normales, como transferencias de tokens, acuñaciones de NFT e instrucciones de programastpu_vote: se centra exclusivamente en las transacciones de vototpu_forwards: si el líder actual no puede procesar todas las transacciones, reenvía los paquetes sin procesar al siguiente líder
Los paquetes se agrupan en lotes de 128 y se reenvían a la etapa SigVerify.
Etapa SigVerify
La etapa SigVerify verifica las firmas de los paquetes y los descarta si la verificación falla. Los votos y los paquetes normales se procesan en dos canales independientes. Desde la perspectiva del software, los paquetes recibidos contienen algunos metadatos, pero aún no está claro si son transacciones.
Si tienes una GPU instalada, se utilizará para verificar firmas. Además, existe una lógica para gestionar el exceso de paquetes cuando aumenta el tráfico, que utiliza las direcciones IP para descartar paquetes.
Etapa bancaria
Esta etapa se encarga de filtrar y procesar transacciones. Actualmente, consta de 6 subprocesos de trabajo independientes: 2 de voto y 4 sin voto. Las transacciones normales se agregan a los subprocesos sin voto. Cada subproceso tiene un búfer local capaz de almacenar hasta 64 transacciones sin conflictos en una cola de prioridad. Después, estas transacciones se procesan en paralelo gracias a Sealevel. Consulta este video para obtener más información sobre la etapa bancaria.
Servicio Proof of History
El módulo PoH Service registra el paso de los ticks. Cada tick representa una unidad de tiempo y hay 64 ticks en un slot. El hash se genera repetidamente hasta que se recibe un registro de la etapa bancaria:
next_hash = hash(prev_hash, hash(transaction_ids))
Estos registros se convierten en entradas y se transmiten a la red mediante la etapa de difusión.
Etapa de difusión
Las entradas del servicio PoH se convierten en shreds, que representan la unidad más pequeña de un bloque, y se envían al resto de la red mediante una técnica de propagación de bloques llamada Turbine. En términos generales, Turbine divide un bloque en fragmentos más pequeños y los distribuye mediante una estructura jerárquica de nodos. Los nodos no tienen que estar en contacto con todos los demás. Solo necesitan comunicarse con unos pocos nodos seleccionados. Consulta este artículo para obtener más información sobre Turbine y su funcionamiento.
¿Por qué fallan las transacciones?
Sin contar los fallos provocados por instrucciones incorrectas o errores de programas personalizados, estas son las posibles causas:
Pérdidas en la red
La capa de red puede descartar una transacción antes de que un líder llegue a procesarla. La pérdida de paquetes UDP es la causa más sencilla. Otro motivo está relacionado con el fetch stage de la TPU. Cuando la red está sometida a una carga elevada, los validadores pueden verse desbordados por la cantidad de transacciones que deben procesar. Los validadores pueden reenviar las transacciones adicionales al puerto tpu_forward del siguiente validador. Sin embargo, existe un límite para la cantidad de datos que pueden reenviarse, y cada reenvío se limita a un salto entre validadores. Esto significa que las transacciones recibidas en el puerto tpu_forwards no se reenvían a otros validadores. Si la cola de retransmisión pendiente supera las 10,000 transacciones, las transacciones nuevas se descartarán.
Blockhash obsoleto o incorrecto
Cada transacción tiene un "blockhash reciente" que funciona como marca de tiempo para el reloj de Proof of History (PoH). Este blockhash ayuda a los validadores a evitar procesar dos veces la misma transacción y permite registrar cuándo y en qué orden se procesaron las transacciones. Durante el procesamiento, el validador rechazará una transacción si el blockhash no es válido.
El blockhash vence
El blockhash de una transacción vence cuando deja de considerarse lo suficientemente "reciente". Para procesar una transacción, los validadores de Solana buscan en un bloque el número de slot correspondiente al blockhash. Si el validador no encuentra un número de slot para el blockhash, o si el número encontrado es más de 151 slots inferior al del bloque que se está procesando, se rechazará la transacción. De forma predeterminada, las transacciones de Solana vencen si no se confirman en un bloque dentro de un plazo determinado (~1 minuto y 19 segundos).
Nodos RPC rezagados
Cuando envías una transacción mediante un RPC, es posible que el grupo RPC esté adelantado con respecto al resto. Esto puede causar problemas cuando los nodos del grupo deben trabajar juntos. Por ejemplo, si el recentBlockhash de una transacción se consulta en la parte adelantada del grupo y se envía a la parte rezagada, los nodos no reconocerán el blockhash adelantado y rechazarán la transacción. Puedes detectar este problema al enviar la transacción si habilitas las comprobaciones previas en sendTransaction.
Bifurcaciones temporales de la red
Las bifurcaciones temporales de la red también pueden provocar que se descarten transacciones. Si un validador tarda en reproducir sus bloques dentro de la etapa bancaria, puede crear una bifurcación minoritaria. Cuando un cliente crea una transacción, esta podría hacer referencia a un recentBlockhash que solo existe en la bifurcación minoritaria. Tras enviar la transacción, el clúster puede abandonar esa bifurcación antes de que se procese. En este caso, la transacción se descarta porque no se encuentra el blockhash.
¿Cómo logro que se confirmen las transacciones?
Para diagnosticar problemas de confirmación, es importante comprender el vencimiento de las transacciones. Sigue estos pasos para aumentar las probabilidades de éxito:
En resumen
- Obtén el blockhash más reciente con el compromiso “
confirmed” o “finalized” - Establece
skipPreflightentrue - Optimiza la cantidad de unidades de cómputo solicitadas
- Agrega y calcula dinámicamente las comisiones de prioridad
- Establece
maxRetriesen0y agrega una lógica de reintentos personalizada para enviar transacciones. - Explora las conexiones con stake
- Si la transacción no depende del tiempo, utiliza nonces duraderos
Blockhash
Las transacciones tienen un plazo limitado para que el validador las procese. Si el blockhash asociado vence antes de que el validador procese la transacción, esta se cancelará. Para asegurar que tu transacción se complete, es importante enviarla con un blockhash reciente. Si el blockhash vence antes de que el validador procese la transacción, puedes volver a intentarlo con uno nuevo. Esto puede hacerse de dos maneras:
1. Establece un nuevo nivel de compromiso:
El método recomendado de la API RPC para obtener el blockhash más reciente es getLatestBlockhash. De forma predeterminada, este método utiliza el nivel de compromiso finalized para devolver el blockhash del bloque finalizado más reciente. Este nivel indica que se agregaron al menos 31 bloques confirmados sobre ese bloque. Así se elimina el riesgo de usar un blockhash perteneciente a una bifurcación descartada. Sin embargo, suele haber una diferencia mínima de 32 slots entre los bloques confirmados y finalizados más recientes. Esta concesión reduce unos 13 segundos el plazo antes del vencimiento de las transacciones, y podría reducirlo aún más si el clúster es inestable.
Puedes reemplazar el compromiso del blockhash estableciendo el parámetro de compromiso en otro nivel. Se recomienda el nivel confirmed para las solicitudes RPC, ya que normalmente solo está unos slots por detrás del nivel processed y tiene pocas probabilidades de pertenecer a una bifurcación descartada. Aunque el nivel processed obtiene el blockhash más reciente, no se recomienda porque aproximadamente el 5 % de los bloques no se finaliza en el clúster debido a las bifurcaciones del protocolo de Solana. Si tu transacción utiliza un blockhash de una bifurcación descartada, ningún bloque de la blockchain finalizada lo considerará reciente.
2. Consulta frecuentemente nuevos blockhashes recientes:
Agrega un script que use con frecuencia el método getLatestBlockhash para obtener y almacenar el blockhash más reciente (cada 60 segundos). Así, cuando un usuario active una transacción, la aplicación tendrá listo un blockhash actualizado. Las wallets también deben consultar nuevos blockhashes con frecuencia y reemplazar el blockhash reciente de una transacción justo antes de firmarla para asegurar que sea lo más reciente posible.
Omitir la comprobación previa
Antes de enviar una transacción, se realizan las siguientes comprobaciones previas:
- Se verifican las firmas de la transacción.
- La transacción se simula en el slot del banco especificado por el compromiso previo. Si falla, se devuelve un error.
Si el bloque elegido para la simulación es más antiguo que el usado para el blockhash de tu transacción, la simulación fallará con el temido error “blockhash not found”.
Si tienes la certeza de que se verificó la firma de tu transacción y no existen otros errores, puedes omitir la comprobación previa. Incluso si utilizas el parámetro skipPreflight, establece siempre el parámetro preflightCommitment en el mismo nivel de compromiso utilizado para obtener el blockhash de tu transacción, tanto en las solicitudes sendTransaction como en simulateTransaction.
Unidades de cómputo
Cuando se confirma una transacción en la red, consume parte de las unidades de cómputo (CU) totales disponibles en un bloque. Actualmente, el límite total por bloque es de 48 millones de CU. Los desarrolladores pueden especificar un presupuesto de unidades de cómputo para sus transacciones. Si no lo hacen, se utiliza el valor predeterminado de 200,000. Muchas transacciones no consumen todo el presupuesto de CU porque no existe ninguna penalización por solicitar más de lo necesario. Sin embargo, pedir demasiadas unidades de cómputo por adelantado puede dificultar la programación eficiente de las transacciones, ya que el planificador no sabe cuánto cómputo queda en un bloque hasta que se ejecuta la transacción. Para evitarlo, los desarrolladores deben ajustar las solicitudes de CU a los requisitos de la transacción. Consulta esta guía para optimizar el presupuesto de unidades de cómputo. En la próxima actualización v1.18 del cliente de Solana, las transacciones que requieran menos unidades de cómputo recibirán mayor prioridad.
Optimizar el uso de unidades de cómputo (CU) ofrece estos beneficios:
- Es más probable que una transacción pequeña se incluya en un bloque.
- Las instrucciones más económicas hacen que tu programa sea más componible.
- Reduce el uso general del bloque y permite incluir más transacciones.
Implementa comisiones de prioridad
Las comisiones de prioridad pueden agregarse a la comisión base para que los validadores den prioridad a las transacciones. Estas comisiones se calculan en microlamports por unidad de cómputo (es decir, pequeñas cantidades de SOL). Se agregan a las transacciones para que resulte económicamente atractivo para los nodos validadores incluirlas en los bloques de la red.
Sin embargo, es importante tener en cuenta que existe un límite razonable para las comisiones de prioridad. Pagar más que la comisión habitual no aumentará la probabilidad de éxito de tu transacción. Por eso, se recomienda calcularlas dinámicamente para pagar la cantidad adecuada, mantener la competitividad y evitar sobrecostos. La integración es sencilla. Puedes consultar la documentación oficial sobre comisiones de prioridad o utilizar la API de Helius, que ya está disponible.
Implementa una lógica de reintentos sólida
En caso de congestión de la red, implementa una lógica personalizada en tu código para gestionar los fallos y reintentar manualmente las transacciones. Para hacerlo, establece el parámetro maxRetries en 0 cuando uses sendTransaction para enviar una transacción. Puedes utilizar distintos métodos para reintentar transacciones:
- Consulta el
transaction statuscon distintos niveles de compromiso y utiliza continuamente la misma transacción firmada hasta que se confirme. Aplica un mecanismo de espera exponencial para evitar el spam. Como alternativa, puedes enviar transacciones en intervalos constantes hasta que se agote el tiempo de espera. - Almacena el
lastValidBlockHeightque proviene delgetLatestBlockhash method. Después, consulta la altura de bloque del clúster y reintenta manualmente la transacción cuando la altura actual supere ellastValidBlockHeight. Al consultar mediantegetLatestBlockhash, se recomienda especificar el nivel de compromiso previsto. Si estableces el compromiso como confirmado (votado) o finalizado (~30 bloques después de la confirmación), puedes evitar consultar un blockhash de una bifurcación minoritaria.
Conexiones con stake
La capacidad del ancho de banda de red de un líder es limitada. Para utilizarla con eficacia, se necesita una ponderación por stake que evite aceptar transacciones a ciegas por orden de llegada sin considerar su origen. Solana funciona como una red de proof-of-stake, por lo que resulta natural ampliar el uso de la ponderación por stake para mejorar la calidad de servicio de las transacciones. Esto significa que un nodo con un stake del 0.5 % puede enviar al menos el 0.5 % de los paquetes al líder, sin que el resto de la red —ni ninguna combinación del stake restante— pueda desplazarlos por completo. Este mecanismo se conoce como calidad de servicio ponderada por stake (SWQoS).
Helius ofrece conexiones con stake para los planes de pago. Para obtener más información, consulta nuestra documentación: Envío de transacciones en Solana.
Nonces duraderos
Los nonces duraderos permiten crear y firmar una transacción que puede enviarse en cualquier momento futuro. Se utilizan en casos como los servicios de custodia, que necesitan más tiempo para generar la firma de una transacción. Si tu transacción no depende del tiempo, puedes usar este método para evitar la corta vigencia del recentBlockhash de una transacción.
Para comenzar a usar transacciones duraderas, debes enviar una transacción que invoque instrucciones para crear una cuenta especial de "nonce" on-chain y almacenar en ella un "blockhash duradero". La cuenta nonce almacena el valor del nonce. Mientras la cuenta nonce no se haya utilizado, puedes crear una transacción duradera si sigues estas dos reglas:
- La lista de instrucciones debe comenzar con una instrucción del sistema "advance nonce", que carga tu cuenta nonce on-chain.
- El blockhash de la transacción debe ser igual al blockhash duradero almacenado en la cuenta nonce on-chain.
Descubre cómo implementar nonces duraderos mediante CLI y Web3.js en este artículo.
El enfoque de Helius para enviar transacciones
La solicitud sendTransaction se enruta automáticamente a nuestro nodo RPC más cercano. Si no se especifica maxRetries, la transacción se reintenta cada 2 segundos hasta que vence el blockhash. Recomendamos establecer maxRetries en 0 y retransmitir tú mismo la transacción cada 2 segundos hasta que se confirme.
Para afrontar la congestión actual de la red, trabajamos sin descanso para mejorar la tasa de confirmación de transacciones de nuestros usuarios. Hemos reducido el límite de solicitudes para la solicitud sendTransaction. Esta medida ayuda a gestionar la congestión y evita el spam al validador. Puedes consultar los límites aquí.
Además, enrutamos el tráfico de alta calidad de los planes de pago mediante conexiones con stake. Aprovechamos nuestro validador para estas conexiones. El tráfico se considera de alta calidad si la comisión de prioridad total es de al menos 10,000 lamports (la mediana del clúster).
Exigimos comisiones totales superiores a 10,000 lamports para asegurar que proporcionemos tráfico de alta calidad a los validadores. Los validadores han comenzado a limitar la frecuencia —o incluso bloquear por completo— de las fuentes de tráfico que envían transacciones con comisiones bajas.
El uso de conexiones con stake puede mejorar considerablemente tu tasa de confirmación de transacciones. Consulta este artículo para obtener más información sobre cómo establecer comisiones de prioridad al crear una transacción.
Nuestras recomendaciones
Usuarios principiantes e intermedios
Recomendamos establecer skipPreflight como false. Las comprobaciones previas incluyen verificar las firmas y simular la transacción en el slot del banco especificado por el compromiso previo. Si la comprobación falla, se devolverá un error. Sin ella, tus transacciones podrían descartarse debido a una configuración incorrecta.
Usuarios avanzados
Si eres un usuario avanzado y necesitas la menor latencia posible, debes establecer skipPreflight en true. Sin embargo, eres responsable de comprobar que la transacción esté configurada correctamente.
Conclusión
Para confirmar transacciones correctamente en la red Solana durante periodos de congestión, necesitas comprender en detalle la arquitectura de la red y sus mecanismos de procesamiento. Si entiendes conceptos esenciales como la función del blockhash en la singularidad y vigencia de las transacciones, el proceso para enviarlas mediante servidores RPC o clientes TPU y la importancia de establecer los parámetros correctos —como skipPreflight, preflightCommitment e maxRetries—, podrás mejorar considerablemente su rendimiento. Implementar un mecanismo de reintentos personalizado y aprovechar las conexiones con stake puede aumentar la tasa de éxito.
Además, es fundamental conocer las limitaciones actuales de la red y los esfuerzos continuos de Anza para resolverlas, como puede verse en el próximo lanzamiento del cliente v1.18. A medida que la red evolucione y escale, mantenerte informado y adaptarte será esencial para interactuar con ella eficazmente.
Si necesitas ayuda o soporte, contáctanos en Discord. Ingresa tu correo electrónico a continuación para no perderte ninguna novedad de Solana. ¿Quieres profundizar? Explora los artículos más recientes del blog de Helius y continúa hoy mismo tu recorrido por Solana.
Recursos
- Transacciones: Solana Cookbook
- Optimización de bloques en Solana
- Conceptos básicos de los validadores de Solana: procesamiento de transacciones por Jito Labs
- Unidad de Procesamiento de Transacciones en un validador de Solana
- El planificador de Solana
- Confirmación de transacciones por Solana
- Reintentos de transacciones por Solana
- Cómo usar comisiones de prioridad
- Cómo optimizar el cómputo
- Comisiones de prioridad y unidades de cómputo
- Nonces de transacciones duraderas
- Firma de transacciones duradera y sin conexión mediante nonces
- Transacciones de Solana: nonces duraderos por Helius
Artículos relacionados
Suscríbete a Helius
Mantente al día con las novedades del desarrollo en Solana y recibe actualizaciones cuando publiquemos


