From 4580730ca55e4a691e1606955e5048e08637a4c8 Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Tue, 12 Sep 2023 15:47:22 +0200 Subject: [PATCH 1/6] feat: add metric for slot of next scheduled attestation duty --- packages/validator/src/metrics.ts | 5 +++++ .../validator/src/services/attestationDuties.ts | 15 ++++++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/packages/validator/src/metrics.ts b/packages/validator/src/metrics.ts index e1890289bd36..5ffcf9278093 100644 --- a/packages/validator/src/metrics.ts +++ b/packages/validator/src/metrics.ts @@ -206,6 +206,11 @@ export function getMetrics(register: MetricsRegister, gitData: LodestarGitData) help: "Total count of instances the attester duties dependant root changed", }), + attesterDutiesNextSlot: register.gauge({ + name: "vc_attestation_duty_slot", + help: "Slot of next scheduled attestation duty", + }), + // BlockProposingService blocksProduced: register.gauge({ diff --git a/packages/validator/src/services/attestationDuties.ts b/packages/validator/src/services/attestationDuties.ts index 0100ca45568e..b189ba9da4bf 100644 --- a/packages/validator/src/services/attestationDuties.ts +++ b/packages/validator/src/services/attestationDuties.ts @@ -63,12 +63,25 @@ export class AttestationDutiesService { if (metrics) { metrics.attesterDutiesCount.addCollect(() => { + const currentSlot = this.clock.getCurrentSlot(); let duties = 0; - for (const attDutiesAtEpoch of this.dutiesByIndexByEpoch.values()) { + let nextDutySlot = null; + for (const [epoch, attDutiesAtEpoch] of this.dutiesByIndexByEpoch.entries()) { duties += attDutiesAtEpoch.dutiesByIndex.size; + + // Historical epochs can be skipped when determining next duty slot + if (epoch < this.clock.currentEpoch) continue; + + for (const {duty} of attDutiesAtEpoch.dutiesByIndex.values()) { + // Set next duty slot to the closest future slot found in all duties + if (duty.slot > currentSlot && (nextDutySlot === null || duty.slot < nextDutySlot)) { + nextDutySlot = duty.slot; + } + } } metrics.attesterDutiesCount.set(duties); metrics.attesterDutiesEpochCount.set(this.dutiesByIndexByEpoch.size); + if (nextDutySlot !== null) metrics.attesterDutiesNextSlot.set(nextDutySlot); }); } } From 9403503dbebdd819c1689e893f00e4bf16c359e1 Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Wed, 13 Sep 2023 10:20:07 +0200 Subject: [PATCH 2/6] Remove .entries() when iterating over dutiesByIndexByEpoch --- packages/validator/src/services/attestationDuties.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/validator/src/services/attestationDuties.ts b/packages/validator/src/services/attestationDuties.ts index b189ba9da4bf..3a06a4f5eaa9 100644 --- a/packages/validator/src/services/attestationDuties.ts +++ b/packages/validator/src/services/attestationDuties.ts @@ -66,7 +66,7 @@ export class AttestationDutiesService { const currentSlot = this.clock.getCurrentSlot(); let duties = 0; let nextDutySlot = null; - for (const [epoch, attDutiesAtEpoch] of this.dutiesByIndexByEpoch.entries()) { + for (const [epoch, attDutiesAtEpoch] of this.dutiesByIndexByEpoch) { duties += attDutiesAtEpoch.dutiesByIndex.size; // Historical epochs can be skipped when determining next duty slot From 6e2108216aed09611711ea5119e60e5a5e6559e7 Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Wed, 13 Sep 2023 13:05:08 +0200 Subject: [PATCH 3/6] Set duty slot to next slot if more than 64 validators --- packages/validator/src/services/attestationDuties.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/validator/src/services/attestationDuties.ts b/packages/validator/src/services/attestationDuties.ts index 3a06a4f5eaa9..794fc9d4f1df 100644 --- a/packages/validator/src/services/attestationDuties.ts +++ b/packages/validator/src/services/attestationDuties.ts @@ -72,6 +72,13 @@ export class AttestationDutiesService { // Historical epochs can be skipped when determining next duty slot if (epoch < this.clock.currentEpoch) continue; + // There is no need to check every single duty at a certain amount + // of validators, next duty slot will almost always be the next slot + if (attDutiesAtEpoch.dutiesByIndex.size >= 64) { + nextDutySlot = currentSlot + 1; + continue; + } + for (const {duty} of attDutiesAtEpoch.dutiesByIndex.values()) { // Set next duty slot to the closest future slot found in all duties if (duty.slot > currentSlot && (nextDutySlot === null || duty.slot < nextDutySlot)) { From 803f3474fe1330975407a4ada602337b9871b67a Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Thu, 14 Sep 2023 01:04:01 +0200 Subject: [PATCH 4/6] Add comment to explain metric name and usage --- packages/validator/src/metrics.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/validator/src/metrics.ts b/packages/validator/src/metrics.ts index 5ffcf9278093..4ae4724fb1c1 100644 --- a/packages/validator/src/metrics.ts +++ b/packages/validator/src/metrics.ts @@ -207,6 +207,9 @@ export function getMetrics(register: MetricsRegister, gitData: LodestarGitData) }), attesterDutiesNextSlot: register.gauge({ + // Metric is used by Rocket Pool dashboard (18391) to determine seconds until next attestation. + // It works without requiring any modification to the dashboard as the metric name is the + // same as Lighthouse uses for this. name: "vc_attestation_duty_slot", help: "Slot of next scheduled attestation duty", }), From 69575542ddeeabbda7a9624aeabcdb7ff404be70 Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Thu, 14 Sep 2023 09:27:13 +0200 Subject: [PATCH 5/6] Remove validator count check --- packages/validator/src/services/attestationDuties.ts | 7 ------- 1 file changed, 7 deletions(-) diff --git a/packages/validator/src/services/attestationDuties.ts b/packages/validator/src/services/attestationDuties.ts index 794fc9d4f1df..3a06a4f5eaa9 100644 --- a/packages/validator/src/services/attestationDuties.ts +++ b/packages/validator/src/services/attestationDuties.ts @@ -72,13 +72,6 @@ export class AttestationDutiesService { // Historical epochs can be skipped when determining next duty slot if (epoch < this.clock.currentEpoch) continue; - // There is no need to check every single duty at a certain amount - // of validators, next duty slot will almost always be the next slot - if (attDutiesAtEpoch.dutiesByIndex.size >= 64) { - nextDutySlot = currentSlot + 1; - continue; - } - for (const {duty} of attDutiesAtEpoch.dutiesByIndex.values()) { // Set next duty slot to the closest future slot found in all duties if (duty.slot > currentSlot && (nextDutySlot === null || duty.slot < nextDutySlot)) { From ba9790d49f454978713d1b516ae8dd99a085d3ac Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Thu, 14 Sep 2023 09:34:54 +0200 Subject: [PATCH 6/6] Stop searching once a next duty slot is found --- packages/validator/src/services/attestationDuties.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/validator/src/services/attestationDuties.ts b/packages/validator/src/services/attestationDuties.ts index 3a06a4f5eaa9..6c9e12b3fafe 100644 --- a/packages/validator/src/services/attestationDuties.ts +++ b/packages/validator/src/services/attestationDuties.ts @@ -69,8 +69,8 @@ export class AttestationDutiesService { for (const [epoch, attDutiesAtEpoch] of this.dutiesByIndexByEpoch) { duties += attDutiesAtEpoch.dutiesByIndex.size; - // Historical epochs can be skipped when determining next duty slot - if (epoch < this.clock.currentEpoch) continue; + // Epochs are sorted, stop searching once a next duty slot is found + if (epoch < this.clock.currentEpoch || nextDutySlot !== null) continue; for (const {duty} of attDutiesAtEpoch.dutiesByIndex.values()) { // Set next duty slot to the closest future slot found in all duties