NUEVO: Helius adquiere Light Protocol
Actualización v1.18 de Solana
Blog/Actualizaciones

Todo lo que necesitas saber sobre la actualización v1.18 de Solana

Developer Experience Engineer0xIchigo en X0xIchigo en LinkedIn0xIchigo en GitHub
19 min de lectura

Muchas gracias a Rex St. John y Mike MacCana por revisar este artículo.

Introducción

La adopción de la actualización 1.18 de Solana por una supermayoría es un hito importante. Introduce numerosas mejoras y funciones nuevas destinadas a optimizar el rendimiento, la confiabilidad y la eficiencia de la red. Uno de los cambios más destacados es la introducción de un planificador central. Este nuevo planificador busca agilizar la gestión de transacciones y garantizar cálculos de prioridad más precisos y eficientes. Otras mejoras en el entorno de ejecución y los despliegues de programas, por ejemplo, ayudan a ofrecer un rendimiento más confiable incluso durante los picos de carga de la red.

Este artículo analiza las actualizaciones y mejoras de la versión 1.18. Exploraremos las razones detrás de estos cambios, los detalles de las nuevas funciones y su impacto esperado en la red. Ya seas operador de un validador, desarrollador o usuario habitual de Solana, este resumen completo de la actualización 1.18 te dará la información necesaria para comprender y aprovechar los beneficios de estas nuevas mejoras.

Primero debemos hablar de Anza, una empresa de desarrollo recién creada que impulsa estos cambios, y de su función en el desarrollo continuo de Solana.

¿Qué es Anza?

Anza es una empresa de desarrollo de software recién creada por antiguos ejecutivos e ingenieros principales de Solana Labs. Su creación representa un movimiento estratégico para reforzar el ecosistema de Solana y mejorar su confiabilidad, descentralización y solidez de red. Anza se fundó para fortalecer el ecosistema de Solana mediante el desarrollo de infraestructura crítica, la contribución a protocolos clave y el fomento de la innovación de nuevas herramientas.

El equipo fundador incluye a Jeff Washington, Stephen Akridge, Jed Halfon, Amber Christiansen, Pankaj Garg, Jon Cinque y varios ingenieros principales de Solana Labs.

Anza se centra en desarrollar y perfeccionar los clientes validadores de Solana mediante la creación de Agave, una bifurcación del cliente validador de Solana Labs. Las ambiciones de Anza van más allá del desarrollo de su cliente validador y abarcan mejoras para todo el ecosistema. Esto incluye el desarrollo de Token Extensions y una cadena de herramientas personalizada de Rust / Clang. Mediante un enfoque de desarrollo abierto y colaborativo, Anza busca acelerar y mejorar el ecosistema de Solana.

¿Qué es Agave?

Como mencionamos brevemente en la sección anterior, Agave es una bifurcación del cliente validador de Solana Labs liderada por Anza. En este contexto, el término “bifurcación” significa que el equipo de desarrollo de Anza tomó el código existente del repositorio de Solana Labs e inició una nueva ruta de desarrollo separada del código base original. Esto permite a Anza implementar sus propias mejoras, funciones y optimizaciones en el cliente de Solana Labs.

El proceso de migración

La migración del cliente a la organización de GitHub de Anza comenzó el 1 de marzo. Al principio, Agave reflejará el repositorio de Solana Labs para dar tiempo a la comunidad de adaptarse. Durante este periodo, Anza se encargará de cerrar solicitudes de incorporación de cambios (PR) y migrar los problemas relevantes al repositorio de Agave. Agave y las versiones 1.17 y 1.18 del cliente de Solana Labs serán idénticos en cuanto a funcionalidad. Anza pretende lanzar Agave v2.0 este verano, lo que incluye archivar el cliente de Solana Labs y recomendar que el 100 % de la red migre al nuevo cliente Agave.

El proceso de migración de Solana Labs a Agave se supervisa públicamente en su GitHub.

El entorno de ejecución de Agave

El entorno de ejecución de Agave hereda su arquitectura base de la Solana Virtual Machine (SVM) y es la columna vertebral para ejecutar las funciones principales definidas por el entorno de ejecución Sealevel. 

El protocolo de Solana define el entorno de ejecución como un componente crítico para procesar transacciones y actualizar el estado de la base de datos de cuentas. Los clientes Agave y Firedancer adoptaron y perfeccionaron esta especificación. La esencia de la SVM es su capacidad para ejecutar todos los programas de Solana y modificar los estados de las cuentas en paralelo.

