mirror of
https://github.com/sigp/lighthouse.git
synced 2026-03-14 18:32:42 +00:00
Fix bugs in proposer calculation post-Fulu (#8101)
As identified by a researcher during the Fusaka security competition, we were computing the proposer index incorrectly in some places by computing without lookahead. - [x] Add "low level" checks to computation functions in `consensus/types` to ensure they error cleanly - [x] Re-work the determination of proposer shuffling decision roots, which are now fork aware. - [x] Re-work and simplify the beacon proposer cache to be fork-aware. - [x] Optimise `with_proposer_cache` to use `OnceCell`. - [x] All tests passing. - [x] Resolve all remaining `FIXME(sproul)`s. - [x] Unit tests for `ProtoBlock::proposer_shuffling_root_for_child_block`. - [x] End-to-end regression test. - [x] Test on pre-Fulu network. - [x] Test on post-Fulu network. Co-Authored-By: Michael Sproul <michael@sigmaprime.io>
This commit is contained in:
@@ -160,6 +160,50 @@ pub struct Block {
|
||||
pub unrealized_finalized_checkpoint: Option<Checkpoint>,
|
||||
}
|
||||
|
||||
impl Block {
|
||||
/// Compute the proposer shuffling decision root of a child block in `child_block_epoch`.
|
||||
///
|
||||
/// This function assumes that `child_block_epoch >= self.epoch`. It is the responsibility of
|
||||
/// the caller to check this condition, or else incorrect results will be produced.
|
||||
pub fn proposer_shuffling_root_for_child_block(
|
||||
&self,
|
||||
child_block_epoch: Epoch,
|
||||
spec: &ChainSpec,
|
||||
) -> Hash256 {
|
||||
let block_epoch = self.current_epoch_shuffling_id.shuffling_epoch;
|
||||
|
||||
if !spec.fork_name_at_epoch(child_block_epoch).fulu_enabled() {
|
||||
// Prior to Fulu the proposer shuffling decision root for the current epoch is the same
|
||||
// as the attestation shuffling for the *next* epoch, i.e. it is determined at the start
|
||||
// of the current epoch.
|
||||
if block_epoch == child_block_epoch {
|
||||
self.next_epoch_shuffling_id.shuffling_decision_block
|
||||
} else {
|
||||
// Otherwise, the child block epoch is greater, so its decision root is its parent
|
||||
// root itself (this block's root).
|
||||
self.root
|
||||
}
|
||||
} else {
|
||||
// After Fulu the proposer shuffling is determined with lookahead, so if the block
|
||||
// lies in the same epoch as its parent, its decision root is the same as the
|
||||
// parent's current epoch attester shuffling
|
||||
//
|
||||
// i.e. the block from the end of epoch N - 2.
|
||||
if child_block_epoch == block_epoch {
|
||||
self.current_epoch_shuffling_id.shuffling_decision_block
|
||||
} else if child_block_epoch == block_epoch + 1 {
|
||||
// If the block is the next epoch, then it instead shares its decision root with
|
||||
// the parent's *next epoch* attester shuffling.
|
||||
self.next_epoch_shuffling_id.shuffling_decision_block
|
||||
} else {
|
||||
// The child block lies in the future beyond the lookahead, at the point where this
|
||||
// block (its parent) will be the decision block.
|
||||
self.root
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A Vec-wrapper which will grow to match any request.
|
||||
///
|
||||
/// E.g., a `get` or `insert` to an out-of-bounds element will cause the Vec to grow (using
|
||||
|
||||
Reference in New Issue
Block a user