mirror of
https://github.com/sigp/lighthouse.git
synced 2026-04-19 22:08:30 +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:
@@ -5,8 +5,7 @@ use std::sync::Arc;
|
||||
|
||||
use crate::beacon_chain::{BeaconChain, BeaconChainTypes};
|
||||
use crate::block_verification::{
|
||||
BlockSlashInfo, cheap_state_advance_to_obtain_committees, get_validator_pubkey_cache,
|
||||
process_block_slash_info,
|
||||
BlockSlashInfo, get_validator_pubkey_cache, process_block_slash_info,
|
||||
};
|
||||
use crate::kzg_utils::{validate_blob, validate_blobs};
|
||||
use crate::observed_data_sidecars::{ObservationStrategy, Observe};
|
||||
@@ -494,59 +493,31 @@ pub fn validate_blob_sidecar_for_gossip<T: BeaconChainTypes, O: ObservationStrat
|
||||
}
|
||||
|
||||
let proposer_shuffling_root =
|
||||
if parent_block.slot.epoch(T::EthSpec::slots_per_epoch()) == blob_epoch {
|
||||
parent_block
|
||||
.next_epoch_shuffling_id
|
||||
.shuffling_decision_block
|
||||
} else {
|
||||
parent_block.root
|
||||
};
|
||||
parent_block.proposer_shuffling_root_for_child_block(blob_epoch, &chain.spec);
|
||||
|
||||
let proposer_opt = chain
|
||||
.beacon_proposer_cache
|
||||
.lock()
|
||||
.get_slot::<T::EthSpec>(proposer_shuffling_root, blob_slot);
|
||||
|
||||
let (proposer_index, fork) = if let Some(proposer) = proposer_opt {
|
||||
(proposer.index, proposer.fork)
|
||||
} else {
|
||||
debug!(
|
||||
%block_root,
|
||||
%blob_index,
|
||||
"Proposer shuffling cache miss for blob verification"
|
||||
);
|
||||
let (parent_state_root, mut parent_state) = chain
|
||||
.store
|
||||
.get_advanced_hot_state(block_parent_root, blob_slot, parent_block.state_root)
|
||||
.map_err(|e| GossipBlobError::BeaconChainError(Box::new(e.into())))?
|
||||
.ok_or_else(|| {
|
||||
BeaconChainError::DBInconsistent(format!(
|
||||
"Missing state for parent block {block_parent_root:?}",
|
||||
))
|
||||
})?;
|
||||
|
||||
let state = cheap_state_advance_to_obtain_committees::<_, GossipBlobError>(
|
||||
&mut parent_state,
|
||||
Some(parent_state_root),
|
||||
blob_slot,
|
||||
&chain.spec,
|
||||
)?;
|
||||
|
||||
let epoch = state.current_epoch();
|
||||
let proposers = state.get_beacon_proposer_indices(epoch, &chain.spec)?;
|
||||
let proposer_index = *proposers
|
||||
.get(blob_slot.as_usize() % T::EthSpec::slots_per_epoch() as usize)
|
||||
.ok_or_else(|| BeaconChainError::NoProposerForSlot(blob_slot))?;
|
||||
|
||||
// Prime the proposer shuffling cache with the newly-learned value.
|
||||
chain.beacon_proposer_cache.lock().insert(
|
||||
blob_epoch,
|
||||
proposer_shuffling_root,
|
||||
proposers,
|
||||
state.fork(),
|
||||
)?;
|
||||
(proposer_index, state.fork())
|
||||
};
|
||||
let proposer = chain.with_proposer_cache(
|
||||
proposer_shuffling_root,
|
||||
blob_epoch,
|
||||
|proposers| proposers.get_slot::<T::EthSpec>(blob_slot),
|
||||
|| {
|
||||
debug!(
|
||||
%block_root,
|
||||
index = %blob_index,
|
||||
"Proposer shuffling cache miss for blob verification"
|
||||
);
|
||||
chain
|
||||
.store
|
||||
.get_advanced_hot_state(block_parent_root, blob_slot, parent_block.state_root)
|
||||
.map_err(|e| GossipBlobError::BeaconChainError(Box::new(e.into())))?
|
||||
.ok_or_else(|| {
|
||||
GossipBlobError::BeaconChainError(Box::new(BeaconChainError::DBInconsistent(
|
||||
format!("Missing state for parent block {block_parent_root:?}",),
|
||||
)))
|
||||
})
|
||||
},
|
||||
)?;
|
||||
let proposer_index = proposer.index;
|
||||
let fork = proposer.fork;
|
||||
|
||||
// Signature verify the signed block header.
|
||||
let signature_is_valid = {
|
||||
|
||||
Reference in New Issue
Block a user