El concepto de banco es clave para procesar transacciones y comprender los cambios que llegarán con la versión 1.18. Un banco es tanto una pieza de lógica como una representación del estado del libro mayor en un momento determinado. Actúa como un controlador sofisticado que administra la base de datos de cuentas, supervisa el seguimiento de las cuentas de clientes, gestiona la ejecución de programas y mantiene la integridad y el avance del libro mayor de Solana. Un banco encapsula el estado resultante de las transacciones incluidas en un bloque determinado y sirve como una instantánea del libro mayor en ese momento.

Cada banco dispone de las cachés y referencias necesarias para ejecutar transacciones, lo que permite inicializarlo desde una instantánea anterior o desde el bloque génesis. Durante la etapa bancaria, donde el validador procesa las transacciones, los bancos se usan para ensamblar bloques y verificar posteriormente su integridad. Este ciclo de vida incluye cargar cuentas, procesar transacciones, congelar el banco para finalizar el estado y, finalmente, establecerlo como raíz para garantizar su permanencia.

En términos generales, el motor de procesamiento de transacciones del entorno de ejecución de Agave se encarga de cargar, compilar y ejecutar programas. Usa compilación Just-In-Time (JIT) y almacena en caché los programas compilados para optimizar la eficiencia de ejecución y reducir las recompilaciones innecesarias. Los programas se compilan en formato eBPF antes del despliegue. Luego, el entorno de ejecución usa el conjunto de herramientas rBPF para crear una máquina virtual eBPF, que realiza la compilación JIT de eBPF a instrucciones de código máquina x86_64 y aprovecha al máximo el hardware disponible. Esto garantiza que los programas se ejecuten de forma eficiente.

La actualización 1.18 introduce un planificador central de transacciones estrechamente relacionado con las eficiencias operativas del entorno de ejecución de Agave. Al mejorar la forma en que las transacciones se compilan, ejecutan y gestionan mediante bancos, la actualización 1.18 permite un proceso de planificación más ágil y eficiente. A su vez, esto acelera el procesamiento de transacciones y aumenta el rendimiento. El nuevo entorno de ejecución de Agave y su cliente son la base de estas mejoras, por lo que es fundamental tener una comprensión general antes de profundizar en los detalles del nuevo planificador. 

Si quieres saber más sobre el entorno de ejecución de Agave, te recomiendo leer el artículo de Joe Caulfield sobre el tema. Profundiza bastante y ofrece fragmentos de código útiles a lo largo del texto.

Un planificador de transacciones más eficiente

La implementación actual

En el flujo de procesamiento de transacciones, los paquetes de transacciones ingresan primero al sistema por el punto de entrada. Luego, estos paquetes pasan por la verificación de firmas durante la etapa SigVerify. Este paso garantiza que cada transacción sea válida y esté autorizada por el remitente.

Después de verificar las firmas, las transacciones se envían a la etapa bancaria. Esta tiene seis hilos: dos dedicados a procesar transacciones de voto provenientes de la Unidad de Procesamiento de Transacciones (TPU) o de Gossip, y cuatro centrados en transacciones sin voto. Cada hilo es independiente de los demás y recibe paquetes de un canal compartido. Es decir, SigVerify envía paquetes en lotes, y cada hilo extrae transacciones de ese canal compartido y las almacena en un búfer local. 

El búfer local recibe las transacciones, determina su prioridad y las ordena según corresponda. Esta cola es dinámica y se actualiza constantemente para reflejar en tiempo real los cambios en el estado de las transacciones y las demandas de la red. A medida que se agregan transacciones a la cola, se reevalúa su orden para garantizar que las de mayor prioridad estén listas para procesarse primero.

Este proceso ocurre continuamente, y lo que sucede con estos paquetes de transacciones depende de la posición del validador en el calendario de líderes. Si no está previsto que el validador sea el líder en un futuro próximo, reenviará los paquetes al siguiente líder y los descartará. Cuando el validador se acerca a su slot de liderazgo programado (a unos ~20 slots), continúa reenviando paquetes, pero deja de descartarlos. Esto garantiza que pueda incluirlos en uno de sus propios bloques si los otros líderes no los procesan. Cuando faltan 2 slots para que un validador se convierta en líder, comienza a retener los paquetes: los acepta y no hace nada con ellos para poder procesarlos cuando se convierta en líder.

