From 01b32cbfc622cccc8d098305480872574f7d6f5b Mon Sep 17 00:00:00 2001 From: chad Date: Thu, 16 Feb 2023 19:18:03 -0500 Subject: [PATCH 01/20] Fix log validator index, status and pubkey each epoch (#4785) --- packages/validator/src/services/indices.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/validator/src/services/indices.ts b/packages/validator/src/services/indices.ts index eead12c70aef..e6c7d2d8b629 100644 --- a/packages/validator/src/services/indices.ts +++ b/packages/validator/src/services/indices.ts @@ -76,6 +76,14 @@ export class IndicesService { private async pollValidatorIndicesInternal(pubkeysHex: PubkeyHex[]): Promise { const pubkeysHexToDiscover = pubkeysHex.filter((pubkey) => !this.pubkey2index.has(pubkey)); + pubkeysHex.forEach((pubkey) => { + if (this.pubkey2index.has(pubkey)) { + this.logger.info("Validator status: ", {status: "active"}); + this.logger.info("Validator index: ", {index: this.pubkey2index.get(pubkey)}); + this.logger.info("Validator pubkey: ", {pubkey}); + } + }); + if (pubkeysHexToDiscover.length === 0) { return []; } From a7a778d06e23d18ea390a5082dcb11a9399e7838 Mon Sep 17 00:00:00 2001 From: chad Date: Fri, 17 Feb 2023 12:09:17 -0500 Subject: [PATCH 02/20] Update validator to display correct status and pubkey each epoch (#4785) --- packages/validator/src/services/indices.ts | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/packages/validator/src/services/indices.ts b/packages/validator/src/services/indices.ts index e6c7d2d8b629..21f6f80a2cbf 100644 --- a/packages/validator/src/services/indices.ts +++ b/packages/validator/src/services/indices.ts @@ -76,14 +76,6 @@ export class IndicesService { private async pollValidatorIndicesInternal(pubkeysHex: PubkeyHex[]): Promise { const pubkeysHexToDiscover = pubkeysHex.filter((pubkey) => !this.pubkey2index.has(pubkey)); - pubkeysHex.forEach((pubkey) => { - if (this.pubkey2index.has(pubkey)) { - this.logger.info("Validator status: ", {status: "active"}); - this.logger.info("Validator index: ", {index: this.pubkey2index.get(pubkey)}); - this.logger.info("Validator pubkey: ", {pubkey}); - } - }); - if (pubkeysHexToDiscover.length === 0) { return []; } @@ -116,6 +108,15 @@ export class IndicesService { this.pubkey2index.set(pubkeyHex, validatorState.index); this.index2pubkey.set(validatorState.index, pubkeyHex); newIndices.push(validatorState.index); + } else { + this.logger.info( + "Validator status: ", + {status: validatorState.status || "unknown"}, + "index: ", + {index: this.pubkey2index.get(pubkeyHex)}, + "pubkey: ", + {pubkeyHex} + ); } } return newIndices; From fe09b0d261f4d0a13b3c3c0d0bb99314b37a5749 Mon Sep 17 00:00:00 2001 From: chad Date: Fri, 17 Feb 2023 12:17:30 -0500 Subject: [PATCH 03/20] Fix update log info formatting for validator status (#4785) --- packages/validator/src/services/indices.ts | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/packages/validator/src/services/indices.ts b/packages/validator/src/services/indices.ts index 21f6f80a2cbf..512cdb370872 100644 --- a/packages/validator/src/services/indices.ts +++ b/packages/validator/src/services/indices.ts @@ -110,12 +110,10 @@ export class IndicesService { newIndices.push(validatorState.index); } else { this.logger.info( - "Validator status: ", - {status: validatorState.status || "unknown"}, - "index: ", - {index: this.pubkey2index.get(pubkeyHex)}, - "pubkey: ", - {pubkeyHex} + `Validator: + status=${validatorState.status || "unknown"} + index=${this.pubkey2index.get(pubkeyHex)} + pubkey=${pubkeyHex}` ); } } From b4eac94e6851c2f87a320c884f3ea7bcd6b51824 Mon Sep 17 00:00:00 2001 From: chad Date: Tue, 21 Feb 2023 20:47:22 -0500 Subject: [PATCH 04/20] Update logs to include total validator availability count (#4785) --- packages/validator/src/services/indices.ts | 28 +++++++++++++------ .../src/services/prepareBeaconProposer.ts | 19 +++++++++---- 2 files changed, 33 insertions(+), 14 deletions(-) diff --git a/packages/validator/src/services/indices.ts b/packages/validator/src/services/indices.ts index 512cdb370872..216ebbedcfde 100644 --- a/packages/validator/src/services/indices.ts +++ b/packages/validator/src/services/indices.ts @@ -2,6 +2,7 @@ import {ValidatorIndex} from "@lodestar/types"; import {ILogger} from "@lodestar/utils"; import {toHexString} from "@chainsafe/ssz"; import {Api, ApiError} from "@lodestar/api"; +import {ValidatorResponse, ValidatorStatus} from "@lodestar/api/lib/beacon/routes/beacon/state.js"; import {batchItems} from "../util/index.js"; import {Metrics} from "../metrics.js"; @@ -90,7 +91,6 @@ export class IndicesService { newIndices.push(...validatorIndicesArr); } - this.logger.info("Discovered new validators", {count: newIndices.length}); this.metrics?.discoveredIndices.inc(newIndices.length); return newIndices; @@ -101,22 +101,34 @@ export class IndicesService { ApiError.assert(res, "Can not fetch state validators from beacon node"); const newIndices = []; + + const allValidators = new Map(); + for (const validatorState of res.response.data) { + // Group all validators by status + allValidators.set(validatorState.status, [validatorState]); + const pubkeyHex = toHexString(validatorState.validator.pubkey); if (!this.pubkey2index.has(pubkeyHex)) { this.logger.debug("Discovered validator", {pubkey: pubkeyHex, index: validatorState.index}); this.pubkey2index.set(pubkeyHex, validatorState.index); this.index2pubkey.set(validatorState.index, pubkeyHex); newIndices.push(validatorState.index); - } else { - this.logger.info( - `Validator: - status=${validatorState.status || "unknown"} - index=${this.pubkey2index.get(pubkeyHex)} - pubkey=${pubkeyHex}` - ); } } + + allValidators.get("active")?.forEach((validatorState: ValidatorResponse) => { + this.logger.info("Validator activated", { + pubkey: toHexString(validatorState.validator.pubkey), + index: validatorState.index, + }); + }); + + this.logger.info("Initialized Validators: ", { + total: allValidators.size, + available: allValidators.get("active")?.length, + }); + return newIndices; } } diff --git a/packages/validator/src/services/prepareBeaconProposer.ts b/packages/validator/src/services/prepareBeaconProposer.ts index dcc9eff29f4e..7179c00a4534 100644 --- a/packages/validator/src/services/prepareBeaconProposer.ts +++ b/packages/validator/src/services/prepareBeaconProposer.ts @@ -1,8 +1,9 @@ import {Epoch, bellatrix} from "@lodestar/types"; -import {Api, ApiError, routes} from "@lodestar/api"; +import {Api, ApiError} from "@lodestar/api"; import {IBeaconConfig} from "@lodestar/config"; import {SLOTS_PER_EPOCH} from "@lodestar/params"; +import {ProposerPreparationData} from "@lodestar/api/lib/beacon/routes/validator.js"; import {IClock, ILoggerVc, batchItems} from "../util/index.js"; import {Metrics} from "../metrics.js"; import {ValidatorStore} from "./validatorStore.js"; @@ -37,13 +38,19 @@ export function pollPrepareBeaconProposer( const indicesChunks = batchItems(validatorStore.getAllLocalIndices(), {batchSize: REGISTRATION_CHUNK_SIZE}); for (const indices of indicesChunks) { + const proposers: ProposerPreparationData[] = []; try { - const proposers = indices.map( - (index): routes.validator.ProposerPreparationData => ({ + indices.forEach((index) => { + const feeRecipient = validatorStore.getFeeRecipientByIndex(index); + const pubKey = validatorStore.getPubkeyOfIndex(index); + + proposers.push({ validatorIndex: String(index as number), - feeRecipient: validatorStore.getFeeRecipientByIndex(index), - }) - ); + feeRecipient, + }); + + logger.info("Validator exists in Beacon Chain", {validatorIndex: index, feeRecipient, pubKey}); + }); ApiError.assert(await api.validator.prepareBeaconProposer(proposers)); } catch (e) { logger.error("Failed to register proposers with beacon", {epoch}, e as Error); From 1014495005fa06c09048b04d3d315634199e0527 Mon Sep 17 00:00:00 2001 From: chad Date: Tue, 21 Feb 2023 21:27:00 -0500 Subject: [PATCH 05/20] Extracted logging to a function and included all validator statuses (#4785) --- packages/validator/src/services/indices.ts | 45 ++++++++++++++++++---- 1 file changed, 37 insertions(+), 8 deletions(-) diff --git a/packages/validator/src/services/indices.ts b/packages/validator/src/services/indices.ts index 1327faaa2de3..9084ad3804c3 100644 --- a/packages/validator/src/services/indices.ts +++ b/packages/validator/src/services/indices.ts @@ -117,18 +117,47 @@ export class IndicesService { } } - allValidators.get("active")?.forEach((validatorState: ValidatorResponse) => { - this.logger.info("Validator activated", { + logValidatorStatuses(allValidators, this.logger); + + return newIndices; + } +} + +function logValidatorStatuses(allValidators: Map, logger: Logger): void { + allValidators.get("active")?.forEach((validatorState: ValidatorResponse) => { + logger.info("Validator activated", { + pubkey: toHexString(validatorState.validator.pubkey), + index: validatorState.index, + }); + }); + + [...(allValidators.get("pending_initialized") ?? []), ...(allValidators.get("pending_queued") ?? [])]?.forEach( + (validatorState: ValidatorResponse) => { + logger.info("Validator pending", { pubkey: toHexString(validatorState.validator.pubkey), index: validatorState.index, }); - }); + } + ); - this.logger.info("Initialized Validators: ", { - total: allValidators.size, - available: allValidators.get("active")?.length, + allValidators.get("withdrawal_done")?.forEach((validatorState: ValidatorResponse) => { + logger.info("Validator withdrawn", { + pubkey: toHexString(validatorState.validator.pubkey), + index: validatorState.index, }); + }); - return newIndices; - } + [...(allValidators.get("exited_slashed") ?? []), ...(allValidators.get("exited_unslashed") ?? [])]?.forEach( + (validatorState: ValidatorResponse) => { + logger.info("Validator Exited", { + pubkey: toHexString(validatorState.validator.pubkey), + index: validatorState.index, + }); + } + ); + + logger.info("Initialized Validators: ", { + total: allValidators.size, + available: allValidators.get("active")?.length, + }); } From f1f0e36265ebe457d6230f080db1100f2ecf954b Mon Sep 17 00:00:00 2001 From: chad Date: Wed, 22 Feb 2023 11:55:51 -0500 Subject: [PATCH 06/20] Refactor to print logs more efficiently (#4785) --- packages/validator/src/services/indices.ts | 57 +++++++++---------- .../src/services/prepareBeaconProposer.ts | 4 +- 2 files changed, 28 insertions(+), 33 deletions(-) diff --git a/packages/validator/src/services/indices.ts b/packages/validator/src/services/indices.ts index 9084ad3804c3..9399c9c5ee72 100644 --- a/packages/validator/src/services/indices.ts +++ b/packages/validator/src/services/indices.ts @@ -1,8 +1,7 @@ import {ValidatorIndex} from "@lodestar/types"; import {Logger} from "@lodestar/utils"; import {toHexString} from "@chainsafe/ssz"; -import {Api, ApiError} from "@lodestar/api"; -import {ValidatorResponse, ValidatorStatus} from "@lodestar/api/lib/beacon/routes/beacon/state.js"; +import {Api, ApiError, ValidatorResponse, ValidatorStatus} from "@lodestar/api"; import {batchItems} from "../util/index.js"; import {Metrics} from "../metrics.js"; @@ -124,40 +123,36 @@ export class IndicesService { } function logValidatorStatuses(allValidators: Map, logger: Logger): void { - allValidators.get("active")?.forEach((validatorState: ValidatorResponse) => { - logger.info("Validator activated", { - pubkey: toHexString(validatorState.validator.pubkey), - index: validatorState.index, - }); - }); - - [...(allValidators.get("pending_initialized") ?? []), ...(allValidators.get("pending_queued") ?? [])]?.forEach( - (validatorState: ValidatorResponse) => { - logger.info("Validator pending", { - pubkey: toHexString(validatorState.validator.pubkey), - index: validatorState.index, - }); - } - ); - - allValidators.get("withdrawal_done")?.forEach((validatorState: ValidatorResponse) => { - logger.info("Validator withdrawn", { + const loggedValidatorStates: {[key: string]: ValidatorStatus[]} = { + "Validator activated": ["active"], + "Validator pending": ["pending_initialized", "pending_queued"], + "Validator withdrawn": ["withdrawal_done"], + "Validator exited": ["exit_slashed", "exit_unslashed"], + }; + + const logFormatter = (message: string, validatorState: ValidatorResponse): void => { + logger.info(message, { pubkey: toHexString(validatorState.validator.pubkey), index: validatorState.index, }); + }; + Object.keys(loggedValidatorStates).map((key) => { + getValidatorStatesByStatuses(loggedValidatorStates[key], allValidators).forEach( + (validatorState: ValidatorResponse) => { + logFormatter(key, validatorState); + } + ); }); - [...(allValidators.get("exited_slashed") ?? []), ...(allValidators.get("exited_unslashed") ?? [])]?.forEach( - (validatorState: ValidatorResponse) => { - logger.info("Validator Exited", { - pubkey: toHexString(validatorState.validator.pubkey), - index: validatorState.index, - }); - } - ); - - logger.info("Initialized Validators: ", { + logger.info("Initialized validators", { total: allValidators.size, - available: allValidators.get("active")?.length, + active: allValidators.get("active")?.length, }); } + +function getValidatorStatesByStatuses( + statuses: ValidatorStatus[], + allValidators: Map +): ValidatorResponse[] { + return statuses.filter((status) => allValidators.has(status)).map((status) => allValidators.get(status)); +} diff --git a/packages/validator/src/services/prepareBeaconProposer.ts b/packages/validator/src/services/prepareBeaconProposer.ts index c48703332e9b..765a14ec67a8 100644 --- a/packages/validator/src/services/prepareBeaconProposer.ts +++ b/packages/validator/src/services/prepareBeaconProposer.ts @@ -3,7 +3,7 @@ import {Api, ApiError} from "@lodestar/api"; import {SLOTS_PER_EPOCH} from "@lodestar/params"; import {BeaconConfig} from "@lodestar/config"; -import {ProposerPreparationData} from "@lodestar/api/lib/beacon/routes/validator.js"; +import {ProposerPreparationData} from "@lodestar/api"; import {IClock, batchItems, LoggerVc} from "../util/index.js"; import {Metrics} from "../metrics.js"; import {ValidatorStore} from "./validatorStore.js"; @@ -49,7 +49,7 @@ export function pollPrepareBeaconProposer( feeRecipient, }); - logger.info("Validator exists in Beacon Chain", {validatorIndex: index, feeRecipient, pubKey}); + logger.info("Validator exists in beacon chain", {validatorIndex: index, feeRecipient, pubKey}); }); ApiError.assert(await api.validator.prepareBeaconProposer(proposers)); } catch (e) { From aa79941edeada7e800ec52467430a757af893c41 Mon Sep 17 00:00:00 2001 From: chad Date: Wed, 22 Feb 2023 13:22:32 -0500 Subject: [PATCH 07/20] Fix imports and updated readability (#4785) --- packages/validator/src/services/indices.ts | 28 +++++++++++-------- .../src/services/prepareBeaconProposer.ts | 4 +-- 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/packages/validator/src/services/indices.ts b/packages/validator/src/services/indices.ts index 9399c9c5ee72..871a16cb7551 100644 --- a/packages/validator/src/services/indices.ts +++ b/packages/validator/src/services/indices.ts @@ -1,7 +1,8 @@ import {ValidatorIndex} from "@lodestar/types"; import {Logger} from "@lodestar/utils"; import {toHexString} from "@chainsafe/ssz"; -import {Api, ApiError, ValidatorResponse, ValidatorStatus} from "@lodestar/api"; +import {Api, ApiError} from "@lodestar/api"; +import {ValidatorStatus, ValidatorResponse} from "@lodestar/api/lib/beacon/routes/beacon/state.js"; import {batchItems} from "../util/index.js"; import {Metrics} from "../metrics.js"; @@ -127,7 +128,7 @@ function logValidatorStatuses(allValidators: Map { @@ -136,17 +137,16 @@ function logValidatorStatuses(allValidators: Map { - getValidatorStatesByStatuses(loggedValidatorStates[key], allValidators).forEach( - (validatorState: ValidatorResponse) => { - logFormatter(key, validatorState); - } - ); - }); + + for (const [message, statuses] of Object.entries(loggedValidatorStates)) { + getValidatorStatesByStatuses(statuses, allValidators).forEach((validatorState) => { + logFormatter(message, validatorState); + }); + } logger.info("Initialized validators", { total: allValidators.size, - active: allValidators.get("active")?.length, + active: allValidators.get("active")?.length ?? 0, }); } @@ -154,5 +154,11 @@ function getValidatorStatesByStatuses( statuses: ValidatorStatus[], allValidators: Map ): ValidatorResponse[] { - return statuses.filter((status) => allValidators.has(status)).map((status) => allValidators.get(status)); + return statuses.reduce((validatorStates, status) => { + const validators = allValidators.get(status); + if (validators) { + validatorStates.push(...validators); + } + return validatorStates; + }, [] as ValidatorResponse[]); } diff --git a/packages/validator/src/services/prepareBeaconProposer.ts b/packages/validator/src/services/prepareBeaconProposer.ts index 765a14ec67a8..3b3720610280 100644 --- a/packages/validator/src/services/prepareBeaconProposer.ts +++ b/packages/validator/src/services/prepareBeaconProposer.ts @@ -3,8 +3,8 @@ import {Api, ApiError} from "@lodestar/api"; import {SLOTS_PER_EPOCH} from "@lodestar/params"; import {BeaconConfig} from "@lodestar/config"; -import {ProposerPreparationData} from "@lodestar/api"; -import {IClock, batchItems, LoggerVc} from "../util/index.js"; +import {ProposerPreparationData} from "@lodestar/api/lib/beacon/routes/validator.js"; +import {IClock, LoggerVc, batchItems} from "../util/index.js"; import {Metrics} from "../metrics.js"; import {ValidatorStore} from "./validatorStore.js"; From 26e35d0bf0ac57262cc25a74fc56afc3c711050c Mon Sep 17 00:00:00 2001 From: chad Date: Thu, 23 Feb 2023 14:29:39 -0500 Subject: [PATCH 08/20] Updated imports + adjusted coding preferences and log formatting --- packages/validator/src/services/indices.ts | 53 +++++++++++-------- .../src/services/prepareBeaconProposer.ts | 4 +- 2 files changed, 33 insertions(+), 24 deletions(-) diff --git a/packages/validator/src/services/indices.ts b/packages/validator/src/services/indices.ts index 871a16cb7551..345d37d9be43 100644 --- a/packages/validator/src/services/indices.ts +++ b/packages/validator/src/services/indices.ts @@ -2,7 +2,7 @@ import {ValidatorIndex} from "@lodestar/types"; import {Logger} from "@lodestar/utils"; import {toHexString} from "@chainsafe/ssz"; import {Api, ApiError} from "@lodestar/api"; -import {ValidatorStatus, ValidatorResponse} from "@lodestar/api/lib/beacon/routes/beacon/state.js"; +import {routes} from "@lodestar/api"; import {batchItems} from "../util/index.js"; import {Metrics} from "../metrics.js"; @@ -102,15 +102,22 @@ export class IndicesService { const newIndices = []; - const allValidators = new Map(); + const allValidators = new Map(); for (const validatorState of res.response.data) { // Group all validators by status - allValidators.set(validatorState.status, [validatorState]); + if (!allValidators.has(validatorState.status)) { + allValidators.set(validatorState.status, [validatorState]); + } else { + allValidators.get(validatorState.status)?.push(validatorState); + } const pubkeyHex = toHexString(validatorState.validator.pubkey); if (!this.pubkey2index.has(pubkeyHex)) { - this.logger.debug("Discovered validator", {pubkey: pubkeyHex, index: validatorState.index}); + this.logger.debug("Validator exists in beacon chain", { + validatorIndex: validatorState.index, + pubkey: pubkeyHex, + }); this.pubkey2index.set(pubkeyHex, validatorState.index); this.index2pubkey.set(validatorState.index, pubkeyHex); newIndices.push(validatorState.index); @@ -123,42 +130,44 @@ export class IndicesService { } } -function logValidatorStatuses(allValidators: Map, logger: Logger): void { - const loggedValidatorStates: {[key: string]: ValidatorStatus[]} = { +function logValidatorStatuses( + allValidators: Map, + logger: Logger +): void { + const loggedValidatorStates: {[key: string]: routes.beacon.ValidatorStatus[]} = { "Validator activated": ["active"], "Validator pending": ["pending_initialized", "pending_queued"], "Validator withdrawn": ["withdrawal_done"], "Validator exited": ["exited_slashed", "exited_unslashed"], }; - const logFormatter = (message: string, validatorState: ValidatorResponse): void => { - logger.info(message, { - pubkey: toHexString(validatorState.validator.pubkey), - index: validatorState.index, - }); - }; - for (const [message, statuses] of Object.entries(loggedValidatorStates)) { - getValidatorStatesByStatuses(statuses, allValidators).forEach((validatorState) => { - logFormatter(message, validatorState); - }); + for (const validatorState of getValidatorStatesByStatuses(statuses, allValidators)) { + logger.info(message, { + pubkey: toHexString(validatorState.validator.pubkey), + index: validatorState.index, + }); + } } - logger.info("Initialized validators", { - total: allValidators.size, + logger.info("Validator statuses", { active: allValidators.get("active")?.length ?? 0, + pending: getValidatorStatesByStatuses(loggedValidatorStates["Validator pending"], allValidators)?.length ?? 0, + exited: getValidatorStatesByStatuses(loggedValidatorStates["Validator exited"], allValidators)?.length ?? 0, + withdrawn: getValidatorStatesByStatuses(loggedValidatorStates["Validator withdrawn"], allValidators)?.length ?? 0, + total: allValidators.size, }); } function getValidatorStatesByStatuses( - statuses: ValidatorStatus[], - allValidators: Map -): ValidatorResponse[] { + statuses: routes.beacon.ValidatorStatus[], + allValidators: Map +): routes.beacon.ValidatorResponse[] { return statuses.reduce((validatorStates, status) => { const validators = allValidators.get(status); if (validators) { validatorStates.push(...validators); } return validatorStates; - }, [] as ValidatorResponse[]); + }, [] as routes.beacon.ValidatorResponse[]); } diff --git a/packages/validator/src/services/prepareBeaconProposer.ts b/packages/validator/src/services/prepareBeaconProposer.ts index 3b3720610280..33c2ecf33190 100644 --- a/packages/validator/src/services/prepareBeaconProposer.ts +++ b/packages/validator/src/services/prepareBeaconProposer.ts @@ -3,7 +3,7 @@ import {Api, ApiError} from "@lodestar/api"; import {SLOTS_PER_EPOCH} from "@lodestar/params"; import {BeaconConfig} from "@lodestar/config"; -import {ProposerPreparationData} from "@lodestar/api/lib/beacon/routes/validator.js"; +import {routes} from "@lodestar/api"; import {IClock, LoggerVc, batchItems} from "../util/index.js"; import {Metrics} from "../metrics.js"; import {ValidatorStore} from "./validatorStore.js"; @@ -38,7 +38,7 @@ export function pollPrepareBeaconProposer( const indicesChunks = batchItems(validatorStore.getAllLocalIndices(), {batchSize: REGISTRATION_CHUNK_SIZE}); for (const indices of indicesChunks) { - const proposers: ProposerPreparationData[] = []; + const proposers: routes.validator.ProposerPreparationData[] = []; try { indices.forEach((index) => { const feeRecipient = validatorStore.getFeeRecipientByIndex(index); From ba679cc6b743c8d87a36a5c3217eeb77683c51d3 Mon Sep 17 00:00:00 2001 From: chad Date: Fri, 24 Feb 2023 12:22:46 -0500 Subject: [PATCH 09/20] Refactored logs to only report the totals by status + removed logging validator status per epoch --- packages/validator/src/services/indices.ts | 67 +++++----------------- 1 file changed, 15 insertions(+), 52 deletions(-) diff --git a/packages/validator/src/services/indices.ts b/packages/validator/src/services/indices.ts index 345d37d9be43..8eb040b1a171 100644 --- a/packages/validator/src/services/indices.ts +++ b/packages/validator/src/services/indices.ts @@ -1,8 +1,7 @@ import {ValidatorIndex} from "@lodestar/types"; -import {Logger} from "@lodestar/utils"; +import {Logger, MapDef} from "@lodestar/utils"; import {toHexString} from "@chainsafe/ssz"; -import {Api, ApiError} from "@lodestar/api"; -import {routes} from "@lodestar/api"; +import {Api, ApiError, routes} from "@lodestar/api"; import {batchItems} from "../util/index.js"; import {Metrics} from "../metrics.js"; @@ -15,6 +14,9 @@ const PUBKEYS_PER_REQUEST = 10; // To assist with readability type PubkeyHex = string; +// To assist with logging statuses, we only log the statuses that are not active_exiting or withdrawal_possible +type SimpleValidatorStatus = Exclude; + export class IndicesService { readonly index2pubkey = new Map(); /** Indexed by pubkey in hex 0x prefixed */ @@ -102,15 +104,14 @@ export class IndicesService { const newIndices = []; - const allValidators = new Map(); + const allValidators = new MapDef(() => 0); for (const validatorState of res.response.data) { // Group all validators by status - if (!allValidators.has(validatorState.status)) { - allValidators.set(validatorState.status, [validatorState]); - } else { - allValidators.get(validatorState.status)?.push(validatorState); - } + allValidators.set( + validatorState.status as SimpleValidatorStatus, + allValidators.getOrDefault(validatorState.status as SimpleValidatorStatus) + 1 + ); const pubkeyHex = toHexString(validatorState.validator.pubkey); if (!this.pubkey2index.has(pubkeyHex)) { @@ -124,50 +125,12 @@ export class IndicesService { } } - logValidatorStatuses(allValidators, this.logger); + // Filter out validator statuses that are greater than 0 + const statuses = Object.fromEntries(Array.from(allValidators.entries()).filter((entry) => entry[1] > 0)); + // The total number of validators + const total = Object.values(statuses).reduce((a, b) => a + b, 0); + logger.info("Validator statuses", {...statuses, total}); return newIndices; } } - -function logValidatorStatuses( - allValidators: Map, - logger: Logger -): void { - const loggedValidatorStates: {[key: string]: routes.beacon.ValidatorStatus[]} = { - "Validator activated": ["active"], - "Validator pending": ["pending_initialized", "pending_queued"], - "Validator withdrawn": ["withdrawal_done"], - "Validator exited": ["exited_slashed", "exited_unslashed"], - }; - - for (const [message, statuses] of Object.entries(loggedValidatorStates)) { - for (const validatorState of getValidatorStatesByStatuses(statuses, allValidators)) { - logger.info(message, { - pubkey: toHexString(validatorState.validator.pubkey), - index: validatorState.index, - }); - } - } - - logger.info("Validator statuses", { - active: allValidators.get("active")?.length ?? 0, - pending: getValidatorStatesByStatuses(loggedValidatorStates["Validator pending"], allValidators)?.length ?? 0, - exited: getValidatorStatesByStatuses(loggedValidatorStates["Validator exited"], allValidators)?.length ?? 0, - withdrawn: getValidatorStatesByStatuses(loggedValidatorStates["Validator withdrawn"], allValidators)?.length ?? 0, - total: allValidators.size, - }); -} - -function getValidatorStatesByStatuses( - statuses: routes.beacon.ValidatorStatus[], - allValidators: Map -): routes.beacon.ValidatorResponse[] { - return statuses.reduce((validatorStates, status) => { - const validators = allValidators.get(status); - if (validators) { - validatorStates.push(...validators); - } - return validatorStates; - }, [] as routes.beacon.ValidatorResponse[]); -} From 9250c5301a82fcddbeee41b28d59cb0843c8f002 Mon Sep 17 00:00:00 2001 From: chad Date: Fri, 24 Feb 2023 12:27:29 -0500 Subject: [PATCH 10/20] fix linting issue --- packages/validator/src/services/indices.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/validator/src/services/indices.ts b/packages/validator/src/services/indices.ts index 8eb040b1a171..db61b5d7763e 100644 --- a/packages/validator/src/services/indices.ts +++ b/packages/validator/src/services/indices.ts @@ -129,7 +129,7 @@ export class IndicesService { const statuses = Object.fromEntries(Array.from(allValidators.entries()).filter((entry) => entry[1] > 0)); // The total number of validators const total = Object.values(statuses).reduce((a, b) => a + b, 0); - logger.info("Validator statuses", {...statuses, total}); + this.logger.info("Validator statuses", {...statuses, total}); return newIndices; } From 31a3879a3cb7d435b46a1cf861a79b41ecd88541 Mon Sep 17 00:00:00 2001 From: chad Date: Mon, 27 Feb 2023 17:38:05 -0500 Subject: [PATCH 11/20] fix: added mapping for simple validator statuses --- packages/validator/src/services/indices.ts | 30 ++++++++++++++++++---- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/packages/validator/src/services/indices.ts b/packages/validator/src/services/indices.ts index db61b5d7763e..d6ae69f79fe0 100644 --- a/packages/validator/src/services/indices.ts +++ b/packages/validator/src/services/indices.ts @@ -15,7 +15,24 @@ const PUBKEYS_PER_REQUEST = 10; type PubkeyHex = string; // To assist with logging statuses, we only log the statuses that are not active_exiting or withdrawal_possible -type SimpleValidatorStatus = Exclude; +type SimpleValidatorStatus = "pending" | "active" | "exited" | "withdrawn" | "unknown"; + +const statusToSimpleStatusMapping = (status: routes.beacon.ValidatorStatus): SimpleValidatorStatus => { + if (status.includes("active") || status === "withdrawal_possible") { + return "active"; + } + if (status.includes("exiting")) { + return "exited"; + } + if (status.includes("pending")) { + return "pending"; + } + if (status === "withdrawal_done") { + return "withdrawn"; + } + + return "unknown"; +}; export class IndicesService { readonly index2pubkey = new Map(); @@ -108,10 +125,8 @@ export class IndicesService { for (const validatorState of res.response.data) { // Group all validators by status - allValidators.set( - validatorState.status as SimpleValidatorStatus, - allValidators.getOrDefault(validatorState.status as SimpleValidatorStatus) + 1 - ); + const status = statusToSimpleStatusMapping(validatorState.status); + allValidators.set(status, allValidators.getOrDefault(status) + 1); const pubkeyHex = toHexString(validatorState.validator.pubkey); if (!this.pubkey2index.has(pubkeyHex)) { @@ -127,6 +142,11 @@ export class IndicesService { // Filter out validator statuses that are greater than 0 const statuses = Object.fromEntries(Array.from(allValidators.entries()).filter((entry) => entry[1] > 0)); + // The number of validators that are not in the beacon chain + const pendingCount = pubkeysHex.length - res.response.data.length; + if (pendingCount > 0) { + statuses["pending"] = pendingCount; + } // The total number of validators const total = Object.values(statuses).reduce((a, b) => a + b, 0); this.logger.info("Validator statuses", {...statuses, total}); From cd71135c570f7805b8aba6dbd0381aaa950dd668 Mon Sep 17 00:00:00 2001 From: chad Date: Tue, 28 Feb 2023 11:03:56 -0500 Subject: [PATCH 12/20] updated mapping for validator statuses --- packages/validator/src/services/indices.ts | 32 ++++++++++++---------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/packages/validator/src/services/indices.ts b/packages/validator/src/services/indices.ts index d6ae69f79fe0..ecd94f897853 100644 --- a/packages/validator/src/services/indices.ts +++ b/packages/validator/src/services/indices.ts @@ -15,23 +15,25 @@ const PUBKEYS_PER_REQUEST = 10; type PubkeyHex = string; // To assist with logging statuses, we only log the statuses that are not active_exiting or withdrawal_possible -type SimpleValidatorStatus = "pending" | "active" | "exited" | "withdrawn" | "unknown"; +type SimpleValidatorStatus = "pending" | "active" | "exited" | "withdrawn"; const statusToSimpleStatusMapping = (status: routes.beacon.ValidatorStatus): SimpleValidatorStatus => { - if (status.includes("active") || status === "withdrawal_possible") { - return "active"; + switch (status) { + case "active": + case "active_exiting": + case "active_slashed": + case "active_ongoing": + case "withdrawal_possible": + return "active"; + case "exited_slashed": + case "exited_unslashed": + return "exited"; + case "pending_initialized": + case "pending_queued": + return "pending"; + case "withdrawal_done": + return "withdrawn"; } - if (status.includes("exiting")) { - return "exited"; - } - if (status.includes("pending")) { - return "pending"; - } - if (status === "withdrawal_done") { - return "withdrawn"; - } - - return "unknown"; }; export class IndicesService { @@ -145,7 +147,7 @@ export class IndicesService { // The number of validators that are not in the beacon chain const pendingCount = pubkeysHex.length - res.response.data.length; if (pendingCount > 0) { - statuses["pending"] = pendingCount; + statuses["pending"] += pendingCount; } // The total number of validators const total = Object.values(statuses).reduce((a, b) => a + b, 0); From 6e27d85c81a231a6cd62f438809acbee6b6eccc7 Mon Sep 17 00:00:00 2001 From: chad Date: Thu, 2 Mar 2023 08:24:47 -0500 Subject: [PATCH 13/20] fix potential NaN error in pending statuses + some minor refactors --- packages/validator/src/services/indices.ts | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/packages/validator/src/services/indices.ts b/packages/validator/src/services/indices.ts index ecd94f897853..23d84852be43 100644 --- a/packages/validator/src/services/indices.ts +++ b/packages/validator/src/services/indices.ts @@ -23,14 +23,17 @@ const statusToSimpleStatusMapping = (status: routes.beacon.ValidatorStatus): Sim case "active_exiting": case "active_slashed": case "active_ongoing": - case "withdrawal_possible": return "active"; + + case "withdrawal_possible": case "exited_slashed": case "exited_unslashed": return "exited"; + case "pending_initialized": case "pending_queued": return "pending"; + case "withdrawal_done": return "withdrawn"; } @@ -123,12 +126,12 @@ export class IndicesService { const newIndices = []; - const allValidators = new MapDef(() => 0); + const allValidatorStatuses = new MapDef(() => 0); for (const validatorState of res.response.data) { // Group all validators by status const status = statusToSimpleStatusMapping(validatorState.status); - allValidators.set(status, allValidators.getOrDefault(status) + 1); + allValidatorStatuses.set(status, allValidatorStatuses.getOrDefault(status) + 1); const pubkeyHex = toHexString(validatorState.validator.pubkey); if (!this.pubkey2index.has(pubkeyHex)) { @@ -142,15 +145,15 @@ export class IndicesService { } } - // Filter out validator statuses that are greater than 0 - const statuses = Object.fromEntries(Array.from(allValidators.entries()).filter((entry) => entry[1] > 0)); + // Retrieve the number of validators for each status + const statuses = Object.fromEntries(Array.from(allValidatorStatuses.entries()).filter((entry) => entry[1] > 0)); // The number of validators that are not in the beacon chain const pendingCount = pubkeysHex.length - res.response.data.length; if (pendingCount > 0) { - statuses["pending"] += pendingCount; + allValidatorStatuses.set("pending", allValidatorStatuses.getOrDefault("pending") + pendingCount); } // The total number of validators - const total = Object.values(statuses).reduce((a, b) => a + b, 0); + const total = pubkeysHex.length; this.logger.info("Validator statuses", {...statuses, total}); return newIndices; From 50825d16cc85a747ce41c21f1f1a990fd799112d Mon Sep 17 00:00:00 2001 From: chad Date: Thu, 2 Mar 2023 08:45:22 -0500 Subject: [PATCH 14/20] fix issue with getting validator pending statuses --- packages/validator/src/services/indices.ts | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/packages/validator/src/services/indices.ts b/packages/validator/src/services/indices.ts index 23d84852be43..1f39434832ea 100644 --- a/packages/validator/src/services/indices.ts +++ b/packages/validator/src/services/indices.ts @@ -145,15 +145,17 @@ export class IndicesService { } } - // Retrieve the number of validators for each status - const statuses = Object.fromEntries(Array.from(allValidatorStatuses.entries()).filter((entry) => entry[1] > 0)); // The number of validators that are not in the beacon chain const pendingCount = pubkeysHex.length - res.response.data.length; - if (pendingCount > 0) { - allValidatorStatuses.set("pending", allValidatorStatuses.getOrDefault("pending") + pendingCount); - } + + allValidatorStatuses.set("pending", allValidatorStatuses.getOrDefault("pending") + pendingCount); + + // Retrieve the number of validators for each status + const statuses = Object.fromEntries(Array.from(allValidatorStatuses.entries()).filter((entry) => entry[1] > 0)); + // The total number of validators const total = pubkeysHex.length; + this.logger.info("Validator statuses", {...statuses, total}); return newIndices; From 07e9d079001c0ec73e678f6693dd792f3447edfb Mon Sep 17 00:00:00 2001 From: chad Date: Thu, 2 Mar 2023 09:30:38 -0500 Subject: [PATCH 15/20] Removed debug log for validator exists in beacon chain --- packages/validator/src/services/indices.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/packages/validator/src/services/indices.ts b/packages/validator/src/services/indices.ts index 1f39434832ea..8aeda0e342e9 100644 --- a/packages/validator/src/services/indices.ts +++ b/packages/validator/src/services/indices.ts @@ -135,10 +135,6 @@ export class IndicesService { const pubkeyHex = toHexString(validatorState.validator.pubkey); if (!this.pubkey2index.has(pubkeyHex)) { - this.logger.debug("Validator exists in beacon chain", { - validatorIndex: validatorState.index, - pubkey: pubkeyHex, - }); this.pubkey2index.set(pubkeyHex, validatorState.index); this.index2pubkey.set(validatorState.index, pubkeyHex); newIndices.push(validatorState.index); From d8094a4a1ebab1a2394dd2e1beb18db3336ffb90 Mon Sep 17 00:00:00 2001 From: chad Date: Thu, 2 Mar 2023 15:18:55 -0500 Subject: [PATCH 16/20] updated import in prepareBeaconProposer --- packages/validator/src/services/prepareBeaconProposer.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/validator/src/services/prepareBeaconProposer.ts b/packages/validator/src/services/prepareBeaconProposer.ts index 33c2ecf33190..6276cb973cd1 100644 --- a/packages/validator/src/services/prepareBeaconProposer.ts +++ b/packages/validator/src/services/prepareBeaconProposer.ts @@ -1,9 +1,8 @@ import {Epoch, bellatrix} from "@lodestar/types"; -import {Api, ApiError} from "@lodestar/api"; -import {SLOTS_PER_EPOCH} from "@lodestar/params"; +import {Api, ApiError, routes} from "@lodestar/api"; import {BeaconConfig} from "@lodestar/config"; +import {SLOTS_PER_EPOCH} from "@lodestar/params"; -import {routes} from "@lodestar/api"; import {IClock, LoggerVc, batchItems} from "../util/index.js"; import {Metrics} from "../metrics.js"; import {ValidatorStore} from "./validatorStore.js"; From 700b06285cbdb39868bff8b9c7b76b4438a4deb7 Mon Sep 17 00:00:00 2001 From: chad Date: Thu, 2 Mar 2023 17:39:48 -0500 Subject: [PATCH 17/20] reverted changes in prepareBeaconProposer and added TODO comments --- packages/validator/src/services/indices.ts | 7 ++++++- .../src/services/prepareBeaconProposer.ts | 16 +++++----------- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/packages/validator/src/services/indices.ts b/packages/validator/src/services/indices.ts index 8aeda0e342e9..bee6cc199353 100644 --- a/packages/validator/src/services/indices.ts +++ b/packages/validator/src/services/indices.ts @@ -135,6 +135,11 @@ export class IndicesService { const pubkeyHex = toHexString(validatorState.validator.pubkey); if (!this.pubkey2index.has(pubkeyHex)) { + //#TODO: We want to include the fee_recipient here, but it's not available in the API + logger.info("Validator exists in beacon chain", { + validatorIndex: validatorState.index, + pubKey: validatorState.validator.pubkey, + }); this.pubkey2index.set(pubkeyHex, validatorState.index); this.index2pubkey.set(validatorState.index, pubkeyHex); newIndices.push(validatorState.index); @@ -151,7 +156,7 @@ export class IndicesService { // The total number of validators const total = pubkeysHex.length; - + //#TODO: Refactor in https://github.com/ChainSafe/lodestar/issues/5158 this.logger.info("Validator statuses", {...statuses, total}); return newIndices; diff --git a/packages/validator/src/services/prepareBeaconProposer.ts b/packages/validator/src/services/prepareBeaconProposer.ts index 6276cb973cd1..473af87b21e3 100644 --- a/packages/validator/src/services/prepareBeaconProposer.ts +++ b/packages/validator/src/services/prepareBeaconProposer.ts @@ -37,19 +37,13 @@ export function pollPrepareBeaconProposer( const indicesChunks = batchItems(validatorStore.getAllLocalIndices(), {batchSize: REGISTRATION_CHUNK_SIZE}); for (const indices of indicesChunks) { - const proposers: routes.validator.ProposerPreparationData[] = []; try { - indices.forEach((index) => { - const feeRecipient = validatorStore.getFeeRecipientByIndex(index); - const pubKey = validatorStore.getPubkeyOfIndex(index); - - proposers.push({ + const proposers = indices.map( + (index): routes.validator.ProposerPreparationData => ({ validatorIndex: String(index as number), - feeRecipient, - }); - - logger.info("Validator exists in beacon chain", {validatorIndex: index, feeRecipient, pubKey}); - }); + feeRecipient: validatorStore.getFeeRecipientByIndex(index), + }) + ); ApiError.assert(await api.validator.prepareBeaconProposer(proposers)); } catch (e) { logger.error("Failed to register proposers with beacon", {epoch}, e as Error); From 5eb7541f7dc27d2dae8ef47671f623c7f392f2c5 Mon Sep 17 00:00:00 2001 From: chad Date: Fri, 3 Mar 2023 11:08:25 -0500 Subject: [PATCH 18/20] update lint error --- packages/validator/src/services/indices.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/validator/src/services/indices.ts b/packages/validator/src/services/indices.ts index bee6cc199353..7498b3179eaf 100644 --- a/packages/validator/src/services/indices.ts +++ b/packages/validator/src/services/indices.ts @@ -136,7 +136,7 @@ export class IndicesService { const pubkeyHex = toHexString(validatorState.validator.pubkey); if (!this.pubkey2index.has(pubkeyHex)) { //#TODO: We want to include the fee_recipient here, but it's not available in the API - logger.info("Validator exists in beacon chain", { + this.logger.info("Validator exists in beacon chain", { validatorIndex: validatorState.index, pubKey: validatorState.validator.pubkey, }); From 335ebbc5f934b9eecbbcb3b73cce5e96548cdadb Mon Sep 17 00:00:00 2001 From: chad Date: Fri, 3 Mar 2023 11:24:19 -0500 Subject: [PATCH 19/20] updated log params --- packages/validator/src/services/indices.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/validator/src/services/indices.ts b/packages/validator/src/services/indices.ts index 7498b3179eaf..da82318f5f99 100644 --- a/packages/validator/src/services/indices.ts +++ b/packages/validator/src/services/indices.ts @@ -135,10 +135,10 @@ export class IndicesService { const pubkeyHex = toHexString(validatorState.validator.pubkey); if (!this.pubkey2index.has(pubkeyHex)) { - //#TODO: We want to include the fee_recipient here, but it's not available in the API + //#TODO: We want to include the fee_recipient here, but it's not available in the API https://github.com/ChainSafe/lodestar/issues/5192 this.logger.info("Validator exists in beacon chain", { validatorIndex: validatorState.index, - pubKey: validatorState.validator.pubkey, + pubKey: pubkeyHex, }); this.pubkey2index.set(pubkeyHex, validatorState.index); this.index2pubkey.set(validatorState.index, pubkeyHex); From b01b460f233b343def3d20bc36b3eecb3e543c34 Mon Sep 17 00:00:00 2001 From: chad Date: Fri, 3 Mar 2023 12:09:07 -0500 Subject: [PATCH 20/20] removed TODOs --- packages/validator/src/services/indices.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/validator/src/services/indices.ts b/packages/validator/src/services/indices.ts index da82318f5f99..aea292400391 100644 --- a/packages/validator/src/services/indices.ts +++ b/packages/validator/src/services/indices.ts @@ -135,7 +135,6 @@ export class IndicesService { const pubkeyHex = toHexString(validatorState.validator.pubkey); if (!this.pubkey2index.has(pubkeyHex)) { - //#TODO: We want to include the fee_recipient here, but it's not available in the API https://github.com/ChainSafe/lodestar/issues/5192 this.logger.info("Validator exists in beacon chain", { validatorIndex: validatorState.index, pubKey: pubkeyHex, @@ -156,7 +155,7 @@ export class IndicesService { // The total number of validators const total = pubkeysHex.length; - //#TODO: Refactor in https://github.com/ChainSafe/lodestar/issues/5158 + this.logger.info("Validator statuses", {...statuses, total}); return newIndices;