Convert RpcBlock to an enum that indicates availability (#8424)

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

Co-Authored-By: Mark Mackey <mark@sigmaprime.io>

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

Co-Authored-By: Jimmy Chen <jchen.tc@gmail.com>
This commit is contained in:
Eitan Seri-Levi
2026-01-27 21:59:32 -08:00
committed by GitHub
parent c4409cdf28
commit f7b5c7ee3f
23 changed files with 1368 additions and 579 deletions

View File

@@ -1,12 +1,12 @@
use crate::blob_verification::GossipVerifiedBlob;
use crate::block_verification_types::{AsBlock, RpcBlock};
use crate::block_verification_types::{AsBlock, AvailableBlockData, RpcBlock};
use crate::custody_context::NodeCustodyType;
use crate::data_column_verification::CustodyDataColumn;
use crate::data_availability_checker::DataAvailabilityChecker;
use crate::graffiti_calculator::GraffitiSettings;
use crate::kzg_utils::{build_data_column_sidecars_fulu, build_data_column_sidecars_gloas};
use crate::observed_operations::ObservationOutcome;
pub use crate::persisted_beacon_chain::PersistedBeaconChain;
use crate::{BeaconBlockResponseWrapper, get_block_root};
use crate::{BeaconBlockResponseWrapper, CustodyContext, get_block_root};
use crate::{
BeaconChain, BeaconChainTypes, BlockError, ChainConfig, ServerSentEventHandler,
StateSkipConfig,
@@ -212,6 +212,34 @@ pub fn test_spec<E: EthSpec>() -> ChainSpec {
spec.target_aggregators_per_committee = DEFAULT_TARGET_AGGREGATORS;
spec
}
pub fn test_da_checker<E: EthSpec>(
spec: Arc<ChainSpec>,
node_custody_type: NodeCustodyType,
) -> DataAvailabilityChecker<EphemeralHarnessType<E>> {
let slot_clock = TestingSlotClock::new(
Slot::new(0),
Duration::from_secs(0),
Duration::from_secs(spec.seconds_per_slot),
);
let kzg = get_kzg(&spec);
let store = Arc::new(HotColdDB::open_ephemeral(<_>::default(), spec.clone()).unwrap());
let ordered_custody_column_indices = generate_data_column_indices_rand_order::<E>();
let custody_context = Arc::new(CustodyContext::new(
node_custody_type,
ordered_custody_column_indices,
&spec,
));
let complete_blob_backfill = false;
DataAvailabilityChecker::new(
complete_blob_backfill,
slot_clock,
kzg,
store,
custody_context,
spec,
)
.expect("should initialise data availability checker")
}
pub struct Builder<T: BeaconChainTypes> {
eth_spec_instance: T::EthSpec,
@@ -2380,8 +2408,16 @@ where
) -> Result<SignedBeaconBlockHash, BlockError> {
self.set_current_slot(slot);
let (block, blob_items) = block_contents;
// Determine if block is available: it's available if it doesn't require blobs,
// or if it requires blobs and we have them
let has_blob_commitments = block
.message()
.body()
.blob_kzg_commitments()
.is_ok_and(|c| !c.is_empty());
let is_available = !has_blob_commitments || blob_items.is_some();
let rpc_block = self.build_rpc_block_from_blobs(block_root, block, blob_items)?;
let rpc_block = self.build_rpc_block_from_blobs(block, blob_items, is_available)?;
let block_hash: SignedBeaconBlockHash = self
.chain
.process_block(
@@ -2405,7 +2441,15 @@ where
let (block, blob_items) = block_contents;
let block_root = block.canonical_root();
let rpc_block = self.build_rpc_block_from_blobs(block_root, block, blob_items)?;
// Determine if block is available: it's available if it doesn't require blobs,
// or if it requires blobs and we have them
let has_blob_commitments = block
.message()
.body()
.blob_kzg_commitments()
.is_ok_and(|c| !c.is_empty());
let is_available = !has_blob_commitments || blob_items.is_some();
let rpc_block = self.build_rpc_block_from_blobs(block, blob_items, is_available)?;
let block_hash: SignedBeaconBlockHash = self
.chain
.process_block(
@@ -2436,7 +2480,13 @@ where
.blob_kzg_commitments()
.is_ok_and(|c| !c.is_empty());
if !has_blobs {
return RpcBlock::new_without_blobs(Some(block_root), block);
return RpcBlock::new(
block,
Some(AvailableBlockData::NoData),
&self.chain.data_availability_checker,
self.chain.spec.clone(),
)
.unwrap();
}
// Blobs are stored as data columns from Fulu (PeerDAS)
@@ -2447,23 +2497,39 @@ where
.get_data_columns(&block_root, fork_name)
.unwrap()
.unwrap();
let custody_columns = columns
.into_iter()
.map(CustodyDataColumn::from_asserted_custody)
.collect::<Vec<_>>();
RpcBlock::new_with_custody_columns(Some(block_root), block, custody_columns).unwrap()
let custody_columns = columns.into_iter().collect::<Vec<_>>();
let block_data = AvailableBlockData::new_with_data_columns(custody_columns);
RpcBlock::new(
block,
Some(block_data),
&self.chain.data_availability_checker,
self.chain.spec.clone(),
)
.unwrap()
} else {
let blobs = self.chain.get_blobs(&block_root).unwrap().blobs();
RpcBlock::new(Some(block_root), block, blobs).unwrap()
let block_data = if let Some(blobs) = blobs {
AvailableBlockData::new_with_blobs(blobs)
} else {
AvailableBlockData::NoData
};
RpcBlock::new(
block,
Some(block_data),
&self.chain.data_availability_checker,
self.chain.spec.clone(),
)
.unwrap()
}
}
/// Builds an `RpcBlock` from a `SignedBeaconBlock` and `BlobsList`.
pub fn build_rpc_block_from_blobs(
&self,
block_root: Hash256,
block: Arc<SignedBeaconBlock<E, FullPayload<E>>>,
blob_items: Option<(KzgProofs<E>, BlobsList<E>)>,
is_available: bool,
) -> Result<RpcBlock<E>, BlockError> {
Ok(if self.spec.is_peer_das_enabled_for_epoch(block.epoch()) {
let epoch = block.slot().epoch(E::slots_per_epoch());
@@ -2476,11 +2542,37 @@ where
let columns = generate_data_column_sidecars_from_block(&block, &self.spec)
.into_iter()
.filter(|d| sampling_columns.contains(d.index()))
.map(CustodyDataColumn::from_asserted_custody)
.collect::<Vec<_>>();
RpcBlock::new_with_custody_columns(Some(block_root), block, columns)?
if is_available {
let block_data = AvailableBlockData::new_with_data_columns(columns);
RpcBlock::new(
block,
Some(block_data),
&self.chain.data_availability_checker,
self.chain.spec.clone(),
)?
} else {
RpcBlock::new(
block,
None,
&self.chain.data_availability_checker,
self.chain.spec.clone(),
)?
}
} else if is_available {
RpcBlock::new(
block,
Some(AvailableBlockData::NoData),
&self.chain.data_availability_checker,
self.chain.spec.clone(),
)?
} else {
RpcBlock::new_without_blobs(Some(block_root), block)
RpcBlock::new(
block,
None,
&self.chain.data_availability_checker,
self.chain.spec.clone(),
)?
}
} else {
let blobs = blob_items
@@ -2489,7 +2581,27 @@ where
})
.transpose()
.unwrap();
RpcBlock::new(Some(block_root), block, blobs)?
if is_available {
let block_data = if let Some(blobs) = blobs {
AvailableBlockData::new_with_blobs(blobs)
} else {
AvailableBlockData::NoData
};
RpcBlock::new(
block,
Some(block_data),
&self.chain.data_availability_checker,
self.chain.spec.clone(),
)?
} else {
RpcBlock::new(
block,
None,
&self.chain.data_availability_checker,
self.chain.spec.clone(),
)?
}
})
}