Durante la producción de bloques, cada hilo toma las 128 transacciones principales de su cola local, intenta adquirir bloqueos y luego comprueba, carga, ejecuta, registra y confirma las transacciones. Si no puede adquirir un bloqueo, vuelve a intentar la transacción más tarde. Veamos cada paso con más detalle:

  • Bloqueo: Este paso comprueba para qué transacciones puede adquirir bloqueos el hilo. Cada transacción leerá y escribirá cierta cantidad de cuentas, por lo que el validador debe asegurarse de que no haya conflictos
  • Comprobaciones: Este paso comprueba si la transacción es demasiado antigua o ya fue procesada. Ten en cuenta que los bancos tienen una caché de estados que registra las transacciones de los últimos 150-300 slots
  • Carga: Este paso carga las cuentas necesarias para ejecutar una transacción determinada. También comprueba si el pagador de comisiones puede pagar las comisiones y si el programa invocado es válido. En esencia, este paso carga las cuentas y realiza la configuración inicial
  • Ejecución: Este paso ejecuta cada transacción
  • Registro: Los resultados de las transacciones ejecutadas se envían al servicio de prueba de historial para aplicarles un hash. Aquí es donde se envía la firma de la transacción
  • Confirmación: Si el paso de registro se completa correctamente, las transacciones se confirman. Este paso también propaga los cambios al sistema de cuentas para que las transacciones futuras de este slot o de slots posteriores tengan la vista actualizada de cada cuenta‍
  • Desbloqueo: Se eliminan los bloqueos de cada cuenta establecidos en el primer paso

La etapa bancaria usa un enfoque de múltiples iteradores para crear estos lotes de transacciones. Un iterador múltiple es un patrón de programación que permite recorrer simultáneamente un conjunto de datos en varias secuencias. Imagina que varios lectores recorren un mismo libro, cada uno desde un capítulo diferente, y se coordinan para no leer la misma página al mismo tiempo si sus interpretaciones del contenido pudieran interferir entre sí. En la etapa bancaria, estos “lectores” son iteradores y el “libro” es el conjunto de transacciones pendientes de procesamiento. El objetivo del iterador múltiple es filtrar las transacciones de manera eficiente y agruparlas en lotes que puedan procesarse sin conflictos de bloqueo.

Al principio, las transacciones se serializan en un vector según su prioridad. Esto proporciona al iterador múltiple una secuencia estructurada para dividirlas en lotes sin conflictos. El iterador múltiple comienza al principio del vector serializado y coloca iteradores en puntos donde las transacciones no entran en conflicto entre sí. De este modo, crea lotes de 128 transacciones sin conflictos de lectura-escritura ni escritura-escritura. Si una transacción entra en conflicto con el lote que se está formando, se omite y queda sin marcar, lo que permite incluirla en un lote posterior donde el conflicto ya no exista. Este proceso iterativo se ajusta de forma dinámica a medida que se siguen procesando transacciones. 

Después de formar correctamente un lote, se ejecutan las transacciones y, si se completan correctamente, se registran en el servicio de prueba de historial y se transmiten a la red.

Problemas de la implementación actual

La implementación actual tiene varias áreas donde el rendimiento puede verse afectado, lo que genera posibles cuellos de botella en el procesamiento de transacciones y una priorización inconsistente. Estos desafíos se deben principalmente a la arquitectura de la etapa bancaria y a la forma en que el sistema gestiona las transacciones.

Un problema fundamental es que los cuatro hilos independientes que procesan transacciones sin voto tienen su propia visión de la prioridad de las transacciones dentro de cada hilo. Esta discrepancia puede causar variaciones o inconsistencias en el orden de las transacciones. Las diferencias se acentúan cuando todas las transacciones de alta prioridad entran en conflicto. Como cada hilo extrae los paquetes de forma esencialmente aleatoria del canal compartido de SigVerify, cada uno tendrá un conjunto aleatorio de todas las transacciones. Durante eventos competitivos, como la acuñación de una colección NFT popular, es probable que muchas transacciones de alta prioridad estén presentes en varios hilos de la etapa bancaria. Esto es problemático porque puede causar conflictos de bloqueo entre hilos. Los hilos, que trabajan con distintas prioridades, pueden competir entre sí para procesar estas transacciones de alta prioridad y desperdiciar tiempo de procesamiento por intentos fallidos de bloqueo.

