Add Gloas data column support (#8682)

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

Co-Authored-By: Eitan Seri- Levi <eserilev@gmail.com>
This commit is contained in:
Eitan Seri-Levi
2026-01-27 20:52:12 -08:00
committed by GitHub
parent 0f57fc9d8e
commit 9bec8df37a
44 changed files with 1507 additions and 680 deletions

View File

@@ -1,5 +1,5 @@
use crate::fetch_blobs::{EngineGetBlobsOutput, FetchEngineBlobError};
use crate::observed_block_producers::ProposalKey;
use crate::observed_data_sidecars::ObservationKey;
use crate::{AvailabilityProcessingStatus, BeaconChain, BeaconChainTypes};
use execution_layer::json_structures::{BlobAndProofV1, BlobAndProofV2};
use kzg::Kzg;
@@ -67,27 +67,25 @@ impl<T: BeaconChainTypes> FetchBlobsBeaconAdapter<T> {
.map_err(FetchEngineBlobError::RequestFailed)
}
pub(crate) fn blobs_known_for_proposal(
pub(crate) fn blobs_known_for_observation_key(
&self,
proposer: u64,
slot: Slot,
observation_key: ObservationKey,
) -> Option<HashSet<u64>> {
let proposer_key = ProposalKey::new(proposer, slot);
self.chain
.observed_blob_sidecars
.read()
.known_for_proposal(&proposer_key)
.known_for_observation_key(&observation_key)
.cloned()
}
pub(crate) fn data_column_known_for_proposal(
pub(crate) fn data_column_known_for_observation_key(
&self,
proposal_key: ProposalKey,
observation_key: ObservationKey,
) -> Option<HashSet<ColumnIndex>> {
self.chain
.observed_column_sidecars
.read()
.known_for_proposal(&proposal_key)
.known_for_observation_key(&observation_key)
.cloned()
}

View File

@@ -18,7 +18,7 @@ use crate::data_column_verification::{KzgVerifiedCustodyDataColumn, KzgVerifiedD
#[cfg_attr(test, double)]
use crate::fetch_blobs::fetch_blobs_beacon_adapter::FetchBlobsBeaconAdapter;
use crate::kzg_utils::blobs_to_data_column_sidecars;
use crate::observed_block_producers::ProposalKey;
use crate::observed_data_sidecars::ObservationKey;
use crate::validator_monitor::timestamp_now;
use crate::{
AvailabilityProcessingStatus, BeaconChain, BeaconChainError, BeaconChainTypes, BlockError,
@@ -193,9 +193,10 @@ async fn fetch_and_process_blobs_v1<T: BeaconChainTypes>(
&kzg_commitments_proof,
)?;
if let Some(observed_blobs) =
chain_adapter.blobs_known_for_proposal(block.message().proposer_index(), block.slot())
{
let observation_key =
ObservationKey::new_proposer_key(block.message().proposer_index(), block.slot());
if let Some(observed_blobs) = chain_adapter.blobs_known_for_observation_key(observation_key) {
blob_sidecar_list.retain(|blob| !observed_blobs.contains(&blob.blob_index()));
if blob_sidecar_list.is_empty() {
debug!(
@@ -380,7 +381,7 @@ async fn compute_custody_columns_to_import<T: BeaconChainTypes>(
.map(|data_columns| {
data_columns
.into_iter()
.filter(|col| custody_columns_indices.contains(&col.index))
.filter(|col| custody_columns_indices.contains(col.index()))
.map(|col| {
KzgVerifiedCustodyDataColumn::from_asserted_custody(
KzgVerifiedDataColumn::from_execution_verified(col),
@@ -391,9 +392,11 @@ async fn compute_custody_columns_to_import<T: BeaconChainTypes>(
.map_err(FetchEngineBlobError::DataColumnSidecarError)?;
// Only consider columns that are not already observed on gossip.
if let Some(observed_columns) = chain_adapter_cloned.data_column_known_for_proposal(
ProposalKey::new(block.message().proposer_index(), block.slot()),
) {
let observation_key = ObservationKey::from_block(&block, block_root, &spec);
if let Some(observed_columns) =
chain_adapter_cloned.data_column_known_for_observation_key(observation_key)
{
custody_columns.retain(|col| !observed_columns.contains(&col.index()));
if custody_columns.is_empty() {
return Ok(vec![]);

View File

@@ -156,7 +156,7 @@ mod get_blobs_v2 {
mock_fork_choice_contains_block(&mut mock_adapter, vec![]);
// All data columns already seen on gossip
mock_adapter
.expect_data_column_known_for_proposal()
.expect_data_column_known_for_observation_key()
.returning(|_| Some(hashset![0, 1, 2]));
// No blobs should be processed
mock_adapter.expect_process_engine_blobs().times(0);
@@ -193,7 +193,7 @@ mod get_blobs_v2 {
mock_get_blobs_v2_response(&mut mock_adapter, Some(blobs_and_proofs));
mock_fork_choice_contains_block(&mut mock_adapter, vec![]);
mock_adapter
.expect_data_column_known_for_proposal()
.expect_data_column_known_for_observation_key()
.returning(|_| None);
mock_adapter
.expect_cached_data_column_indexes()
@@ -332,8 +332,8 @@ mod get_blobs_v1 {
.expect_cached_blob_indexes()
.returning(|_| None);
mock_adapter
.expect_blobs_known_for_proposal()
.returning(|_, _| None);
.expect_blobs_known_for_observation_key()
.returning(|_| None);
// Returned blobs should be processed
mock_process_engine_blobs_result(
&mut mock_adapter,
@@ -427,8 +427,8 @@ mod get_blobs_v1 {
.expect_cached_blob_indexes()
.returning(|_| None);
mock_adapter
.expect_blobs_known_for_proposal()
.returning(move |_, _| Some(all_blob_indices.clone()));
.expect_blobs_known_for_observation_key()
.returning(move |_| Some(all_blob_indices.clone()));
// **WHEN**: Trigger `fetch_blobs` on the block
let custody_columns: [ColumnIndex; 3] = [0, 1, 2];
@@ -467,8 +467,8 @@ mod get_blobs_v1 {
.expect_cached_blob_indexes()
.returning(|_| None);
mock_adapter
.expect_blobs_known_for_proposal()
.returning(|_, _| None);
.expect_blobs_known_for_observation_key()
.returning(|_| None);
mock_process_engine_blobs_result(
&mut mock_adapter,
Ok(AvailabilityProcessingStatus::Imported(block_root)),