Validator Ejector
Introducción
Ejector es un servicio daemon que monitorea los eventos de ValidatorsExitBusOracle y envía mensajes de salida almacenados cuando es necesario. Permite a los Node Operators generar y firmar mensajes de salida con anticipación, los cuales serán enviados por Ejector cuando el Protocolo solicite realizar una salida.
Al iniciar, carga los mensajes de salida desde una carpeta especificada en forma de archivos individuales .json
y valida su formato, estructura y firma. Luego, carga eventos de una cantidad configurable de bloques finalizados más recientes, verifica si se deben realizar salidas y periódicamente obtiene eventos frescos.
Requisitos
Hardware
- CPU de 2 núcleos
- 1GB de RAM
Nodos
- Nodo de Ejecución - Se requiere un nodo completo
- Nodo de Consenso
Software
Utilizando Docker:
Docker + docker-compose.
Ejecutando directamente o para encriptación de mensajes:
Node.js 16.
Mensajes de Salida
Ejector carga y valida los mensajes de salida al inicio. Esto significa que cualquier cambio en la carpeta de mensajes (por ejemplo, nuevos mensajes de salida) requiere un reinicio de la aplicación para ser detectado.
Ejector acepta mensajes en tres formatos:
Formato Genérico
{
"message": { "epoch": "123", "validator_index": "123" },
"signature": "0x123"
}
Formato de Salida de ethdo
{
"exit": {
"message": { "epoch": "123", "validator_index": "123" },
"signature": "0x123"
},
"fork_version": "0x123"
}
Formato Encriptado
{
"version": 4,
"uuid": "123abc-123abc-123abc",
"path": "",
"pubkey": "",
"crypto": {
"kdf": {
"function": "pbkdf2",
"params": {
"dklen": 123,
"c": 123,
"prf": "hmac-sha256",
"salt": "123abc"
},
"message": ""
},
"checksum": {
"function": "sha256",
"params": {},
"message": "123abc"
},
"cipher": {
"function": "aes-128-ctr",
"params": { "iv": "123abc" },
"message": "123abc"
}
}
}
Encriptación de Mensajes
Se recomienda encarecidamente que después de generar y firmar los mensajes de salida, se encripten para la seguridad del almacenamiento. Ejector descifrará los archivos al inicio buscando la contraseña en la variable de entorno MESSAGES_PASSWORD
.
Los mensajes de salida se encriptan y descifran siguiendo la especificación EIP-2335.
Ejector incluye un pequeño y fácil de usar script de encriptación.
Encriptación usando Ejector - Código Fuente
- Clonar el repositorio:
git clone https://github.com/lidofinance/validator-ejector.git
cd validator-ejector
- Crear el archivo
.env
con la contraseña de encriptación o pasarla antes del comando:
MESSAGES_PASSWORD=password
- Copiar los archivos JSON de mensajes de salida a
encryptor/input
- Ejecutar
yarn & yarn encrypt
- Los archivos de mensajes de salida encriptados se guardarán en
encryptor/output
Encriptación usando Ejector - Docker
Ejector incluye un script de encriptación dentro, por lo que se puede ejecutar usando la misma imagen Docker:
docker run \
-e MESSAGES_PASSWORD=secret \
-v /full/path/to/input:/app/encryptor/input/ \
-v /full/path/to/output:/app/encryptor/output/ \
lidofinance/validator-ejector@sha256:<hash> \
node /app/dist/encryptor/encrypt.js
Puedes encontrar el hash de la versión recomendada aquí.
Para plataformas con una arquitectura diferente pero con soporte de emulación/transpilación como macOS en procesadores M, especifica adicionalmente:
--platform linux/amd64
Variables de Entorno
EXECUTION_NODE
Dirección del Nodo de Ejecución.
CONSENSUS_NODE
Dirección del Nodo de Consenso.
LOCATOR_ADDRESS
Dirección del contrato LidoLocator: Holešky / Mainnet
STAKING_MODULE_ID
ID del contrato StakingRouter: StakingRouter.sol. Actualmente, solo tiene un módulo (NodeOperatorsRegistry), cuyo ID es 1
.
OPERATOR_ID
Puedes encontrar este ID en el Panel de Operadores (#123
en la tarjeta del operador): Holešky / Mainnet.
MESSAGES_LOCATION
Ubicación desde la cual cargar los mensajes de salida en formato .json
.
Cuando se establece, activa el modo de mensajes. No es necesario si estás utilizando Ejector en modo webhook.
Por ejemplo, /messages
en Docker o simplemente messages
si se ejecuta directamente para archivos locales.
También se admite la URL de un bucket de almacenamiento externo para AWS S3 y Google Cloud Storage:
s3://
para S3gs://
para GCS
Configuración de autenticación: GCS, S3.
VALIDATOR_EXIT_WEBHOOK
Endpoint al cual hacer una solicitud cuando se requiere una salida. Permite implementar un enfoque Just-in-Time (JIT) descargando la lógica de salida a un servicio externo y utilizando Ejector como lector seguro de eventos de salida.
Cuando se establece, activa el modo webhook. No es necesario si estás utilizando Ejector en modo mensajes.
En el endpoint, se realizará un POST de JSON con la siguiente estructura:
{
"validatorIndex": "123",
"validatorPubkey": "0x123"
}
Se considerará una salida exitosa si la respuesta es 200, y como fallida si no lo es.
ORACLE_ADDRESSES_ALLOWLIST
Un array JSON de direcciones de oráculos de Lido, de las cuales solo se aceptarán transacciones de informe.
Puedes obtener una lista desde Etherscan en Holešky o Mainnet.
Formato:
["0x123", "0x123"]
MESSAGES_PASSWORD
Contraseña para descifrar los mensajes de salida encriptados al inicio de la aplicación.
MESSAGES_PASSWORD_FILE
Alternativa a MESSAGES_PASSWORD
. Ruta a un archivo con la contraseña dentro para descifrar los mensajes de salida. Si se utiliza, MESSAGES_PASSWORD
(no MESSAGES_PASSWORD_FILE
) debe agregarse a LOGGER_SECRETS
para que se oculte.
BLOCKS_PRELOAD
Cantidad de bloques desde los cuales cargar eventos al iniciar.
Se sugiere incluirlo en tus variables de entorno, pero dejar el valor predeterminado de 50000 (~7 días de bloques).
En caso de una emergencia que requiera que Ejector esté inactivo, este valor puede ajustarse para permitir cargar una cantidad mayor de bloques al inicio.
HTTP_PORT
Puerto para servir métricas y un punto de verificación de salud. El valor predeterminado es 8989.
RUN_METRICS
Habilita con true
para servir métricas de Prometheus: lista completa.
Se servirá en HOST:$HTTP_PORT/metrics
.
Altamente recomendado para monitoreo y alertas.
RUN_HEALTH_CHECK
Habilitado por defecto, deshabilitado con false
. Altamente recomendado para monitorear este endpoint.
Se servirá en HOST:$HTTP_PORT/health
.
LOGGER_LEVEL
Recomendado establecerlo en info
(predeterminado), puede cambiarse a debug
en caso de problemas para facilitar la depuración.
LOGGER_FORMAT
Formato de los logs, por defecto es simple
, pero puede establecerse en json
para que sea fácilmente interpretable por Loki, por ejemplo.
LOGGER_SECRETS
Nombres de variables de entorno o valores exactos que deben reemplazarse en los logs, en formato de array JSON de cadenas.
Se recomienda incluir tu MESSAGES_PASSWORD
, EXECUTION_NODE
, y CONSENSUS_NODE
:
["MESSAGES_PASSWORD", "EXECUTION_NODE", "CONSENSUS_NODE"]
Asegúrate de copiar correctamente las comillas si copias este ejemplo.
DRY_RUN
Permite probar la aplicación con true
sin enviar realmente mensajes de salida.
¡Úsalo con precaución!
Asegúrate de establecerlo en false
o de eliminarlo completamente en producción.
Parámetros Avanzados
Por favor, no los utilices a menos que lo sugiera un contribuidor de Lido.
- BLOCKS_LOOP - 900 (3 horas de bloques) - Cantidad de bloques que Ejector observa en trabajos de sondeo al despertar.
- JOB_INTERVAL - 384000 (1 epoch) - Tiempo que Ejector duerme entre trabajos.
- DISABLE_SECURITY_DONT_USE_IN_PRODUCTION - false - Establecer en
true
para omitir controles de seguridad, por ejemplo, si el contrato de Consenso de Bus de Salida fue cambiado después de que Ejector no pudiera salir de los validadores, por ejemplo, si fue desactivado.
Ejecución
Código Fuente
- Clona el repositorio:
git clone https://github.com/lidofinance/validator-ejector.git
cd validator-ejector
- Crea una carpeta de mensajes de salida, por ejemplo, localmente
mkdir messages
. - Coloca los archivos de mensajes de salida en la carpeta de mensajes.
- Copia el archivo de ejemplo de env:
cp sample.env .env
. - Llena las variables de entorno en el archivo
.env
. - Ejecuta:
yarn
yarn build
yarn start
Docker con docker-compose
- Crea una carpeta raíz para Ejector, y entra en esa carpeta.
- Crea una carpeta de mensajes de salida
mkdir messages
. - Coloca los archivos de mensajes de salida en la carpeta de mensajes.
- Copia el archivo de env:
cp sample.env .env
. - Crea un archivo
docker-compose.yml
utilizando la siguiente plantilla:
https://github.com/lidofinance/validator-ejector/blob/develop/docker-compose.yml
- Ejecuta
docker-compose up
odocker-compose up -d
para iniciar en modo desacoplado (en segundo plano).
Verificación de que Ejector está funcionando
- Asegúrate de que no haya errores en los logs y de que no haya reinicios.
- Verifica que la configuración registrada al inicio sea correcta en los logs.
- Si has colocado mensajes prefirmados en la carpeta de mensajes, asegúrate de que el recuento de mensajes cargados sea mayor que
0
. - Asegúrate de ver líneas como
Job started
yJob finished
en los logs.
Ejemplo de logs de operación correcta:
info: Application started, version 1.0.0 {"EXECUTION_NODE":"<secret>","CONSENSUS_NODE":"<secret>","LOCATOR_ADDRESS":"0x123","STAKING_MODULE_ID":"1","OPERATOR_ID":"0","MESSAGES_LOCATION":"messages","ORACLE_ADDRESSES_ALLOWLIST":["0x123"],"MESSAGES_PASSWORD":"<secret>","BLOCKS_PRELOAD":190000,"BLOCKS_LOOP":64,"JOB_INTERVAL":384000,"HTTP_PORT":8989,"RUN_METRICS":true,"RUN_HEALTH_CHECK":true,"DRY_RUN":false}
info: Loading messages from messages
info: Loaded 123 messages
info: Validating messages
info: Starting, searching only for requests for operator 0
info: Loading initial events for 190000 last blocks
info: Job started {"operatorId":"0","stakingModuleId":"1","loadedMessages":123}
info: Resolved Exit Bus contract address using the Locator {"exitBusAddress":"0x123"}
info: Resolved Consensus contract address {"consensusAddress":"0x123"}
info: Fetched the latest block from EL {"latestBlock":12345}
info: Fetching request events from the Exit Bus {"eventsNumber":190000,"fromBlock":12345,"toBlock":12345}
info
: Loaded ValidatorExitRequest events {"amount":0}
info: Handling ejection requests {"amount":0}
info: Job finished
info: Starting 384 seconds polling for 64 last blocks
¿Qué hacer si algo está mal?
- Asegúrate de que la configuración sea correcta.
- Asegúrate de estar usando el hash SHA o la versión recomendada de la imagen Docker.
- Verifica que los nodos estén sincronizados y funcionando correctamente.
- Reinicia la aplicación.
- Inicia la aplicación con la variable de entorno
LOGGER_LEVEL=debug
y contacta a los desarrolladores de Lido con los logs para investigar el problema.
Recursos Adicionales
Repositorio GitHub de Validator Ejector (Open Source) https://github.com/lidofinance/validator-ejector
Retiros de Lido: Automatización de Salidas de Validador - algunas partes pueden estar desactualizadas https://hackmd.io/@lido/BkxRxAr-o
Especificación de la Lógica de Ejector - algunas partes pueden estar desactualizadas https://hackmd.io/@lido/r1KZ4YNdj