From ce914d191d804a765c573843c3c7448facd04ccb Mon Sep 17 00:00:00 2001 From: Jimmy Chen Date: Tue, 23 Apr 2024 15:55:47 +1000 Subject: [PATCH 1/4] Reduce frequency of polling unknown validators. --- validator_client/src/duties_service.rs | 40 ++++++++++++++++++++++++++ validator_client/src/lib.rs | 1 + 2 files changed, 41 insertions(+) diff --git a/validator_client/src/duties_service.rs b/validator_client/src/duties_service.rs index b5b56943c4b..b6c568c3389 100644 --- a/validator_client/src/duties_service.rs +++ b/validator_client/src/duties_service.rs @@ -214,6 +214,8 @@ pub struct DutiesService { pub sync_duties: SyncDutiesMap, /// Provides the canonical list of locally-managed validators. pub validator_store: Arc>, + /// Maps unknown validator pubkeys to the next slot time when a poll should be conducted again. + pub unknown_validator_next_poll_slots: RwLock>, /// Tracks the current slot. pub slot_clock: T, /// Provides HTTP access to remote beacon nodes. @@ -478,6 +480,18 @@ async fn poll_validator_indices( .validator_store .voting_pubkeys(DoppelgangerStatus::ignored); + let current_slot_opt = duties_service.slot_clock.now(); + let next_poll_slot_opt = current_slot_opt.map(|slot| slot.saturating_add(E::slots_per_epoch())); + + let is_first_slot_of_epoch = if let Some(current_slot) = current_slot_opt { + let current_epoch_first_slot = current_slot + .epoch(E::slots_per_epoch()) + .start_slot(E::slots_per_epoch()); + current_slot == current_epoch_first_slot + } else { + false + }; + for pubkey in all_pubkeys { // This is on its own line to avoid some weirdness with locks and if statements. let is_known = duties_service @@ -488,6 +502,20 @@ async fn poll_validator_indices( .is_some(); if !is_known { + if let Some(current_slot) = current_slot_opt { + // Query an unknown validator later if it was queried within the last epoch, or if + // the current slot is the first slot of an epoch. + let poll_later = duties_service + .unknown_validator_next_poll_slots + .read() + .get(&pubkey) + .map(|&poll_slot| poll_slot > current_slot || is_first_slot_of_epoch) + .unwrap_or(false); + if poll_later { + continue; + } + } + // Query the remote BN to resolve a pubkey to a validator index. let download_result = duties_service .beacon_nodes @@ -532,10 +560,22 @@ async fn poll_validator_indices( .initialized_validators() .write() .set_index(&pubkey, response.data.index); + + duties_service + .unknown_validator_next_poll_slots + .write() + .remove(&pubkey); } // This is not necessarily an error, it just means the validator is not yet known to // the beacon chain. Ok(None) => { + if let Some(next_poll_slot) = next_poll_slot_opt { + duties_service + .unknown_validator_next_poll_slots + .write() + .insert(pubkey, next_poll_slot); + } + debug!( log, "Validator without index"; diff --git a/validator_client/src/lib.rs b/validator_client/src/lib.rs index 268c25cdf7d..59632a2805f 100644 --- a/validator_client/src/lib.rs +++ b/validator_client/src/lib.rs @@ -455,6 +455,7 @@ impl ProductionValidatorClient { slot_clock: slot_clock.clone(), beacon_nodes: beacon_nodes.clone(), validator_store: validator_store.clone(), + unknown_validator_next_poll_slots: <_>::default(), spec: context.eth2_config.spec.clone(), context: duties_context, enable_high_validator_count_metrics: config.enable_high_validator_count_metrics, From f66aae656f95d6935896f78f0231c37a2f71b488 Mon Sep 17 00:00:00 2001 From: Jimmy Chen Date: Mon, 6 May 2024 15:38:58 +1000 Subject: [PATCH 2/4] Move slot calculation into for loop. --- validator_client/src/duties_service.rs | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/validator_client/src/duties_service.rs b/validator_client/src/duties_service.rs index b6c568c3389..d738bb7a0ce 100644 --- a/validator_client/src/duties_service.rs +++ b/validator_client/src/duties_service.rs @@ -480,18 +480,6 @@ async fn poll_validator_indices( .validator_store .voting_pubkeys(DoppelgangerStatus::ignored); - let current_slot_opt = duties_service.slot_clock.now(); - let next_poll_slot_opt = current_slot_opt.map(|slot| slot.saturating_add(E::slots_per_epoch())); - - let is_first_slot_of_epoch = if let Some(current_slot) = current_slot_opt { - let current_epoch_first_slot = current_slot - .epoch(E::slots_per_epoch()) - .start_slot(E::slots_per_epoch()); - current_slot == current_epoch_first_slot - } else { - false - }; - for pubkey in all_pubkeys { // This is on its own line to avoid some weirdness with locks and if statements. let is_known = duties_service @@ -502,7 +490,16 @@ async fn poll_validator_indices( .is_some(); if !is_known { + let current_slot_opt = duties_service.slot_clock.now(); + if let Some(current_slot) = current_slot_opt { + let is_first_slot_of_epoch = { + let current_epoch_first_slot = current_slot + .epoch(E::slots_per_epoch()) + .start_slot(E::slots_per_epoch()); + current_slot == current_epoch_first_slot + }; + // Query an unknown validator later if it was queried within the last epoch, or if // the current slot is the first slot of an epoch. let poll_later = duties_service @@ -569,7 +566,8 @@ async fn poll_validator_indices( // This is not necessarily an error, it just means the validator is not yet known to // the beacon chain. Ok(None) => { - if let Some(next_poll_slot) = next_poll_slot_opt { + if let Some(current_slot) = current_slot_opt { + let next_poll_slot = current_slot.saturating_add(E::slots_per_epoch()); duties_service .unknown_validator_next_poll_slots .write() From 437ef4178c6765991780685091231f9988c2060e Mon Sep 17 00:00:00 2001 From: Jimmy Chen Date: Tue, 21 May 2024 11:37:02 +1000 Subject: [PATCH 3/4] Simplify logic. Co-authored-by: Michael Sproul --- validator_client/src/duties_service.rs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/validator_client/src/duties_service.rs b/validator_client/src/duties_service.rs index d738bb7a0ce..fc2d93e162c 100644 --- a/validator_client/src/duties_service.rs +++ b/validator_client/src/duties_service.rs @@ -493,12 +493,7 @@ async fn poll_validator_indices( let current_slot_opt = duties_service.slot_clock.now(); if let Some(current_slot) = current_slot_opt { - let is_first_slot_of_epoch = { - let current_epoch_first_slot = current_slot - .epoch(E::slots_per_epoch()) - .start_slot(E::slots_per_epoch()); - current_slot == current_epoch_first_slot - }; + let is_first_slot_of_epoch = current_slot % E::slots_per_epoch() == 0; // Query an unknown validator later if it was queried within the last epoch, or if // the current slot is the first slot of an epoch. From e782323bc1cda3e6bd45d5ee3a21faac52fbd645 Mon Sep 17 00:00:00 2001 From: Jimmy Chen Date: Tue, 21 May 2024 16:48:29 +1000 Subject: [PATCH 4/4] Fix formatting --- validator_client/src/duties_service.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validator_client/src/duties_service.rs b/validator_client/src/duties_service.rs index fc2d93e162c..2e77bb0afd2 100644 --- a/validator_client/src/duties_service.rs +++ b/validator_client/src/duties_service.rs @@ -493,7 +493,7 @@ async fn poll_validator_indices( let current_slot_opt = duties_service.slot_clock.now(); if let Some(current_slot) = current_slot_opt { - let is_first_slot_of_epoch = current_slot % E::slots_per_epoch() == 0; + let is_first_slot_of_epoch = current_slot % E::slots_per_epoch() == 0; // Query an unknown validator later if it was queried within the last epoch, or if // the current slot is the first slot of an epoch.