From baf8f080fed65fc0df42dc6712ec5a8fbd776ed5 Mon Sep 17 00:00:00 2001 From: pablomendezroyo Date: Wed, 18 Dec 2024 09:39:04 +0100 Subject: [PATCH] Remove exited validators once a day --- packages/brain/src/index.ts | 4 +- packages/brain/src/modules/cron/index.ts | 5 ++ .../cron/removeExitedValidators/index.ts | 54 +++++++++++++++++++ .../cron/removeExitedValidators/logPrefix.ts | 1 + 4 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 packages/brain/src/modules/cron/removeExitedValidators/index.ts create mode 100644 packages/brain/src/modules/cron/removeExitedValidators/logPrefix.ts diff --git a/packages/brain/src/index.ts b/packages/brain/src/index.ts index 4e995e4a..717eeb23 100644 --- a/packages/brain/src/index.ts +++ b/packages/brain/src/index.ts @@ -35,7 +35,7 @@ await brainDb.initialize(signerApi, validatorApi); logger.debug(brainDb.data); // CRON -const { reloadValidatorsCronTask } = getCrons({ +const { reloadValidatorsCronTask, removeExitedValidatorsCronTask } = getCrons({ sendNotification: true, postgresClient, prometheusApi, @@ -48,6 +48,7 @@ const { reloadValidatorsCronTask } = getCrons({ dappmanagerApi }); reloadValidatorsCronTask.start(); +removeExitedValidatorsCronTask.start(); //trackValidatorsPerformanceCronTask.start(); // Start server APIs @@ -68,6 +69,7 @@ const { uiServer, launchpadServer, brainApiServer } = getServers({ function handle(signal: string): void { logger.info(`${signal} received. Shutting down...`); reloadValidatorsCronTask.stop(); + removeExitedValidatorsCronTask.stop(); //trackValidatorsPerformanceCronTask.stop(); brainDb.close(); postgresClient.close().catch((err) => logger.error(`Error closing postgres client`, err)); // postgresClient db connection is the only external resource that needs to be closed diff --git a/packages/brain/src/modules/cron/index.ts b/packages/brain/src/modules/cron/index.ts index f55c5a80..0f0b55dc 100644 --- a/packages/brain/src/modules/cron/index.ts +++ b/packages/brain/src/modules/cron/index.ts @@ -9,6 +9,7 @@ import { PrometheusApi } from "../apiClients/prometheus/index.js"; import { PostgresClient } from "../apiClients/postgres/index.js"; import { BeaconchainApi } from "../apiClients/beaconchain/index.js"; import { DappmanagerApi } from "../apiClients/dappmanager/index.js"; +import { removeExitedValidators } from "./removeExitedValidators/index.js"; export const getCrons = ({ sendNotification, @@ -50,6 +51,10 @@ export const getCrons = ({ }), reloadValidatorsCronTask: new CronJob(60 * 1000, () => reloadValidators(signerApi, signerUrl, validatorApi, brainDb) + ), + + removeExitedValidatorsCronTask: new CronJob(60 * 1000 * 60 * 24, () => + removeExitedValidators(brainDb, signerApi, validatorApi, beaconchainApi) ) }; }; diff --git a/packages/brain/src/modules/cron/removeExitedValidators/index.ts b/packages/brain/src/modules/cron/removeExitedValidators/index.ts new file mode 100644 index 00000000..24c72cf8 --- /dev/null +++ b/packages/brain/src/modules/cron/removeExitedValidators/index.ts @@ -0,0 +1,54 @@ +import { BeaconchainApi, ValidatorApi, Web3SignerApi } from "../../apiClients/index.js"; +import { ValidatorStatus } from "../../apiClients/types"; +import { BrainDataBase } from "../../db/index.js"; +import logger from "../../logger/index.js"; + +/** + * Remove the validators with status "exited_slashed" or "withdrawal_done" + */ +export async function removeExitedValidators( + brainDb: BrainDataBase, + signerApi: Web3SignerApi, + validatorApi: ValidatorApi, + beaconchainApi: BeaconchainApi +): Promise { + try { + // get validators from db + const validators = brainDb.getData(); + + // get validators status from beaconchain + const validatorsStatus = await beaconchainApi.postStateValidators({ + stateId: "finalized", + body: { + ids: Object.keys(validators), + statuses: [ValidatorStatus.EXITED_SLASHED, ValidatorStatus.WITHDRAWAL_DONE] + } + }); + + // filter validators with status "exited_slashed" or "withdrawal_done" + const validatorsToRemove = validatorsStatus.data + .filter( + (validator) => + validator.status === ValidatorStatus.EXITED_SLASHED || validator.status === ValidatorStatus.WITHDRAWAL_DONE + ) + .map((validator) => validator.index); + + if (validatorsToRemove.length === 0) { + logger.info("No validators with status 'exited_slashed' or 'withdrawal_done' to remove"); + return; + } + + logger.info( + `Removing validators with status "exited_slashed" or "withdrawal_done": ${validatorsToRemove.join(", ")}` + ); + + // remove validators from the validator API + await validatorApi.deleteRemoteKeys({ pubkeys: validatorsToRemove }); + // remove validators from the signer API + await signerApi.deleteRemoteKeys({ pubkeys: validatorsToRemove }); + // remove validators from the DB + brainDb.deleteValidators(validatorsToRemove); + } catch (e) { + logger.error(`Error removing exited validators: ${e.message}`, e); + } +} diff --git a/packages/brain/src/modules/cron/removeExitedValidators/logPrefix.ts b/packages/brain/src/modules/cron/removeExitedValidators/logPrefix.ts new file mode 100644 index 00000000..34f8e309 --- /dev/null +++ b/packages/brain/src/modules/cron/removeExitedValidators/logPrefix.ts @@ -0,0 +1 @@ +export const logPrefix = "[CRON - removeExitedValidators]: ";