From c4ad0e3fb338cf6cb4a3f18040d1d0e66a86dd8b Mon Sep 17 00:00:00 2001 From: realbigsean Date: Tue, 2 Nov 2021 02:26:32 +0000 Subject: [PATCH] Ensure dependent root consistency in head events (#2753) ## Issue Addressed @paulhauner noticed that when we send head events, we use the block root from `new_head` in `fork_choice_internal`, but calculate `dependent_root` and `previous_dependent_root` using the `canonical_head`. This is normally fine because `new_head` updates the `canonical_head` in `fork_choice_internal`, but it's possible we have a reorg updating `canonical_head` before our head events are sent. So this PR ensures `dependent_root` and `previous_dependent_root` are always derived from the state associated with `new_head`. Co-authored-by: realbigsean --- beacon_node/beacon_chain/src/beacon_chain.rs | 36 ++++++++------------ 1 file changed, 15 insertions(+), 21 deletions(-) diff --git a/beacon_node/beacon_chain/src/beacon_chain.rs b/beacon_node/beacon_chain/src/beacon_chain.rs index c4ed8ace98..1ae4f42a2b 100644 --- a/beacon_node/beacon_chain/src/beacon_chain.rs +++ b/beacon_node/beacon_chain/src/beacon_chain.rs @@ -3050,14 +3050,6 @@ impl BeaconChain { // These fields are used for server-sent events. let state_root = new_head.beacon_state_root(); let head_slot = new_head.beacon_state.slot(); - let target_epoch_start_slot = new_head - .beacon_state - .current_epoch() - .start_slot(T::EthSpec::slots_per_epoch()); - let prev_target_epoch_start_slot = new_head - .beacon_state - .previous_epoch() - .start_slot(T::EthSpec::slots_per_epoch()); let head_proposer_index = new_head.beacon_block.message().proposer_index(); let proposer_graffiti = new_head .beacon_block @@ -3066,6 +3058,15 @@ impl BeaconChain { .graffiti() .as_utf8_lossy(); + // Find the dependent roots associated with this head before updating the snapshot. This + // is to ensure consistency when sending server sent events later in this method. + let dependent_root = new_head + .beacon_state + .proposer_shuffling_decision_root(self.genesis_block_root); + let prev_dependent_root = new_head + .beacon_state + .attester_shuffling_decision_root(self.genesis_block_root, RelativeEpoch::Current); + drop(lag_timer); // Update the snapshot that stores the head of the chain at the time it received the @@ -3210,12 +3211,8 @@ impl BeaconChain { // Register a server-sent event if necessary if let Some(event_handler) = self.event_handler.as_ref() { if event_handler.has_head_subscribers() { - if let Ok(Some(current_duty_dependent_root)) = - self.block_root_at_slot(target_epoch_start_slot - 1, WhenSlotSkipped::Prev) - { - if let Ok(Some(previous_duty_dependent_root)) = self - .block_root_at_slot(prev_target_epoch_start_slot - 1, WhenSlotSkipped::Prev) - { + match (dependent_root, prev_dependent_root) { + (Ok(current_duty_dependent_root), Ok(previous_duty_dependent_root)) => { event_handler.register(EventKind::Head(SseHead { slot: head_slot, block: beacon_block_root, @@ -3224,17 +3221,14 @@ impl BeaconChain { previous_duty_dependent_root, epoch_transition: is_epoch_transition, })); - } else { + } + (Err(e), _) | (_, Err(e)) => { warn!( self.log, - "Unable to find previous target root, cannot register head event" + "Unable to find dependent roots, cannot register head event"; + "error" => ?e ); } - } else { - warn!( - self.log, - "Unable to find current target root, cannot register head event" - ); } }