Imagina la etapa bancaria como una orquesta donde cada hilo es una sección distinta: cuerdas, metales, maderas y percusión. Lo ideal sería que un director coordinara estas secciones para garantizar una interpretación armoniosa. Sin embargo, el sistema actual se parece a una orquesta que intenta interpretar una pieza compleja sin director. Cada sección toca su propia melodía y choca con las demás constantemente. Las transacciones de alta prioridad son las partes solistas que todas las secciones intentan tocar al mismo tiempo, lo que genera confusión. Esta falta de coordinación destaca la necesidad de un “director” centralizado que garantice eficiencia y armonía en el procesamiento de transacciones de Solana, como un director que guía a una orquesta.

El nuevo planificador de transacciones

La actualización 1.18 introduce un hilo de planificación central que sustituye el modelo anterior de cuatro hilos bancarios independientes, cada uno encargado de priorizar y procesar sus propias transacciones. En esta estructura revisada, el planificador central es el único receptor de las transacciones de la etapa SigVerify. Crea una cola de prioridad y usa un grafo de dependencias para gestionar la priorización y el procesamiento de transacciones.

Este grafo de dependencias se conoce como prio-graph. Es un grafo acíclico dirigido que se evalúa de forma diferida a medida que se agregan nuevas transacciones. Las transacciones se insertan en el grafo para crear cadenas de ejecución y luego se extraen por orden temporal de prioridad. Cuando hay transacciones en conflicto, la primera que se inserta siempre tendrá mayor prioridad. En el ejemplo anterior, tenemos las transacciones de la A a la H. Observa que las transacciones A y E tienen la máxima prioridad dentro de sus respectivas cadenas y no entran en conflicto. El planificador avanza de izquierda a derecha y procesa las transacciones por lotes:

Las transacciones A y E se procesan como primer lote; luego B y F; después C, D y G; y finalmente H. Como puedes ver, las transacciones de mayor prioridad están en la parte superior del grafo, es decir, en el extremo izquierdo. A medida que el planificador examina las transacciones en orden descendente, identifica los conflictos. Si una transacción entra en conflicto con otra de mayor prioridad, se crea una arista en el grafo para representar esta dependencia (por ejemplo, C y D entran en conflicto con B).

El nuevo modelo de planificación resuelve varios problemas clave inherentes al enfoque de múltiples iteradores:

  • Coherencia en la gestión de prioridades: El nuevo sistema centraliza la recepción y planificación de transacciones para garantizar que todas se procesen en un orden de prioridad coherente. Esto elimina las variaciones que antes causaban los distintos hilos con diferentes visiones de las prioridades
  • Reducción de los retrasos de procesamiento: El prio-graph garantiza que sea muy probable que los lotes preparados para su ejecución se completen sin conflictos de bloqueo, lo que agiliza el procesamiento y evita los retrasos causados por la contención de bloqueos. Observa el uso de la frase “muy probable que se completen”: no es estrictamente cierto que el prio-graph cree lotes que no puedan fallar por bloqueos, ya que podrían entrar en conflicto con los hilos de voto, aunque este es un caso extremo muy poco frecuente
  • Escalabilidad y flexibilidad: El diseño del nuevo planificador permite aumentar la cantidad de hilos sin las preocupaciones anteriores sobre el incremento de conflictos de bloqueo. Esto es posible gracias a la vista centralizada de los bloqueos y a una distribución más controlada de las transacciones entre los trabajadores 

Se espera que la introducción del planificador central en la versión 1.18 mejore considerablemente la gestión de transacciones y reduzca la complejidad y la sobrecarga del sistema anterior. Es probable que esto acelere el procesamiento de transacciones, aumente el rendimiento y haga que la red sea más estable. Debido a los retrasos en el lanzamiento de la versión 1.18, el planificador ha mejorado desde su creación. Por ejemplo, la verificación previa a la compilación de las transacciones se trasladó a los hilos de trabajo para mejorar la eficiencia. Además, los límites de CU ahora son más razonables, con proporciones estimadas/reales mucho menores que las del planificador anterior. El nuevo planificador ahora puede usar CU para limitar las colas de trabajo programadas y evitar que se acumule trabajo excesivo por conflictos entre cuentas.

