Fix wrong columns getting processed on a CGC change (#7792)

This PR fixes a bug where wrong columns could get processed immediately after a CGC increase.

Scenario:
- The node's CGC increased due to additional validators attached to it (lets say from 10 to 11)
- The new CGC is advertised and new subnets are subscribed immediately, however the change won't be effective in the data availability check until the next epoch (See [this](ab0e8870b4/beacon_node/beacon_chain/src/validator_custody.rs (L93-L99))). Data availability checker still only require 10 columns for the current epoch.
- During this time, data columns for the additional custody column (lets say column 11) may arrive via gossip as we're already subscribed to the topic, and it may be incorrectly used to satisfy the existing data availability requirement (10 columns), and result in this additional column (instead of a required one) getting persisted, resulting in database inconsistency.
This commit is contained in:
Jimmy Chen
2025-08-07 10:45:04 +10:00
committed by GitHub
parent 9c972201bc
commit 8bc6693dac
27 changed files with 577 additions and 277 deletions

View File

@@ -2206,7 +2206,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
pub fn verify_data_column_sidecar_for_gossip(
self: &Arc<Self>,
data_column_sidecar: Arc<DataColumnSidecar<T::EthSpec>>,
subnet_id: u64,
subnet_id: DataColumnSubnetId,
) -> Result<GossipVerifiedDataColumn<T>, GossipDataColumnError> {
metrics::inc_counter(&metrics::DATA_COLUMN_SIDECAR_PROCESSING_REQUESTS);
let _timer = metrics::start_timer(&metrics::DATA_COLUMN_SIDECAR_GOSSIP_VERIFICATION_TIMES);
@@ -3594,7 +3594,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
let availability = self
.data_availability_checker
.put_gossip_verified_data_columns(block_root, data_columns)?;
.put_gossip_verified_data_columns(block_root, slot, data_columns)?;
self.process_availability(slot, availability, publish_fn)
.await
@@ -3685,9 +3685,11 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
// This slot value is purely informative for the consumers of
// `AvailabilityProcessingStatus::MissingComponents` to log an error with a slot.
let availability = self
.data_availability_checker
.put_rpc_custody_columns(block_root, custody_columns)?;
let availability = self.data_availability_checker.put_rpc_custody_columns(
block_root,
slot,
custody_columns,
)?;
self.process_availability(slot, availability, || Ok(()))
.await
@@ -7110,6 +7112,14 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
roots.reverse();
roots
}
/// Returns a list of column indices that should be sampled for a given epoch.
/// Used for data availability sampling in PeerDAS.
pub fn sampling_columns_for_epoch(&self, epoch: Epoch) -> &[ColumnIndex] {
self.data_availability_checker
.custody_context()
.sampling_columns_for_epoch(epoch, &self.spec)
}
}
impl<T: BeaconChainTypes> Drop for BeaconChain<T> {