Add range sync machinery on sync side

This commit is contained in:
Pawan Dhananjay
2026-03-30 17:00:29 -07:00
parent 0f996ddbe8
commit 4ca10e95be
12 changed files with 538 additions and 72 deletions

View File

@@ -2,10 +2,11 @@ use crate::data_availability_checker::{AvailabilityCheckError, DataAvailabilityC
pub use crate::data_availability_checker::{
AvailableBlock, AvailableBlockData, MaybeAvailableBlock,
};
use crate::payload_envelope_verification::AvailableEnvelope;
use crate::{BeaconChainTypes, PayloadVerificationOutcome};
use educe::Educe;
use state_processing::ConsensusContext;
use std::fmt::{Debug, Formatter};
use std::hash::{Hash, Hasher};
use std::sync::Arc;
use types::data::BlobIdentifier;
use types::{
@@ -40,43 +41,63 @@ impl<E: EthSpec> LookupBlock<E> {
}
}
/// A fully available block that has been constructed by range sync.
/// The block contains all the data required to import into fork choice.
/// This includes any and all blobs/columns required, including zero if
/// none are required. This can happen if the block is pre-deneb or if
/// it's simply past the DA boundary.
#[derive(Clone, Educe)]
#[educe(Hash(bound(E: EthSpec)))]
pub struct RangeSyncBlock<E: EthSpec> {
block: AvailableBlock<E>,
/// A block that has been constructed by range sync with all required data.
///
/// - `Base`: Pre-Gloas blocks bundled as an `AvailableBlock` (block + blobs/columns).
/// - `Gloas`: Post-Gloas blocks where the execution payload is a separate envelope.
#[derive(Clone)]
pub enum RangeSyncBlock<E: EthSpec> {
Base(AvailableBlock<E>),
Gloas {
block: Arc<SignedBeaconBlock<E>>,
envelope: Option<Box<AvailableEnvelope<E>>>,
},
}
impl<E: EthSpec> Hash for RangeSyncBlock<E> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.block_root().hash(state);
}
}
impl<E: EthSpec> Debug for RangeSyncBlock<E> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "RpcBlock({:?})", self.block_root())
write!(f, "RangeSyncBlock({:?})", self.block_root())
}
}
impl<E: EthSpec> RangeSyncBlock<E> {
pub fn block_root(&self) -> Hash256 {
self.block.block_root()
match self {
Self::Base(block) => block.block_root(),
Self::Gloas { block, .. } => block.canonical_root(),
}
}
pub fn as_block(&self) -> &SignedBeaconBlock<E> {
self.block.block()
match self {
Self::Base(block) => block.block(),
Self::Gloas { block, .. } => block,
}
}
pub fn block_cloned(&self) -> Arc<SignedBeaconBlock<E>> {
self.block.block_cloned()
match self {
Self::Base(block) => block.block_cloned(),
Self::Gloas { block, .. } => block.clone(),
}
}
pub fn block_data(&self) -> &AvailableBlockData<E> {
self.block.data()
match self {
Self::Base(block) => block.data(),
Self::Gloas { .. } => {
unreachable!("block_data called on Gloas variant — use envelope data instead")
}
}
}
}
impl<E: EthSpec> RangeSyncBlock<E> {
/// Constructs an `RangeSyncBlock` from a block and availability data.
/// Constructs a `Base` variant from a block and availability data.
///
/// # Errors
///
@@ -94,32 +115,54 @@ impl<E: EthSpec> RangeSyncBlock<E> {
T: BeaconChainTypes<EthSpec = E>,
{
let available_block = AvailableBlock::new(block, block_data, da_checker, spec)?;
Ok(Self {
block: available_block,
})
Ok(Self::Base(available_block))
}
/// Constructs a `Gloas` variant from a block and optional available envelope.
pub fn new_gloas(
block: Arc<SignedBeaconBlock<E>>,
envelope: Option<Box<AvailableEnvelope<E>>>,
) -> Self {
Self::Gloas { block, envelope }
}
#[allow(clippy::type_complexity)]
pub fn deconstruct(self) -> (Hash256, Arc<SignedBeaconBlock<E>>, AvailableBlockData<E>) {
self.block.deconstruct()
match self {
Self::Base(block) => block.deconstruct(),
Self::Gloas { .. } => {
unreachable!("deconstruct called on Gloas variant")
}
}
}
pub fn n_blobs(&self) -> usize {
match self.block_data() {
AvailableBlockData::NoData | AvailableBlockData::DataColumns(_) => 0,
AvailableBlockData::Blobs(blobs) => blobs.len(),
match self {
Self::Base(block) => match block.data() {
AvailableBlockData::NoData | AvailableBlockData::DataColumns(_) => 0,
AvailableBlockData::Blobs(blobs) => blobs.len(),
},
Self::Gloas { .. } => 0,
}
}
pub fn n_data_columns(&self) -> usize {
match self.block_data() {
AvailableBlockData::NoData | AvailableBlockData::Blobs(_) => 0,
AvailableBlockData::DataColumns(columns) => columns.len(),
match self {
Self::Base(block) => match block.data() {
AvailableBlockData::NoData | AvailableBlockData::Blobs(_) => 0,
AvailableBlockData::DataColumns(columns) => columns.len(),
},
Self::Gloas { .. } => 0,
}
}
pub fn into_available_block(self) -> AvailableBlock<E> {
self.block
match self {
Self::Base(block) => block,
Self::Gloas { .. } => {
unreachable!("into_available_block called on Gloas variant")
}
}
}
}
@@ -405,13 +448,13 @@ impl<E: EthSpec> AsBlock<E> for RangeSyncBlock<E> {
self.as_block().message()
}
fn as_block(&self) -> &SignedBeaconBlock<E> {
self.block.as_block()
RangeSyncBlock::as_block(self)
}
fn block_cloned(&self) -> Arc<SignedBeaconBlock<E>> {
self.block.block_cloned()
RangeSyncBlock::block_cloned(self)
}
fn canonical_root(&self) -> Hash256 {
self.block.block_root()
self.block_root()
}
}

View File

@@ -20,7 +20,7 @@ use tracing::{debug, error, instrument};
use types::data::{BlobIdentifier, FixedBlobSidecarList};
use types::{
BlobSidecar, BlobSidecarList, BlockImportSource, ChainSpec, DataColumnSidecar,
DataColumnSidecarList, Epoch, EthSpec, Hash256, SignedBeaconBlock, Slot,
DataColumnSidecarList, Epoch, EthSpec, ForkName, Hash256, SignedBeaconBlock, Slot,
};
mod error;
@@ -420,6 +420,11 @@ impl<T: BeaconChainTypes> DataAvailabilityChecker<T> {
self.da_check_required_for_epoch(epoch) && self.spec.is_peer_das_enabled_for_epoch(epoch)
}
/// Determines if execution payload envelopes are required for an epoch (Gloas and later).
pub fn envelopes_required_for_epoch(&self, epoch: Epoch) -> bool {
self.spec.fork_name_at_epoch(epoch) >= ForkName::Gloas
}
/// See `Self::blobs_required_for_epoch`
fn blobs_required_for_block(&self, block: &SignedBeaconBlock<T::EthSpec>) -> bool {
block.num_expected_blobs() > 0 && self.blobs_required_for_epoch(block.epoch())

View File

@@ -47,7 +47,7 @@ pub struct EnvelopeImportData<E: EthSpec> {
pub post_state: Box<BeaconState<E>>,
}
#[derive(Debug)]
#[derive(Debug, Clone)]
#[allow(dead_code)]
pub struct AvailableEnvelope<E: EthSpec> {
execution_block_hash: ExecutionBlockHash,