Ten en cuenta que el planificador central no está activado de forma predeterminada y debe habilitarse con el nuevo indicador --block-production-method central-scheduler al iniciar un validador. Por ahora, su uso es opcional, pero se convertirá en el planificador predeterminado en versiones futuras. También puedes habilitar el planificador anterior con el indicador --block-production-method thread-local-multi-iterator (está activado de forma predeterminada, pero no lo uses en versiones futuras: el planificador central es mucho más eficiente y resuelve los problemas del planificador anterior).

Un cálculo de prioridad más eficaz 

La versión 1.18 también perfecciona la forma de determinar la prioridad de las transacciones, lo que hace que el proceso sea más equitativo y eficiente en cuanto al uso de recursos y la recuperación de costos. Antes, la priorización se basaba principalmente en la prioridad del presupuesto de cómputo, lo que a veces generaba precios poco óptimos para las unidades de cómputo. Esto ocurría porque la priorización no consideraba adecuadamente las comisiones base recaudadas, lo que podía infravalorar los recursos y afectar la eficiencia operativa de la red.

El nuevo enfoque ajusta el cálculo de prioridad de las transacciones para considerar las comisiones y los costos asociados mediante la fórmula Prioridad = Comisiones / (Costo + 1). Aquí, las comisiones representan las comisiones asociadas a una transacción determinada, mientras que el costo representa el consumo de recursos y cómputo determinado por el modelo de costos de Solana. Agregar “1” al denominador es una medida de seguridad para evitar la división entre cero. 

Podemos desglosar aún más la fórmula para hacer que Comisiones y Costo sean más explícitos:

Ahora, el costo de una transacción se calcula de forma integral y considera todos los costos operativos y de cómputo asociados. Esto garantiza que los cálculos de prioridad reflejen el consumo real de recursos de una transacción. Por lo tanto, los desarrolladores y usuarios recibirán una prioridad mayor si solicitan menos unidades de cómputo. También significa que las transferencias simples, sin comisiones de prioridad, tendrán cierta prioridad en la cola.

Despliegue de programas mejorado

La versión 1.18 también mejora considerablemente los despliegues de programas en cuanto a confiabilidad del despliegue y eficiencia de ejecución. 

La nueva actualización resuelve un problema por el que los programas desplegados en el último slot de una época no aplicaban correctamente los cambios del entorno de ejecución previstos para la época siguiente. Por lo tanto, un programa desplegado durante este periodo de transición usaba por error el entorno de ejecución anterior. La versión 1.18 ajusta el proceso de despliegue para garantizar que el entorno de ejecución de cualquier programa desplegado al final de una época coincida con el de la época siguiente.

La versión 1.18 también resuelve la imposibilidad de establecer un precio o límite de unidades de cómputo en las transacciones de despliegue al agregar el indicador --with-compute-unit-price a los comandos de despliegue de programas de la CLI. Este indicador se puede usar con los comandos solana program deploy y solana program write-buffer. El límite de unidades de cómputo se establece mediante la simulación de cada tipo de transacción de despliegue y se fija en la cantidad de unidades de cómputo consumidas.  

Otra mejora importante afecta la forma de gestionar los blockhashes en despliegues de programas grandes. Antes de la versión 1.18, las transacciones enviadas con sign_all_messages_and_send se limitaban a 100 TPS. En programas más grandes, la cantidad de transacciones de despliegue puede llegar a miles. Esto significa que las transacciones podían retrasarse y correr el riesgo de usar blockhashes vencidos, ya que muchas de ellas se retrasaban más de 10 segundos. La versión 1.18 retrasa la firma de las transacciones de despliegue con un blockhash reciente hasta después de la demora de limitación. Ahora, los blockhashes se actualizan cada 5 segundos, por lo que los despliegues con más de 500 transacciones se beneficiarán del uso de un blockhash más reciente.

Además, la versión 1.18 mejora la forma en que la red gestiona los despliegues de programas y verifica las transacciones. Antes, algunos programas se marcaban incorrectamente como FailedVerification debido a errores al identificar el estado de las cuentas. Esto podía etiquetar de forma errónea programas que en realidad no habían fallado ninguna comprobación. Ahora, estos programas se identifican correctamente como Closed si no deben estar activos. Este cambio garantiza que solo los programas problemáticos se marquen para una nueva comprobación y ayuda a evitar verificaciones repetidas innecesarias.

