Gloas payload envelope processing (#8806)

Co-Authored-By: Eitan Seri- Levi <eserilev@gmail.com>

Co-Authored-By: Eitan Seri-Levi <eserilev@ucsc.edu>

Co-Authored-By: Jimmy Chen <jchen.tc@gmail.com>

Co-Authored-By: Michael Sproul <michael@sigmaprime.io>

Co-Authored-By: Michael Sproul <michaelsproul@users.noreply.github.com>
This commit is contained in:
Eitan Seri-Levi
2026-03-09 14:23:34 +09:00
committed by GitHub
parent 537c2ba8b3
commit 7dab32dd16
19 changed files with 1813 additions and 127 deletions

View File

@@ -4,9 +4,7 @@ use crate::attestation_verification::{
batch_verify_unaggregated_attestations,
};
use crate::beacon_block_streamer::{BeaconBlockStreamer, CheckCaches};
use crate::beacon_proposer_cache::{
BeaconProposerCache, EpochBlockProposers, ensure_state_can_determine_proposers_for_epoch,
};
use crate::beacon_proposer_cache::{BeaconProposerCache, EpochBlockProposers};
use crate::blob_verification::{GossipBlobError, GossipVerifiedBlob};
use crate::block_times_cache::BlockTimesCache;
use crate::block_verification::{
@@ -26,6 +24,7 @@ use crate::data_availability_checker::{
};
use crate::data_column_verification::{GossipDataColumnError, GossipVerifiedDataColumn};
use crate::early_attester_cache::EarlyAttesterCache;
use crate::envelope_times_cache::EnvelopeTimesCache;
use crate::errors::{BeaconChainError as Error, BlockProductionError};
use crate::events::ServerSentEventHandler;
use crate::execution_payload::{NotifyExecutionLayer, PreparePayloadHandle, get_execution_payload};
@@ -66,7 +65,6 @@ use crate::sync_committee_verification::{
};
use crate::validator_monitor::{
HISTORIC_EPOCHS as VALIDATOR_MONITOR_HISTORIC_EPOCHS, ValidatorMonitor, get_slot_delay_ms,
timestamp_now,
};
use crate::validator_pubkey_cache::ValidatorPubkeyCache;
use crate::{
@@ -462,6 +460,8 @@ pub struct BeaconChain<T: BeaconChainTypes> {
pub early_attester_cache: EarlyAttesterCache<T::EthSpec>,
/// A cache used to keep track of various block timings.
pub block_times_cache: Arc<RwLock<BlockTimesCache>>,
/// A cache used to keep track of various envelope timings.
pub envelope_times_cache: Arc<RwLock<EnvelopeTimesCache>>,
/// A cache used to track pre-finalization block roots for quick rejection.
pub pre_finalization_block_cache: PreFinalizationBlockCache,
/// A cache used to produce light_client server messages
@@ -4042,23 +4042,10 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
// See https://github.com/sigp/lighthouse/issues/2028
let (_, signed_block, block_data) = signed_block.deconstruct();
match self.get_blobs_or_columns_store_op(block_root, signed_block.slot(), block_data) {
Ok(Some(blobs_or_columns_store_op)) => {
ops.push(blobs_or_columns_store_op);
}
Ok(None) => {}
Err(e) => {
error!(
msg = "Restoring fork choice from disk",
error = &e,
?block_root,
"Failed to store data columns into the database"
);
return Err(self
.handle_import_block_db_write_error(fork_choice)
.err()
.unwrap_or(BlockError::InternalError(e)));
}
if let Some(blobs_or_columns_store_op) =
self.get_blobs_or_columns_store_op(block_root, signed_block.slot(), block_data)
{
ops.push(blobs_or_columns_store_op);
}
let block = signed_block.message();
@@ -4088,7 +4075,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
// We're declaring the block "imported" at this point, since fork choice and the DB know
// about it.
let block_time_imported = timestamp_now();
let block_time_imported = self.slot_clock.now_duration().unwrap_or(Duration::MAX);
// compute state proofs for light client updates before inserting the state into the
// snapshot cache.
@@ -4157,7 +4144,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
}
/// Check block's consistentency with any configured weak subjectivity checkpoint.
fn check_block_against_weak_subjectivity_checkpoint(
pub(crate) fn check_block_against_weak_subjectivity_checkpoint(
&self,
block: BeaconBlockRef<T::EthSpec>,
block_root: Hash256,
@@ -6407,6 +6394,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
// sync anyway).
self.naive_aggregation_pool.write().prune(slot);
self.block_times_cache.write().prune(slot);
self.envelope_times_cache.write().prune(slot);
// Don't run heavy-weight tasks during sync.
if self.best_slot() + MAX_PER_SLOT_FORK_CHOICE_DISTANCE < slot {
@@ -6466,62 +6454,14 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
accessor: impl Fn(&EpochBlockProposers) -> Result<V, BeaconChainError>,
state_provider: impl FnOnce() -> Result<(Hash256, BeaconState<T::EthSpec>), E>,
) -> Result<V, E> {
let cache_entry = self
.beacon_proposer_cache
.lock()
.get_or_insert_key(proposal_epoch, shuffling_decision_block);
// If the cache entry is not initialised, run the code to initialise it inside a OnceCell.
// This prevents duplication of work across multiple threads.
//
// If it is already initialised, then `get_or_try_init` will return immediately without
// executing the initialisation code at all.
let epoch_block_proposers = cache_entry.get_or_try_init(|| {
// Fetch the state on-demand if the required epoch was missing from the cache.
// If the caller wants to not compute the state they must return an error here and then
// catch it at the call site.
let (state_root, mut state) = state_provider()?;
// Ensure the state can compute proposer duties for `epoch`.
ensure_state_can_determine_proposers_for_epoch(
&mut state,
state_root,
proposal_epoch,
&self.spec,
)?;
// Sanity check the state.
let latest_block_root = state.get_latest_block_root(state_root);
let state_decision_block_root = state.proposer_shuffling_decision_root_at_epoch(
proposal_epoch,
latest_block_root,
&self.spec,
)?;
if state_decision_block_root != shuffling_decision_block {
return Err(Error::ProposerCacheIncorrectState {
state_decision_block_root,
requested_decision_block_root: shuffling_decision_block,
}
.into());
}
let proposers = state.get_beacon_proposer_indices(proposal_epoch, &self.spec)?;
// Use fork_at_epoch rather than the state's fork, because post-Fulu we may not have
// advanced the state completely into the new epoch.
let fork = self.spec.fork_at_epoch(proposal_epoch);
debug!(
?shuffling_decision_block,
epoch = %proposal_epoch,
"Priming proposer shuffling cache"
);
Ok::<_, E>(EpochBlockProposers::new(proposal_epoch, fork, proposers))
})?;
// Run the accessor function on the computed epoch proposers.
accessor(epoch_block_proposers).map_err(Into::into)
crate::beacon_proposer_cache::with_proposer_cache(
&self.beacon_proposer_cache,
shuffling_decision_block,
proposal_epoch,
accessor,
state_provider,
&self.spec,
)
}
/// Runs the `map_fn` with the committee cache for `shuffling_epoch` from the chain with head
@@ -7197,16 +7137,16 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
block_root: Hash256,
block_slot: Slot,
block_data: AvailableBlockData<T::EthSpec>,
) -> Result<Option<StoreOp<'_, T::EthSpec>>, String> {
) -> Option<StoreOp<'_, T::EthSpec>> {
match block_data {
AvailableBlockData::NoData => Ok(None),
AvailableBlockData::NoData => None,
AvailableBlockData::Blobs(blobs) => {
debug!(
%block_root,
count = blobs.len(),
"Writing blobs to store"
);
Ok(Some(StoreOp::PutBlobs(block_root, blobs)))
Some(StoreOp::PutBlobs(block_root, blobs))
}
AvailableBlockData::DataColumns(mut data_columns) => {
let columns_to_custody = self.custody_columns_for_epoch(Some(
@@ -7222,7 +7162,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
count = data_columns.len(),
"Writing data columns to store"
);
Ok(Some(StoreOp::PutDataColumns(block_root, data_columns)))
Some(StoreOp::PutDataColumns(block_root, data_columns))
}
}
}