diff --git a/beacon_node/beacon_chain/src/pending_payload_cache/mod.rs b/beacon_node/beacon_chain/src/pending_payload_cache/mod.rs index 5b46270a19..616e3ead32 100644 --- a/beacon_node/beacon_chain/src/pending_payload_cache/mod.rs +++ b/beacon_node/beacon_chain/src/pending_payload_cache/mod.rs @@ -174,14 +174,30 @@ impl PendingPayloadCache { }) } - /// Checks if a specific data column is cached for the given block root. + /// Filter out cells that are already cached for the given column sidecar. + /// Returns the cells that still need KZG verification, or `None` if all cells are cached. #[instrument(skip_all, level = "trace")] pub fn missing_cells_for_column_sidecar<'a>( &'_ self, data_column: &'a DataColumnSidecar, ) -> Result>, MissingCellsError> { - // TODO(gloas): implement cell-level missing check - Ok(None) + let block_root = data_column.block_root(); + let column_index = *data_column.index(); + + self.peek_pending_components(&block_root, |components| { + let Some(cached) = components.and_then(|c| c.verified_data_columns.get(&column_index)) + else { + return data_column.try_filter_to_partial_ref(|_, _, _| Ok(true)); + }; + + data_column.try_filter_to_partial_ref(|cell_idx, cell, proof| { + match cached.cell_matches(cell_idx, cell, proof) { + None => Ok(true), + Some(true) => Ok(false), + Some(false) => Err(MissingCellsError::MismatchesCachedColumn), + } + }) + }) } /// Insert an executed payload envelope into the cache and performs an availability check diff --git a/beacon_node/beacon_chain/src/pending_payload_cache/pending_column.rs b/beacon_node/beacon_chain/src/pending_payload_cache/pending_column.rs index 91c0d27b8c..ae2c556007 100644 --- a/beacon_node/beacon_chain/src/pending_payload_cache/pending_column.rs +++ b/beacon_node/beacon_chain/src/pending_payload_cache/pending_column.rs @@ -19,12 +19,23 @@ impl PendingColumn { if let Some(existing_cell) = self.cells.get_mut(index) && existing_cell.is_none() { - *existing_cell = Some((cell.clone(), proof)); + *existing_cell = Some((cell.clone(), *proof)); } } // TODO(gloas): insert_from_partial + pub fn has_cell(&self, index: usize) -> bool { + self.cells.get(index).is_some_and(|c| c.is_some()) + } + + pub fn cell_matches(&self, index: usize, cell: &Cell, proof: &KzgProof) -> Option { + self.cells + .get(index)? + .as_ref() + .map(|(c, p)| c == cell && p == proof) + } + pub fn is_complete(&self, blob_count: usize) -> bool { self.cells.len() == blob_count && self.cells.iter().all(|cell| cell.is_some()) } @@ -49,7 +60,7 @@ impl PendingColumn { }; // TODO(gloas): we likely want to go and arc all cells column.push(cell.clone()); - kzg_proofs.push(proof); + kzg_proofs.push(*proof); } Some(Arc::new(DataColumnSidecar::Gloas(DataColumnSidecarGloas {