También se perfeccionó el proceso para actualizar los estados de los programas. Ahora, los programas pueden pasar de un estado Closed a uno activo dentro del mismo slot en el que se despliegan. Esto permite que entren en funcionamiento de forma más rápida y confiable, algo fundamental durante los periodos de alta demanda. Sin embargo, es importante señalar que esta mejora sigue sujeta al periodo de espera de un slot para cancelar, repetir o realizar un despliegue, así como al retraso de visibilidad de un slot. Por lo tanto, aunque estos ajustes ayudan a gestionar la carga de la red de manera más eficaz y evitan ciertos tipos de congestión, no cambian de forma significativa el flujo de trabajo de los desarrolladores de dApps.

“El parche de congestión”: mejor gestión de la congestión

La versión 1.18.11 de Testnet, anunciada como “El parche de congestión”, propuso cambios para resolver la congestión reciente de Solana. Ten en cuenta que esta versión no es exclusiva de la 1.18 y que se adaptó de forma retroactiva a la 1.17.31. Aun así, es fundamental hablar de ella.

El gran cambio es que QUIC ahora trata a los pares con un stake extremadamente bajo como pares sin stake en la calidad de servicio ponderada por stake (SWQoS). Esto se hizo porque los nodos con un stake muy pequeño podían abusar del sistema para obtener una cantidad desproporcionada de ancho de banda. Además, las métricas existentes no permitían determinar la proporción de paquetes enviados y limitados provenientes de nodos con stake frente a nodos sin stake. Por eso, se agregaron estas métricas para ofrecer mayor visibilidad. También se optimizó la gestión de los fragmentos de paquetes al sustituir instancias de vec por smallvec, lo que ahorra una asignación por paquete. Esto es posible porque los streams tienen el tamaño de un paquete, por lo que se esperan pocos. 

Antes, en la etapa bancaria, todos los paquetes se reenviaban al siguiente nodo. Sin embargo, la versión 1.18 cambia esto para que solo se reenvíen los paquetes de nodos con stake. Esta actualización hace que las conexiones con stake sean más importantes que nunca, ya que tienen mayor peso al calcular la prioridad y reenviar transacciones.

Documentación mejorada

La actualización 1.18 también mejora considerablemente la compatibilidad con traducciones de la documentación oficial de Solana para hacerla más accesible a un público global. Las actualizaciones incluyen mejoras en la CLI y la configuración de Crowdin, lo que agiliza la sincronización de documentos entre idiomas, y la introducción de un nuevo comando serve para mejorar las pruebas locales mediante Docusaurus. La documentación también mejora la gestión del contenido estático al vincular los archivos PDF directamente con blobs de GitHub para evitar problemas con las rutas relativas en las compilaciones traducidas.

Para los desarrolladores, el proceso de contribución a las traducciones se aclara con un README actualizado que explica cómo gestionar problemas comunes, como las variables de entorno necesarias y los errores de compilación habituales. Esto se complementa con mejoras en el flujo de integración continua, que ahora solo incluye traducciones en las compilaciones del canal estable. De este modo, únicamente la documentación revisada y estable llega a los usuarios finales. Estos cambios buscan simplificar las contribuciones, mejorar la calidad de la documentación oficial y brindar a todos los usuarios acceso a información confiable y precisa.

Conclusión

Impulsada por Anza, la actualización 1.18 mejora considerablemente la gestión de transacciones, los cálculos de prioridad, los despliegues de programas, la documentación oficial y el rendimiento general de la red. Con la introducción de un planificador central y diversas correcciones para resolver la congestión reciente, Solana está mejor preparada para gestionar los picos de carga y garantizar un funcionamiento eficiente y confiable de la red. Solana es la mejor oportunidad para lograr una blockchain escalable, y esta actualización confirma su potencial.

Si llegaste hasta aquí, ¡gracias, anon! Asegúrate de ingresar tu dirección de correo electrónico a continuación para no perderte ninguna novedad de Solana. ¿Quieres profundizar más? Explora los artículos más recientes del blog de Helius y continúa hoy mismo tu recorrido por Solana.

Recursos adicionales

Suscríbete a Helius

Mantente al día con las novedades del desarrollo en Solana y recibe actualizaciones cuando publiquemos

Imagen ampliada