actually - store bid

This commit is contained in:
Daniel Knopik
2026-04-29 09:34:06 +02:00
parent c76eb3e4c5
commit 215a07c22e
5 changed files with 77 additions and 60 deletions

View File

@@ -344,16 +344,22 @@ impl<T: BeaconChainTypes> DataAvailabilityRouter<T> {
self.pending_block_cache.get_cached_block(block_root) self.pending_block_cache.get_cached_block(block_root)
} }
/// Inserts a pre-execution block into the cache (v1). /// Inserts a pre-execution block into the cache.
pub fn put_pre_execution_block( pub fn put_pre_execution_block(
&self, &self,
block_root: Hash256, block_root: Hash256,
block: Arc<SignedBeaconBlock<T::EthSpec>>, block: Arc<SignedBeaconBlock<T::EthSpec>>,
source: BlockImportSource, source: BlockImportSource,
) -> Result<(), AvailabilityCheckError> { ) -> Result<(), AvailabilityCheckError> {
if let ForkName::Gloas = block.fork_name_unchecked() {
self.pending_payload_cache
.init_pending_block(block_root, block);
Ok(())
} else {
self.pending_block_cache self.pending_block_cache
.put_pre_execution_block(block_root, block, source) .put_pre_execution_block(block_root, block, source)
} }
}
/// Insert an executed block and check availability (v1). /// Insert an executed block and check availability (v1).
pub fn put_executed_block( pub fn put_executed_block(

View File

@@ -25,7 +25,7 @@ use state_processing::{BlockProcessingError, envelope_processing::EnvelopeProces
use store::Error as DBError; use store::Error as DBError;
use tracing::instrument; use tracing::instrument;
use types::{ use types::{
BeaconState, BeaconStateError, ChainSpec, DataColumnSidecarList, EthSpec, ExecutionBlockHash, BeaconState, BeaconStateError, DataColumnSidecarList, EthSpec, ExecutionBlockHash,
ExecutionPayloadEnvelope, Hash256, SignedExecutionPayloadEnvelope, Slot, ExecutionPayloadEnvelope, Hash256, SignedExecutionPayloadEnvelope, Slot,
}; };
@@ -57,7 +57,6 @@ pub struct AvailableEnvelope<E: EthSpec> {
pub columns: DataColumnSidecarList<E>, pub columns: DataColumnSidecarList<E>,
/// Timestamp at which this envelope first became available (UNIX timestamp, time since 1970). /// Timestamp at which this envelope first became available (UNIX timestamp, time since 1970).
pub columns_available_timestamp: Option<std::time::Duration>, pub columns_available_timestamp: Option<std::time::Duration>,
pub spec: Arc<ChainSpec>,
} }
impl<E: EthSpec> AvailableEnvelope<E> { impl<E: EthSpec> AvailableEnvelope<E> {
@@ -66,14 +65,12 @@ impl<E: EthSpec> AvailableEnvelope<E> {
envelope: Arc<SignedExecutionPayloadEnvelope<E>>, envelope: Arc<SignedExecutionPayloadEnvelope<E>>,
columns: DataColumnSidecarList<E>, columns: DataColumnSidecarList<E>,
columns_available_timestamp: Option<std::time::Duration>, columns_available_timestamp: Option<std::time::Duration>,
spec: Arc<ChainSpec>,
) -> Self { ) -> Self {
Self { Self {
execution_block_hash, execution_block_hash,
envelope, envelope,
columns, columns,
columns_available_timestamp, columns_available_timestamp,
spec,
} }
} }

View File

@@ -55,12 +55,13 @@ use task_executor::TaskExecutor;
use tracing::{Span, debug, error, instrument, trace}; use tracing::{Span, debug, error, instrument, trace};
use types::{ use types::{
ChainSpec, ColumnIndex, DataColumnSidecar, DataColumnSidecarList, Epoch, EthSpec, Hash256, ChainSpec, ColumnIndex, DataColumnSidecar, DataColumnSidecarList, Epoch, EthSpec, Hash256,
PartialDataColumnSidecarRef, Slot, PartialDataColumnSidecarRef, SignedBeaconBlock, Slot,
}; };
mod pending_column; mod pending_column;
mod pending_components; mod pending_components;
use crate::block_verification_types::AsBlock;
use crate::data_column_verification::{ use crate::data_column_verification::{
GossipVerifiedDataColumn, KzgVerifiedCustodyDataColumn, KzgVerifiedDataColumn, GossipVerifiedDataColumn, KzgVerifiedCustodyDataColumn, KzgVerifiedDataColumn,
}; };
@@ -159,7 +160,12 @@ impl<T: BeaconChainTypes> PendingPayloadCache<T> {
c.verified_data_columns c.verified_data_columns
.iter() .iter()
.filter_map(|(col_idx, col)| { .filter_map(|(col_idx, col)| {
col.try_to_sidecar(*col_idx, c.slot, block_root, c.num_blobs_expected) col.try_to_sidecar(
*col_idx,
c.block.slot(),
block_root,
c.num_blobs_expected(),
)
}) })
.collect() .collect()
}) })
@@ -229,11 +235,13 @@ impl<T: BeaconChainTypes> PendingPayloadCache<T> {
/// Initialize pending components for a block. Called when the beacon block (containing the /// Initialize pending components for a block. Called when the beacon block (containing the
/// bid) arrives. Sets up the slot and expected blob count so that subsequent column insertions /// bid) arrives. Sets up the slot and expected blob count so that subsequent column insertions
/// know how many cells to expect per column. /// know how many cells to expect per column.
pub fn init_pending_block(&self, block_root: Hash256, slot: Slot, num_blobs_expected: usize) { pub fn init_pending_block(
&self,
block_root: Hash256,
block: Arc<SignedBeaconBlock<T::EthSpec>>,
) {
let mut write_lock = self.availability_cache.write(); let mut write_lock = self.availability_cache.write();
write_lock.get_or_insert_mut(block_root, || { write_lock.get_or_insert_mut(block_root, || PendingComponents::empty(block_root, block));
PendingComponents::empty(block_root, slot, num_blobs_expected, self.spec.clone())
});
} }
/// Perform KZG verification on RPC custody columns and insert them into the cache. /// Perform KZG verification on RPC custody columns and insert them into the cache.
@@ -761,17 +769,6 @@ mod data_availability_checker_tests {
// once the Gloas harness can produce KZG-valid columns. These wrappers add KZG verification // once the Gloas harness can produce KZG-valid columns. These wrappers add KZG verification
// and custody column filtering on top of `put_kzg_verified_custody_data_columns`. // and custody column filtering on top of `put_kzg_verified_custody_data_columns`.
fn num_blobs_in_block<E: EthSpec>(block: &SignedBeaconBlock<E, FullPayload<E>>) -> usize {
block
.message()
.body()
.signed_execution_payload_bid()
.expect("gloas block should have bid")
.message
.blob_kzg_commitments
.len()
}
fn make_test_signed_envelope(block_root: Hash256) -> Arc<SignedExecutionPayloadEnvelope<E>> { fn make_test_signed_envelope(block_root: Hash256) -> Arc<SignedExecutionPayloadEnvelope<E>> {
Arc::new(SignedExecutionPayloadEnvelope { Arc::new(SignedExecutionPayloadEnvelope {
message: ExecutionPayloadEnvelope { message: ExecutionPayloadEnvelope {
@@ -817,7 +814,7 @@ mod data_availability_checker_tests {
); );
let block_root = Hash256::random(); let block_root = Hash256::random();
cache.init_pending_block(block_root, Slot::new(0), num_blobs_in_block(&block)); cache.init_pending_block(block_root, Arc::new(block));
let verified_columns: Vec<_> = data_columns let verified_columns: Vec<_> = data_columns
.into_iter() .into_iter()
@@ -861,7 +858,7 @@ mod data_availability_checker_tests {
); );
let block_root = Hash256::random(); let block_root = Hash256::random();
cache.init_pending_block(block_root, Slot::new(0), num_blobs_in_block(&block)); cache.init_pending_block(block_root, Arc::new(block));
let first_column = data_columns.first().cloned().expect("should have column"); let first_column = data_columns.first().cloned().expect("should have column");
let column_index = *first_column.index(); let column_index = *first_column.index();
@@ -907,7 +904,7 @@ mod data_availability_checker_tests {
); );
let block_root = Hash256::random(); let block_root = Hash256::random();
cache.init_pending_block(block_root, Slot::new(0), num_blobs_in_block(&block)); cache.init_pending_block(block_root, Arc::new(block));
let verified_columns: Vec<_> = data_columns let verified_columns: Vec<_> = data_columns
.into_iter() .into_iter()
@@ -946,7 +943,7 @@ mod data_availability_checker_tests {
); );
let block_root = Hash256::random(); let block_root = Hash256::random();
cache.init_pending_block(block_root, Slot::new(0), num_blobs_in_block(&block)); cache.init_pending_block(block_root, Arc::new(block));
let verified_columns: Vec<_> = data_columns let verified_columns: Vec<_> = data_columns
.into_iter() .into_iter()
@@ -982,10 +979,20 @@ mod data_availability_checker_tests {
} }
type T = DiskHarnessType<E>; type T = DiskHarnessType<E>;
let (_harness, cache, _path) = setup_harness_and_cache::<T>().await; let (harness, cache, _path) = setup_harness_and_cache::<T>().await;
let mut rng = StdRng::seed_from_u64(0xDEADBEEF);
let spec = harness.spec.clone();
let (block, _) = generate_rand_block_and_data_columns::<E>(
ForkName::Gloas,
NumBlobs::Number(0),
&mut rng,
&spec,
);
let block_root = Hash256::random(); let block_root = Hash256::random();
cache.init_pending_block(block_root, Slot::new(0), 0); cache.init_pending_block(block_root, Arc::new(block));
let executed_envelope = make_test_executed_envelope(block_root); let executed_envelope = make_test_executed_envelope(block_root);
let result = cache let result = cache
@@ -1019,7 +1026,7 @@ mod data_availability_checker_tests {
); );
let block_root = Hash256::random(); let block_root = Hash256::random();
cache.init_pending_block(block_root, Slot::new(0), num_blobs_in_block(&block)); cache.init_pending_block(block_root, Arc::new(block));
let verified_columns: Vec<_> = data_columns let verified_columns: Vec<_> = data_columns
.into_iter() .into_iter()
@@ -1088,7 +1095,7 @@ mod data_availability_checker_tests {
assert!(cache.get_data_columns(block_root).is_none()); assert!(cache.get_data_columns(block_root).is_none());
cache.init_pending_block(block_root, Slot::new(0), num_blobs_in_block(&block)); cache.init_pending_block(block_root, Arc::new(block));
let verified_columns: Vec<_> = data_columns let verified_columns: Vec<_> = data_columns
.into_iter() .into_iter()
@@ -1128,13 +1135,13 @@ mod data_availability_checker_tests {
&spec, &spec,
); );
let num_blobs = num_blobs_in_block(&block); let block = Arc::new(block);
let mut roots = Vec::new(); let mut roots = Vec::new();
for _ in 0..33 { for _ in 0..33 {
let block_root = Hash256::random(); let block_root = Hash256::random();
roots.push(block_root); roots.push(block_root);
cache.init_pending_block(block_root, Slot::new(0), num_blobs); cache.init_pending_block(block_root, block.clone());
let col = data_columns.first().cloned().expect("should have column"); let col = data_columns.first().cloned().expect("should have column");
let verified = vec![KzgVerifiedCustodyDataColumn::from_asserted_custody( let verified = vec![KzgVerifiedCustodyDataColumn::from_asserted_custody(
KzgVerifiedDataColumn::__new_for_testing(col), KzgVerifiedDataColumn::__new_for_testing(col),
@@ -1169,7 +1176,7 @@ mod data_availability_checker_tests {
); );
let block_root = Hash256::random(); let block_root = Hash256::random();
cache.init_pending_block(block_root, Slot::new(0), num_blobs_in_block(&block)); cache.init_pending_block(block_root, Arc::new(block));
let col = data_columns.first().cloned().expect("should have column"); let col = data_columns.first().cloned().expect("should have column");
let verified = vec![KzgVerifiedCustodyDataColumn::from_asserted_custody( let verified = vec![KzgVerifiedCustodyDataColumn::from_asserted_custody(
@@ -1209,7 +1216,7 @@ mod data_availability_checker_tests {
); );
let block_root = Hash256::random(); let block_root = Hash256::random();
cache.init_pending_block(block_root, Slot::new(0), num_blobs_in_block(&block)); cache.init_pending_block(block_root, Arc::new(block));
let executed_envelope = make_test_executed_envelope(block_root); let executed_envelope = make_test_executed_envelope(block_root);
cache cache

View File

@@ -8,31 +8,38 @@ use std::cmp::Ordering;
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::Arc; use std::sync::Arc;
use tracing::{Span, debug, debug_span}; use tracing::{Span, debug, debug_span};
use types::{ChainSpec, ColumnIndex, Epoch, EthSpec, Hash256}; use types::DataColumnSidecar;
use types::{DataColumnSidecar, Slot}; use types::{ColumnIndex, Epoch, EthSpec, Hash256, SignedBeaconBlock};
/// This represents the components of a payload pending data availability. /// This represents the components of a payload pending data availability.
/// ///
/// The columns are all gossip and kzg verified. /// The columns are all gossip and kzg verified.
/// The payload is considered "available" when all required columns are received. /// The payload is considered "available" when all required columns are received.
pub struct PendingComponents<E: EthSpec> { pub struct PendingComponents<E: EthSpec> {
pub slot: Slot, pub block: Arc<SignedBeaconBlock<E>>,
pub num_blobs_expected: usize,
/// a cached post executed payload envelope /// a cached post executed payload envelope
pub envelope: Option<AvailabilityPendingExecutedEnvelope<E>>, pub envelope: Option<AvailabilityPendingExecutedEnvelope<E>>,
pub verified_data_columns: HashMap<ColumnIndex, PendingColumn<E>>, pub verified_data_columns: HashMap<ColumnIndex, PendingColumn<E>>,
pub reconstruction_started: bool, pub reconstruction_started: bool,
pub(crate) span: Span, pub(crate) span: Span,
spec: Arc<ChainSpec>,
} }
impl<E: EthSpec> PendingComponents<E> { impl<E: EthSpec> PendingComponents<E> {
pub fn num_blobs_expected(&self) -> usize {
self.block.num_expected_blobs()
}
/// Returns the completed custody columns /// Returns the completed custody columns
pub fn get_cached_data_columns(&self, block_root: Hash256) -> Vec<Arc<DataColumnSidecar<E>>> { pub fn get_cached_data_columns(&self, block_root: Hash256) -> Vec<Arc<DataColumnSidecar<E>>> {
self.verified_data_columns self.verified_data_columns
.iter() .iter()
.filter_map(|(col_idx, col)| { .filter_map(|(col_idx, col)| {
col.try_to_sidecar(*col_idx, self.slot, block_root, self.num_blobs_expected) col.try_to_sidecar(
*col_idx,
self.block.slot(),
block_root,
self.num_blobs_expected(),
)
}) })
.collect() .collect()
} }
@@ -42,7 +49,8 @@ impl<E: EthSpec> PendingComponents<E> {
self.verified_data_columns self.verified_data_columns
.iter() .iter()
.filter_map(|(col_idx, col)| { .filter_map(|(col_idx, col)| {
col.is_complete(self.num_blobs_expected).then_some(*col_idx) col.is_complete(self.num_blobs_expected())
.then_some(*col_idx)
}) })
.collect() .collect()
} }
@@ -52,12 +60,13 @@ impl<E: EthSpec> PendingComponents<E> {
&mut self, &mut self,
kzg_verified_data_columns: I, kzg_verified_data_columns: I,
) -> Result<(), AvailabilityCheckError> { ) -> Result<(), AvailabilityCheckError> {
let num_blobs_expected = self.num_blobs_expected();
for data_column in kzg_verified_data_columns { for data_column in kzg_verified_data_columns {
let data_column = data_column.as_data_column(); let data_column = data_column.as_data_column();
let col = self let col = self
.verified_data_columns .verified_data_columns
.entry(*data_column.index()) .entry(*data_column.index())
.or_insert_with(|| PendingColumn::new_with_capacity(self.num_blobs_expected)); .or_insert_with(|| PendingColumn::new_with_capacity(num_blobs_expected));
for (cell_idx, (cell, proof)) in data_column for (cell_idx, (cell, proof)) in data_column
.column() .column()
.iter() .iter()
@@ -84,7 +93,7 @@ impl<E: EthSpec> PendingComponents<E> {
pub fn num_completed_columns(&self) -> usize { pub fn num_completed_columns(&self) -> usize {
self.verified_data_columns self.verified_data_columns
.values() .values()
.filter_map(|col| col.is_complete(self.num_blobs_expected).then_some(())) .filter_map(|col| col.is_complete(self.num_blobs_expected()).then_some(()))
.count() .count()
} }
@@ -105,7 +114,7 @@ impl<E: EthSpec> PendingComponents<E> {
payload_verification_outcome, payload_verification_outcome,
} = envelope; } = envelope;
let columns = if self.num_blobs_expected == 0 { let columns = if self.num_blobs_expected() == 0 {
self.span.in_scope(|| { self.span.in_scope(|| {
debug!("Bid has no blobs, data is available"); debug!("Bid has no blobs, data is available");
}); });
@@ -129,9 +138,9 @@ impl<E: EthSpec> PendingComponents<E> {
.filter_map(|(col_idx, col)| { .filter_map(|(col_idx, col)| {
col.try_to_sidecar( col.try_to_sidecar(
*col_idx, *col_idx,
self.slot, self.block.slot(),
block_hash, block_hash,
self.num_blobs_expected, self.num_blobs_expected(),
) )
}) })
.collect() .collect()
@@ -148,7 +157,6 @@ impl<E: EthSpec> PendingComponents<E> {
envelope: envelope.clone(), envelope: envelope.clone(),
columns, columns,
columns_available_timestamp: None, columns_available_timestamp: None,
spec: self.spec.clone(),
}; };
Ok(Some(AvailableExecutedEnvelope { Ok(Some(AvailableExecutedEnvelope {
@@ -159,28 +167,21 @@ impl<E: EthSpec> PendingComponents<E> {
} }
/// Returns an empty `PendingComponents` object with the given block root. /// Returns an empty `PendingComponents` object with the given block root.
pub fn empty( pub fn empty(block_root: Hash256, block: Arc<SignedBeaconBlock<E>>) -> Self {
block_root: Hash256, let span = debug_span!(parent: None, "lh_pending_components", %block_root);
slot: Slot,
num_blobs_expected: usize,
spec: Arc<ChainSpec>,
) -> Self {
let span = debug_span!(parent: None, "lh_pending_components", %block_root, %slot);
let _guard = span.clone().entered(); let _guard = span.clone().entered();
Self { Self {
slot, block,
num_blobs_expected,
envelope: None, envelope: None,
verified_data_columns: HashMap::new(), verified_data_columns: HashMap::new(),
reconstruction_started: false, reconstruction_started: false,
span, span,
spec,
} }
} }
/// Returns the epoch of the bid or first data column, if available. /// Returns the epoch of the bid or first data column, if available.
pub fn epoch(&self) -> Epoch { pub fn epoch(&self) -> Epoch {
self.slot.epoch(E::slots_per_epoch()) self.block.slot().epoch(E::slots_per_epoch())
} }
pub fn status_str(&self, num_expected_columns: usize) -> String { pub fn status_str(&self, num_expected_columns: usize) -> String {

View File

@@ -354,6 +354,12 @@ impl<E: EthSpec, Payload: AbstractExecPayload<E>> SignedBeaconBlock<E, Payload>
self.message() self.message()
.body() .body()
.blob_kzg_commitments() .blob_kzg_commitments()
.or_else(|_| {
self.message()
.body()
.signed_execution_payload_bid()
.map(|bid| &bid.message.blob_kzg_commitments)
})
.map(|c| c.len()) .map(|c| c.len())
.unwrap_or(0) .unwrap_or(0)
} }