mirror of
https://github.com/sigp/lighthouse.git
synced 2026-06-18 22:49:34 +00:00
5306 implemented
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -4218,12 +4218,6 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
let cached_head = self.canonical_head.cached_head();
|
||||
let old_head_slot = cached_head.head_slot();
|
||||
|
||||
// Compute the expected proposer for `current_slot` on the canonical chain. This is used by
|
||||
// `on_block` to gate proposer boost on the block's proposer matching the canonical proposer
|
||||
// (per spec `update_proposer_boost_root` added in v1.7.0-alpha.5).
|
||||
let canonical_head_proposer_index =
|
||||
self.canonical_head_proposer_index(current_slot, &cached_head)?;
|
||||
|
||||
// Take an upgradable read lock on fork choice so we can check if this block has already
|
||||
// been imported. We don't want to repeat work importing a block that is already imported.
|
||||
let fork_choice_reader = self.canonical_head.fork_choice_upgradable_read_lock();
|
||||
@@ -4255,7 +4249,6 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
block_delay,
|
||||
&state,
|
||||
payload_verification_status,
|
||||
canonical_head_proposer_index,
|
||||
&self.spec,
|
||||
)
|
||||
.map_err(|e| BlockError::BeaconChainError(Box::new(e.into())))?;
|
||||
@@ -5003,42 +4996,6 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
}))
|
||||
}
|
||||
|
||||
/// Compute the expected beacon proposer for `slot` on the canonical chain extending `cached_head`.
|
||||
///
|
||||
/// Uses the beacon proposer cache to avoid recomputing the shuffling on every block import.
|
||||
///
|
||||
/// This is used by `update_proposer_boost_root` to gate proposer boost on the block's proposer
|
||||
/// matching the canonical proposer, per consensus-specs v1.7.0-alpha.5.
|
||||
///
|
||||
/// This function should never error unless there is some corruption of the head state. If a
|
||||
/// state advance is needed, it will be handled by the proposer cache.
|
||||
pub fn canonical_head_proposer_index(
|
||||
&self,
|
||||
slot: Slot,
|
||||
cached_head: &CachedHead<T::EthSpec>,
|
||||
) -> Result<u64, Error> {
|
||||
let proposal_epoch = slot.epoch(T::EthSpec::slots_per_epoch());
|
||||
let head_block_root = cached_head.head_block_root();
|
||||
let head_state = &cached_head.snapshot.beacon_state;
|
||||
|
||||
let shuffling_decision_root = head_state.proposer_shuffling_decision_root_at_epoch(
|
||||
proposal_epoch,
|
||||
head_block_root,
|
||||
&self.spec,
|
||||
)?;
|
||||
|
||||
self.with_proposer_cache::<_, Error>(
|
||||
shuffling_decision_root,
|
||||
proposal_epoch,
|
||||
|proposers| {
|
||||
proposers
|
||||
.get_slot::<T::EthSpec>(slot)
|
||||
.map(|p| p.index as u64)
|
||||
},
|
||||
|| Ok((cached_head.head_state_root(), head_state.clone())),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn get_expected_withdrawals(
|
||||
&self,
|
||||
forkchoice_update_params: &ForkchoiceUpdateParameters,
|
||||
|
||||
@@ -1077,7 +1077,6 @@ async fn invalid_parent() {
|
||||
Duration::from_secs(0),
|
||||
&state,
|
||||
PayloadVerificationStatus::Optimistic,
|
||||
block.message().proposer_index(),
|
||||
&rig.harness.chain.spec,
|
||||
),
|
||||
Err(ForkChoiceError::ProtoArrayStringError(message))
|
||||
|
||||
@@ -621,10 +621,6 @@ mod tests {
|
||||
.into_available_block();
|
||||
|
||||
let current_slot = harness.get_current_slot();
|
||||
let cached_head = chain.canonical_head.cached_head();
|
||||
let canonical_head_proposer_index = chain
|
||||
.canonical_head_proposer_index(current_slot, &cached_head)
|
||||
.unwrap();
|
||||
|
||||
chain
|
||||
.canonical_head
|
||||
@@ -636,7 +632,6 @@ mod tests {
|
||||
Duration::ZERO,
|
||||
&post_state,
|
||||
PayloadVerificationStatus::Verified,
|
||||
canonical_head_proposer_index,
|
||||
&chain.spec,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
@@ -530,6 +530,30 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the dependent root for `block_root`, per the spec `get_dependent_root` helper.
|
||||
///
|
||||
/// The dependent root is the block root at the slot immediately preceding the start of epoch
|
||||
/// `current_epoch - MIN_SEED_LOOKAHEAD`. Two blocks that share a dependent root descend from
|
||||
/// the same shuffling, which is the condition used to gate proposer boost (see the spec
|
||||
/// `update_proposer_boost_root`).
|
||||
fn get_dependent_root(
|
||||
&self,
|
||||
block_root: Hash256,
|
||||
current_slot: Slot,
|
||||
spec: &ChainSpec,
|
||||
) -> Result<Option<Hash256>, Error<T::Error>> {
|
||||
let epoch = current_slot.epoch(E::slots_per_epoch());
|
||||
if epoch <= spec.min_seed_lookahead {
|
||||
// Genesis block parent.
|
||||
return Ok(Some(Hash256::zero()));
|
||||
}
|
||||
let dependent_slot = epoch
|
||||
.saturating_sub(spec.min_seed_lookahead)
|
||||
.start_slot(E::slots_per_epoch())
|
||||
.saturating_sub(1_u64);
|
||||
self.get_ancestor(block_root, dependent_slot)
|
||||
}
|
||||
|
||||
/// Run the fork choice rule to determine the head.
|
||||
///
|
||||
/// ## Specification
|
||||
@@ -760,7 +784,6 @@ where
|
||||
block_delay: Duration,
|
||||
state: &BeaconState<E>,
|
||||
payload_verification_status: PayloadVerificationStatus,
|
||||
canonical_head_proposer_index: u64,
|
||||
spec: &ChainSpec,
|
||||
) -> Result<(), Error<T::Error>> {
|
||||
let _timer = metrics::start_timer(&metrics::FORK_CHOICE_ON_BLOCK_TIMES);
|
||||
@@ -825,19 +848,29 @@ where
|
||||
|
||||
let attestation_threshold = spec.get_attestation_due::<E>(block.slot());
|
||||
|
||||
// Add proposer score boost if the block is the first timely block for this slot and its
|
||||
// proposer matches the expected proposer on the canonical chain (per spec
|
||||
// `update_proposer_boost_root`, introduced in v1.7.0-alpha.5).
|
||||
// Add proposer score boost if the block is the first timely block for this slot and it
|
||||
// shares the same dependent root as the canonical chain head (per spec
|
||||
// `update_proposer_boost_root`).
|
||||
let is_before_attesting_interval = block_delay < attestation_threshold;
|
||||
|
||||
let is_timely = current_slot == block.slot() && is_before_attesting_interval;
|
||||
let is_first_block = self.fc_store.proposer_boost_root().is_zero();
|
||||
let is_canonical_proposer = block.proposer_index() == canonical_head_proposer_index;
|
||||
if current_slot == block.slot()
|
||||
&& is_before_attesting_interval
|
||||
&& is_first_block
|
||||
&& is_canonical_proposer
|
||||
{
|
||||
self.fc_store.set_proposer_boost_root(block_root);
|
||||
|
||||
if is_timely && is_first_block {
|
||||
// Compute the head *before* this block is added to fork choice, matching the spec's
|
||||
// `head = get_head(store)` in `on_block`. This is gated on `is_timely && is_first_block`
|
||||
// so `get_head` runs at most once per slot.
|
||||
let (head_root, _) = self.get_head(system_time_current_slot, spec)?;
|
||||
|
||||
// The block has not yet been added to proto-array, so resolve its dependent root via
|
||||
// its parent. The ancestor at the dependent slot (an earlier epoch boundary) is
|
||||
// identical whether resolved from the block or its parent.
|
||||
let block_dependent_root =
|
||||
self.get_dependent_root(block.parent_root(), current_slot, spec)?;
|
||||
let head_dependent_root = self.get_dependent_root(head_root, current_slot, spec)?;
|
||||
|
||||
if block_dependent_root.is_some() && block_dependent_root == head_dependent_root {
|
||||
self.fc_store.set_proposer_boost_root(block_root);
|
||||
}
|
||||
}
|
||||
|
||||
// Update store with checkpoints if necessary
|
||||
|
||||
@@ -316,7 +316,6 @@ impl ForkChoiceTest {
|
||||
Duration::from_secs(0),
|
||||
&state,
|
||||
PayloadVerificationStatus::Verified,
|
||||
block.message().proposer_index(),
|
||||
&self.harness.chain.spec,
|
||||
)
|
||||
.unwrap();
|
||||
@@ -360,7 +359,6 @@ impl ForkChoiceTest {
|
||||
Duration::from_secs(0),
|
||||
&state,
|
||||
PayloadVerificationStatus::Verified,
|
||||
block.message().proposer_index(),
|
||||
&self.harness.chain.spec,
|
||||
)
|
||||
.expect_err("on_block did not return an error");
|
||||
|
||||
@@ -849,7 +849,6 @@ impl<E: EthSpec> Tester<E> {
|
||||
block_delay,
|
||||
&state,
|
||||
PayloadVerificationStatus::Irrelevant,
|
||||
block.message().proposer_index(),
|
||||
&self.harness.chain.spec,
|
||||
);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user