
Plugins de Solana Geyser: transmisión de datos a la velocidad de la luz
Tabla de contenido
- ¿De qué trata este artículo?
- Réplicas de AccountsDB: un enfoque abandonado para la replicación de datos y la carga de RPC
- ¿Qué son los plugins de Solana Geyser?
- La interfaz de plugins de Geyser
- Código fuente
- Declaración del trait
- Método obligatorio
- Métodos proporcionados
- Nota sobre los niveles de compromiso
- Plugins comunes de Solana Geyser
- Crea tu propio plugin de Solana Geyser
- La plantilla de plugins de Solana Geyser
- El administrador de plugins
- Crear un plugin de Geyser desde cero
- Transmisión con Helius Geyser
- Conclusión
- Recursos adicionales
¿De qué trata este artículo?
Los plugins de Geyser son componentes modulares diseñados para transmitir datos sobre cuentas, slots, bloques y transacciones a almacenes de datos externos. Esto permite a los desarrolladores eliminar la carga de RPC (llamada a procedimiento remoto) de un validador. Los plugins de Geyser ofrecen una solución flexible para quienes buscan personalizar sus necesidades de transmisión y procesamiento de datos.
En este artículo, profundizaremos en los detalles de los plugins de Solana Geyser. Comenzaremos explorando las réplicas de AccountsDB, un enfoque propuesto para la replicación de datos y la gestión de carga que finalmente se abandonó en favor de los plugins de Geyser.
Luego explicaremos qué son los plugins de Geyser, cómo funcionan y cómo se estructuran mediante la interfaz de plugins.
A partir de ahí, analizaremos los plugins de Geyser más comunes y te guiaremos por el complejo proceso de crear el tuyo. Por último, hablaremos de Helius y de cómo simplificamos la transmisión de datos en Solana.
Réplicas de AccountsDB: un enfoque abandonado para la replicación de datos y la carga de RPC
Solana exploró varias alternativas para resolver el problema de la elevada carga de RPC y la replicación de datos. Un enfoque prometedor fue usar réplicas de AccountsDB. Estas réplicas se diseñaron para transferir las solicitudes de análisis de cuentas del validador principal a las réplicas de AccountsDB. Aunque era prometedor, el sistema era intrínsecamente complejo y requería un nuevo conjunto de servicios para garantizar la sincronización entre el validador principal y las réplicas. Finalmente, esta propuesta se abandonó en favor del sistema de plugins de Geyser, una solución más sencilla de admitir para el cliente validador y que ofrece a los desarrolladores mayor flexibilidad al implementar sus aplicaciones.
Entonces, ¿qué son exactamente los plugins de Solana Geyser?
¿Qué son los plugins de Solana Geyser?
Los plugins de Solana Geyser ofrecen acceso de baja latencia a los datos de Solana y pueden atender a aplicaciones que eliminan la necesidad de hacer llamadas RPC a los validadores. Por ejemplo, si un validador tuviera que atender numerosas llamadas getProgramAccounts en rápida sucesión, podría quedarse atrás respecto de la red debido a este tráfico intenso.
Los plugins de Geyser resuelven este problema redirigiendo información sobre cuentas, bloques, slots y transacciones a almacenes de datos externos, como bases de datos relacionales, bases de datos NoSQL o Kafka.
Esta redirección de datos permite que los servicios RPC ofrezcan optimizaciones más flexibles y específicas, como almacenamiento en caché e indexación, para quienes buscan obtener datos de estos almacenes externos.
Los plugins de Geyser actúan como puente entre Solana y las soluciones externas de almacenamiento de datos. Permiten que los desarrolladores descarguen de los validadores una parte considerable de las tareas de gestión de datos, lo que mejora el rendimiento y reduce el riesgo de posibles cuellos de botella.
Los plugins de Geyser garantizan que los validadores permanezcan sincronizados con la red, sin importar el volumen de tráfico RPC.
La interfaz de plugins de Geyser
Los desarrolladores pueden crear plugins de Geyser con la interfaz de plugins de Solana Geyser. La interfaz proporciona acceso a cuentas, transacciones, slots, metadatos de bloques y entradas. Se declara en el crate solana-geyser-plugin-interface y se define mediante el trait GeyserPlugin.
El trait define métodos, cada uno con el prefijo update_, que se invocan cuando se crean datos nuevos o se actualizan datos existentes. Los plugins de Geyser también deben especificar su comportamiento durante los procesos de carga y descarga. El trait describe los métodos esenciales que debe implementar un plugin de Geyser para garantizar una transmisión eficiente de datos según el comportamiento deseado del plugin.
Código fuente
pub trait GeyserPlugin:Any +Send +Sync +Debug {
// Required method
fn name(&self) -> &'static str;
// Provided methods
fn on_load(&mut self, _config_file: &str) ->Result<()> { ... }
fn on_unload(&mut self) { ... }
fn update_account(
&self,
account:ReplicaAccountInfoVersions<'_>,
slot: Slot,
is_startup:bool
) ->Result<()> { ... }
fn notify_end_of_startup(&self) ->Result<()> { ... }
fn update_slot_status(
&self,
slot: Slot,
parent:Option,
status:SlotStatus
) ->Result<()> { ... }
fn notify_transaction(
&self,
transaction:ReplicaTransactionInfoVersions<'_>,
slot: Slot
) ->Result<()> { ... }
fn notify_entry(&self, entry:ReplicaEntryInfoVersions<'_>) ->Result<()> { ... }
fn notify_block_metadata(
&self,
blockinfo:ReplicaBlockInfoVersions<'_>
) ->Result<()> { ... }
fn account_data_notifications_enabled(&self) ->bool { ... }
fn transaction_notifications_enabled(&self) ->bool { ... }
fn entry_notifications_enabled(&self) ->bool { ... }
}Declaración del trait
El trait GeyserPlugin funciona como la interfaz base de todos los plugins del ecosistema de Solana Geyser. Se declara como un trait público con los límites de trait Any, Send, Sync y Debug de la biblioteca estándar de Rust. Los límites de trait son los siguientes:
Anypermite la reflexión de tipos, lo que habilita la conversión descendente a un tipo concretoSendindica que la propiedad del tipo que implementa este trait puede transferirse entre hilosSyncimplica que las referencias del tipo que implementa este trait pueden compartirse entre hilosDebugpermite formatear el tipo para su salida, específicamente con fines de depuración
Any e Debug no son muy importantes para nosotros.
Lo que importa de verdad es que GeyserPlugin necesita Send e Sync para que el programa sea seguro entre hilos.
Método obligatorio
fn name(&self) -> &'static str;El método name es obligatorio para cualquier tipo que implemente GeyserPlugin. Este método sirve como identificador del plugin de Geyser. Devuelve un segmento de cadena estático que representa el nombre del plugin de Geyser.
El hecho de que este método y todos los demás, excepto on_load e on_unload, usen &self en lugar de &mut self es una novedad de la actualización 1.16 de Solana. Esto mejora drásticamente el rendimiento porque elimina la necesidad de envolver el plugin de Geyser en un bloqueo de lectura y escritura y obtener un bloqueo de escritura cada vez que llamas a una de sus funciones.
Métodos proporcionados
El trait tiene varios métodos proporcionados que contienen implementaciones predeterminadas, las cuales pueden ser sobrescritas por las implementaciones de GeyserPlugin.
fn on_load(&mut self, _config_file: &str) ->Result<()> { ... }El método on_load es la función de retorno que se invoca cuando el sistema carga un plugin y se utiliza para cualquier inicialización que este requiera. Acepta una referencia a un string que representa la ruta de un archivo de configuración. La configuración debe tener formato JSON5 e incluir un campo libpath que indique la ruta completa de la biblioteca compartida que implementa esta interfaz.
fn on_unload(&mut self) { ... }El método on_unload es una función de retorno que se invoca para realizar cualquier limpieza antes de que el sistema descargue un plugin.
fn update_account(
&self,
account:ReplicaAccountInfoVersions<'_>,
slot: Slot,
is_startup:bool
) ->Result<()> { ... }El método update_account se llama cuando se actualiza una cuenta en el nivel de confirmación procesado, algo que puede ocurrir varias veces dentro de un slot. Aquí es fundamental hacer seguimiento de los slots que se confirman para obtener las actualizaciones de cuenta que se incorporan a la cadena canónica.
La estructura ReplicaAccountInfoVersions contiene los metadatos y los datos de la cuenta transmitida.
El parámetro slot apunta al slot en el que se actualiza la cuenta.
Cuando is_startup es verdadero, indica que la cuenta se carga desde instantáneas al iniciar el validador. Cuando is_startup es falso, la cuenta se actualiza durante el procesamiento de transacciones.
fn notify_end_of_startup(&self) ->Result<()> { ... }El método notify_end_of_startup se invoca para señalar el final de la fase de inicio. Esto ocurre cuando el validador restauró la base de datos de cuentas desde instantáneas y todas las cuentas se actualizaron según corresponde.
fn update_slot_status(
&self,
slot: Slot,
parent:Option,
status:SlotStatus
) ->Result<()> { ... }El método update_slot_status se llama cuando se actualiza el estado de un slot. Acepta un Slot, un Option<u64> para el slot principal y una instancia de SlotStatus enum.
SlotStatus define los tres estados de un slot en Solana:
Processed: el slot más alto en el que trabajó el nodo. Aunque el slot no está confirmado ni finalizado, forma parte de la cadena que el validador considera con más probabilidades de volverse canónicaConfirmed: el slot recibió suficientes votos para considerarse seguro y parte de la cadena. Este slot cuenta con el respaldo de una supermayoría de los validadores de SolanaRooted: el slot ahora forma parte permanente de la blockchain y todas las demás versiones o bifurcaciones de la cadena deben construirse sobre este slot. Esto significa que todas las ramas de la red descienden de este bloque
fn notify_transaction(
&self,
transaction:ReplicaTransactionInfoVersions<'_>,
slot: Slot
) ->Result<()> { ... }El método notify_transaction se llama cuando se procesa una transacción en un slot e informa al plugin los detalles de la transacción.
ReplicaTransactionInfoVersions es un contenedor enum que administra ReplicaTransactionInfo. Si cambiara la estructura de RepicaTransactionInfo, habría una nueva entrada enum para la versión más reciente. Esto obligaría a las implementaciones del plugin a gestionar el cambio admitiendo una nueva entrada de enum. Actualmente, enum contiene dos variantes:
V0_0_1(&'a ReplicaTransactionInfo<'a>)V0_0_2(&'a ReplicaTransactionInfoV2<'a>)
pub struct ReplicaTransactionInfo<'a> {
pub signature: &'a Signature,
pub is_vote: bool,
pub transaction: &'a SanitizedTransaction,
pub transaction_status_meta: &'a TransactionStatusMeta,
}
pub struct ReplicaTransactionInfoV2<'a> {
pub signature: &'a Signature,
pub is_vote: bool,
pub transaction: &'a SanitizedTransaction,
pub transaction_status_meta: &'a TransactionStatusMeta,
pub index: usize,
}La principal diferencia entre las variantes es que la segunda almacena el índice de la transacción en el bloque.
fn notify_entry(&self, entry:ReplicaEntryInfoVersions<'_>) ->Result<()> { ... }notify_entry notifica al plugin de una nueva entrada. Acepta una instancia de ReplicaEntryInfoVersions, que es un contenedor diseñado para mantener la compatibilidad futura con la gestión de ReplicaEntryInfo. Actualmente contiene la variante V0_0_1(&'a ReplicaEntryInfo<'a>).
Esta variante es una estructura que contiene información sobre el slot de la entrada, su índice en el bloque, el número de hashes desde la entrada anterior, el hash SHA-256 de la entrada y el número de transacciones ejecutadas en ella.
fn notify_block_metadata(
&self,
blockinfo:ReplicaBlockInfoVersions<'_>
) ->Result<()> { ... }El método notify_block_metadata se llama cuando se actualizan los metadatos de un bloque. Acepta una instancia de ReplicaBlockInfoVersions enum para la información del bloque. Este enum es un contenedor para las distintas versiones de ReplicaBlockInfo, que incluyen información sobre el bloque, como su slot, hash, recompensas, hora del bloque, altura del bloque, etc.
fn account_data_notifications_enabled(&self) ->bool { ... }
fn transaction_notifications_enabled(&self) ->bool { ... }
fn entry_notifications_enabled(&self) ->bool { ... }Estos métodos devuelven valores booleanos que indican si el plugin desea habilitar notificaciones para datos de cuentas, transacciones y entradas, respectivamente.
Nota sobre los niveles de compromiso
Geyser envía de inmediato las actualizaciones de datos de cuentas y transacciones en cuanto se procesan. Esto beneficia la velocidad de indexación integral. Sin embargo, existe el riesgo de que se omita un slot procesado.
Un slot omitido es un slot anterior que no produjo un bloque, ya sea porque el líder estaba desconectado o porque se abandonó la bifurcación que contenía el slot en favor de una alternativa mejor. Es fundamental que los sistemas de almacenamiento de datos que reciben la transmisión reconozcan esta posibilidad y gestionen las actualizaciones según corresponda.
Plugins comunes de Solana Geyser
Existe una amplia variedad de plugins de Solana Geyser que los desarrolladores pueden usar e incluso bifurcar para satisfacer sus necesidades específicas. Algunos plugins destacados son:
PostgreSQL Plugin: para administrar y consultar datos con PostgreSQLgRPC Service Streaming Plugin: para transmitir actualizaciones de cuentas de Solana a un servicio gRPCRabbitMQ Producer Plugin: para facilitar las colas de mensajes con RabbitMQKafka Producer Plugin: para transmitir datos con KafkaAmazon SQS Plugin: para crear colas de mensajes que aprovechan Simple Queue Service de AmazonGoogle BigTable Plugin: para administrar y consultar datos con Google BigTable
Estos plugins pueden adaptarse a una gran variedad de casos de uso.
Por ejemplo, Clockwork utilizó un plugin de Geyser para programar transacciones y crear programas de Solana automatizados y orientados a eventos. Aunque el proyecto finalizó, su código abierto sigue siendo un recurso valioso que puedes consultar en su GitHub.
Otros posibles casos de uso incluyen emplear plugins de Geyser para monitorear los saldos de cuentas en una plataforma DeFi, proporcionar métricas sobre el estado de la red o monitorear eventos de la cadena de suministro en tiempo real.
Crea tu propio plugin de Solana Geyser
Estos son algunos recursos y componentes para crear tu propio plugin:
La plantilla de plugins de Solana Geyser
La plantilla de plugins de Solana Geyser es el recurso más sencillo para comenzar a desarrollar plugins de Solana Geyser. Esta plantilla minimalista registra las interacciones entre el administrador de plugins y el propio plugin. Es un excelente punto de partida para familiarizarte con el flujo de trabajo de los plugins y las técnicas de depuración.
El administrador de plugins
El administrador de plugins es el componente principal que dirige el ciclo de vida y las interacciones de todos los plugins de Geyser. Puede cargar y descargar plugins de forma dinámica durante la ejecución, lo que ofrece mayor flexibilidad y modularidad.
Durante la ejecución, el administrador de plugins pasa la ruta del archivo de configuración a tu plugin. Esto permite usar ajustes personalizables en los plugins de Geyser que pueden modificarse sin cambiar el código del plugin.
Para integrar un plugin en un validador, debes especificar la ruta de la biblioteca dinámica mediante el parámetro --geyser-plugin-config. Esto indica al validador dónde encontrar el plugin y su configuración asociada.
Como mínimo, el archivo de configuración debe estar en formato JSON y contener la ruta de la biblioteca dinámica del plugin de Geyser: .so en Linux. Un archivo de configuración mínimo se vería así:
{
"libpath": "/.so"
}Crear un plugin de Geyser desde cero
Si quieres tomar un camino menos explorado y crear tu propio plugin de Geyser sin usar la plantilla ni modificar un plugin existente, debes programarlo con la interfaz de plugins de Geyser.
Un plugin debe implementar el trait GeyserPlugin para funcionar con el entorno de ejecución. Además, la biblioteca dinámica debe exportar una función “C” _create_plugin que cree la implementación del plugin.
Un ejemplo sería crear un plugin de webhook que implemente el trait GeyserPlugin:
#[no_mangle]
#[allow(improper_ctypes_definitions)]
/// # Safety
///
/// This function returns the WebhookPlugin pointer as trait GeyserPlugin.
pub unsafe extern "C" fn _create_plugin() -> *mut dyn GeyserPlugin {
let plugin = WebhookPlugin::new();
let plugin: Box = Box::new(plugin);
Box::into_raw(plugin)
}Aquí creamos una función pública no segura que usa la convención de llamadas de C, extern "C", lo que la hace compatible con C y otros lenguajes. La propia función fn _create*_*plugin() -> *mut dyn GeyserPlugin devuelve un puntero sin procesar mutable a un dynGeyserPlugin, que es el trait GeyserPlugin. El cuerpo de la función crea una nueva instancia de WebhookPlugin, encapsula esta instancia como un objeto de trait y luego convierte el objeto encapsulado en un puntero sin procesar para que la función pueda devolverlo.
Por lo tanto, los pasos para crear tu propio plugin de Geyser son los siguientes:
- Crea tu plugin de modo que implemente la interfaz de plugins de Solana Geyser
- Obtén la biblioteca dinámica (archivo
.so) de la carpetatarget/releaseotarget/debug - Crea un archivo
geyser-config.json, que debe contener la ruta de la biblioteca dinámica del plugin de Geyser en un campo “libpath” - Inicia tu validador con la marca
--geyser-plugin-config geyser-config.json
Estos pasos parecen bastante sencillos. Sin embargo, ejecutar y mantener un plugin de Solana Geyser puede ser un proceso bastante arduo.
Transmisión con Helius Geyser
Helius es reconocido por ofrecer una experiencia para desarrolladores sin igual en Solana. Su enfoque exclusivo en Solana le ha permitido acumular una amplia experiencia al superar diversos desafíos y facilitar numerosas integraciones a gran escala. Helius está en una posición única para resolver cualquier problema que pueda enfrentar un desarrollador.
En Helius, administramos plugins de Geyser para varios equipos de alto rendimiento del ecosistema de Solana. Operamos clústeres especializados de Geyser con redundancia y tolerancia a fallos adicionales para que nunca tengas que preocuparte por la pérdida de datos ni por el tiempo de inactividad. Nuestro acceso programático mediante API te permite modificar tus plugins de Geyser de forma dinámica sin tener que preocuparte por la confiabilidad. Administrar plugins de Geyser suele ser una tarea abrumadora, ya que eres responsable de garantizar la coherencia, confiabilidad y disponibilidad de los datos. ¿Por qué no dejar que Helius lo haga por ti?
Si te interesa la transmisión con Geyser, solicita un nodo dedicado desde tu panel de Helius o contáctanos en Discord para comenzar hoy mismo.
Conclusión
¡Felicidades!
En este artículo, exploramos las complejidades de la replicación de datos y la gestión de carga de RPC mediante el análisis de los plugins de Solana Geyser. Entender este sistema no es fácil: es una arquitectura sofisticada con muy poca documentación, pero ofrece numerosas oportunidades de personalización y optimización del rendimiento para los desarrolladores de Solana.
El conocimiento adquirido en este artículo es invaluable, especialmente si eres un desarrollador o formas parte de un equipo que busca crear o administrar aplicaciones de alto rendimiento en Solana. Es fundamental comprender los plugins de Geyser, ya que ofrecen una solución escalable y confiable para el ecosistema de Solana.
Si llegaste hasta aquí, anónimo, ¡gracias!
Recursos adicionales
Artículos relacionados
Suscríbete a Helius
Mantente al día con las novedades del desarrollo en Solana y recibe actualizaciones cuando publiquemos


