From 309c30136374cdf5f757d1fafbd3275a3d46ad34 Mon Sep 17 00:00:00 2001 From: Pawan Dhananjay Date: Sun, 13 Jul 2025 23:42:55 -0700 Subject: [PATCH] Allow /validator apis to work pre-genesis (#7729) N/A Lighthouse BN http endpoint would return a server error pre-genesis on the `validator/duties/attester` and `validator/prepare_beacon_proposer` because `slot_clock.now()` would return a `None` pre-genesis. The prysm VC depends on the endpoints pre-genesis and was having issues interoping with the lighthouse bn because of this reason. The proposer duties endpoint explicitly handles the pre-genesis case here https://github.com/sigp/lighthouse/blob/538067f1ff9840d44e3c2ea60581e18aba8c4143/beacon_node/http_api/src/proposer_duties.rs#L23-L28 I see no reason why we can't make the other endpoints more flexible to work pre-genesis. This PR handles the pre-genesis case on the attester and prepare_beacon_proposer endpoints as well. Thanks for raising @james-prysm. --- beacon_node/http_api/src/attester_duties.rs | 23 +++++++++++++++------ beacon_node/http_api/src/lib.rs | 6 +++++- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/beacon_node/http_api/src/attester_duties.rs b/beacon_node/http_api/src/attester_duties.rs index 8905b24cde..b42e474b5c 100644 --- a/beacon_node/http_api/src/attester_duties.rs +++ b/beacon_node/http_api/src/attester_duties.rs @@ -16,7 +16,12 @@ pub fn attester_duties( request_indices: &[u64], chain: &BeaconChain, ) -> Result { - let current_epoch = chain.epoch().map_err(warp_utils::reject::unhandled_error)?; + let current_epoch = chain + .slot_clock + .now_or_genesis() + .map(|slot| slot.epoch(T::EthSpec::slots_per_epoch())) + .ok_or(BeaconChainError::UnableToReadSlot) + .map_err(warp_utils::reject::unhandled_error)?; // Determine what the current epoch would be if we fast-forward our system clock by // `MAXIMUM_GOSSIP_CLOCK_DISPARITY`. @@ -24,11 +29,17 @@ pub fn attester_duties( // Most of the time, `tolerant_current_epoch` will be equal to `current_epoch`. However, during // the first `MAXIMUM_GOSSIP_CLOCK_DISPARITY` duration of the epoch `tolerant_current_epoch` // will equal `current_epoch + 1` - let tolerant_current_epoch = chain - .slot_clock - .now_with_future_tolerance(chain.spec.maximum_gossip_clock_disparity()) - .ok_or_else(|| warp_utils::reject::custom_server_error("unable to read slot clock".into()))? - .epoch(T::EthSpec::slots_per_epoch()); + let tolerant_current_epoch = if chain.slot_clock.is_prior_to_genesis().unwrap_or(true) { + current_epoch + } else { + chain + .slot_clock + .now_with_future_tolerance(chain.spec.maximum_gossip_clock_disparity()) + .ok_or_else(|| { + warp_utils::reject::custom_server_error("unable to read slot clock".into()) + })? + .epoch(T::EthSpec::slots_per_epoch()) + }; if request_epoch == current_epoch || request_epoch == current_epoch + 1 diff --git a/beacon_node/http_api/src/lib.rs b/beacon_node/http_api/src/lib.rs index 2db93c0033..cacdd4a44c 100644 --- a/beacon_node/http_api/src/lib.rs +++ b/beacon_node/http_api/src/lib.rs @@ -3790,7 +3790,11 @@ pub fn serve( .ok_or(BeaconChainError::ExecutionLayerMissing) .map_err(warp_utils::reject::unhandled_error)?; - let current_slot = chain.slot().map_err(warp_utils::reject::unhandled_error)?; + let current_slot = chain + .slot_clock + .now_or_genesis() + .ok_or(BeaconChainError::UnableToReadSlot) + .map_err(warp_utils::reject::unhandled_error)?; let current_epoch = current_slot.epoch(T::EthSpec::slots_per_epoch()); debug!(