Skip to content

Commit 46dde9a

Browse files
Fix data column rpc request (#8247)
Fixes an issue mentioned in this comment regarding data column rpc requests: #6572 (comment) Co-Authored-By: Eitan Seri-Levi <[email protected]> Co-Authored-By: Michael Sproul <[email protected]>
1 parent 21bab08 commit 46dde9a

File tree

3 files changed

+130
-22
lines changed

3 files changed

+130
-22
lines changed

beacon_node/beacon_chain/src/beacon_chain.rs

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6946,9 +6946,49 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
69466946
pub fn update_data_column_custody_info(&self, slot: Option<Slot>) {
69476947
self.store
69486948
.put_data_column_custody_info(slot)
6949-
.unwrap_or_else(
6950-
|e| tracing::error!(error = ?e, "Failed to update data column custody info"),
6951-
);
6949+
.unwrap_or_else(|e| error!(error = ?e, "Failed to update data column custody info"));
6950+
}
6951+
6952+
/// Get the earliest epoch in which the node has met its custody requirements.
6953+
/// A `None` response indicates that we've met our custody requirements up to the
6954+
/// column data availability window
6955+
pub fn earliest_custodied_data_column_epoch(&self) -> Option<Epoch> {
6956+
self.store
6957+
.get_data_column_custody_info()
6958+
.inspect_err(
6959+
|e| error!(error=?e, "Failed to get data column custody info from the store"),
6960+
)
6961+
.ok()
6962+
.flatten()
6963+
.and_then(|info| info.earliest_data_column_slot)
6964+
.map(|slot| {
6965+
let mut epoch = slot.epoch(T::EthSpec::slots_per_epoch());
6966+
// If the earliest custodied slot isn't the first slot in the epoch
6967+
// The node has only met its custody requirements for the next epoch.
6968+
if slot > epoch.start_slot(T::EthSpec::slots_per_epoch()) {
6969+
epoch += 1;
6970+
}
6971+
epoch
6972+
})
6973+
}
6974+
6975+
/// The data availability boundary for custodying columns. It will just be the
6976+
/// regular data availability boundary unless we are near the Fulu fork epoch.
6977+
pub fn column_data_availability_boundary(&self) -> Option<Epoch> {
6978+
match self.data_availability_boundary() {
6979+
Some(da_boundary_epoch) => {
6980+
if let Some(fulu_fork_epoch) = self.spec.fulu_fork_epoch {
6981+
if da_boundary_epoch < fulu_fork_epoch {
6982+
Some(fulu_fork_epoch)
6983+
} else {
6984+
Some(da_boundary_epoch)
6985+
}
6986+
} else {
6987+
None // Fulu hasn't been enabled
6988+
}
6989+
}
6990+
None => None, // Deneb hasn't been enabled
6991+
}
69526992
}
69536993

69546994
/// This method serves to get a sense of the current chain health. It is used in block proposal

beacon_node/beacon_chain/tests/store_tests.rs

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4369,6 +4369,65 @@ async fn fulu_prune_data_columns_fork_boundary() {
43694369
check_data_column_existence(&harness, pruned_slot, harness.head_slot(), true);
43704370
}
43714371

4372+
#[tokio::test]
4373+
async fn test_column_da_boundary() {
4374+
let mut spec = ForkName::Electra.make_genesis_spec(E::default_spec());
4375+
let fulu_fork_epoch = Epoch::new(4);
4376+
spec.fulu_fork_epoch = Some(fulu_fork_epoch);
4377+
let db_path = tempdir().unwrap();
4378+
let store = get_store_generic(&db_path, StoreConfig::default(), spec);
4379+
4380+
if !store.get_chain_spec().is_peer_das_scheduled() {
4381+
// No-op if PeerDAS not scheduled.
4382+
panic!("PeerDAS not scheduled");
4383+
}
4384+
4385+
let harness = get_harness(store.clone(), LOW_VALIDATOR_COUNT);
4386+
4387+
// The column da boundary should be the fulu fork epoch
4388+
assert_eq!(
4389+
harness.chain.column_data_availability_boundary(),
4390+
Some(fulu_fork_epoch)
4391+
);
4392+
}
4393+
4394+
#[tokio::test]
4395+
async fn test_earliest_custodied_data_column_epoch() {
4396+
let spec = ForkName::Fulu.make_genesis_spec(E::default_spec());
4397+
let db_path = tempdir().unwrap();
4398+
let store = get_store_generic(&db_path, StoreConfig::default(), spec);
4399+
let custody_info_epoch = Epoch::new(4);
4400+
4401+
if !store.get_chain_spec().is_peer_das_scheduled() {
4402+
// No-op if PeerDAS not scheduled.
4403+
panic!("PeerDAS not scheduled");
4404+
}
4405+
4406+
let harness = get_harness(store.clone(), LOW_VALIDATOR_COUNT);
4407+
4408+
// earliest custody info is set to the last slot in `custody_info_epoch`
4409+
harness
4410+
.chain
4411+
.update_data_column_custody_info(Some(custody_info_epoch.end_slot(E::slots_per_epoch())));
4412+
4413+
// earliest custodied data column epoch should be `custody_info_epoch` + 1
4414+
assert_eq!(
4415+
harness.chain.earliest_custodied_data_column_epoch(),
4416+
Some(custody_info_epoch + 1)
4417+
);
4418+
4419+
// earliest custody info is set to the first slot in `custody_info_epoch`
4420+
harness
4421+
.chain
4422+
.update_data_column_custody_info(Some(custody_info_epoch.start_slot(E::slots_per_epoch())));
4423+
4424+
// earliest custodied data column epoch should be `custody_info_epoch`
4425+
assert_eq!(
4426+
harness.chain.earliest_custodied_data_column_epoch(),
4427+
Some(custody_info_epoch)
4428+
);
4429+
}
4430+
43724431
/// Check that blob pruning prunes data columns older than the data availability boundary with
43734432
/// margin applied.
43744433
#[tokio::test]

beacon_node/network/src/network_beacon_processor/rpc_methods.rs

Lines changed: 28 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1204,33 +1204,42 @@ impl<T: BeaconChainTypes> NetworkBeaconProcessor<T> {
12041204

12051205
let request_start_slot = Slot::from(req.start_slot);
12061206

1207-
let data_availability_boundary_slot = match self.chain.data_availability_boundary() {
1208-
Some(boundary) => boundary.start_slot(T::EthSpec::slots_per_epoch()),
1209-
None => {
1210-
debug!("Deneb fork is disabled");
1211-
return Err((RpcErrorResponse::InvalidRequest, "Deneb fork is disabled"));
1212-
}
1213-
};
1207+
let column_data_availability_boundary_slot =
1208+
match self.chain.column_data_availability_boundary() {
1209+
Some(boundary) => boundary.start_slot(T::EthSpec::slots_per_epoch()),
1210+
None => {
1211+
debug!("Fulu fork is disabled");
1212+
return Err((RpcErrorResponse::InvalidRequest, "Fulu fork is disabled"));
1213+
}
1214+
};
12141215

1215-
let oldest_data_column_slot = self
1216-
.chain
1217-
.store
1218-
.get_data_column_info()
1219-
.oldest_data_column_slot
1220-
.unwrap_or(data_availability_boundary_slot);
1216+
let earliest_custodied_data_column_slot =
1217+
match self.chain.earliest_custodied_data_column_epoch() {
1218+
Some(earliest_custodied_epoch) => {
1219+
let earliest_custodied_slot =
1220+
earliest_custodied_epoch.start_slot(T::EthSpec::slots_per_epoch());
1221+
// Ensure the earliest columns we serve are within the data availability window
1222+
if earliest_custodied_slot < column_data_availability_boundary_slot {
1223+
column_data_availability_boundary_slot
1224+
} else {
1225+
earliest_custodied_slot
1226+
}
1227+
}
1228+
None => column_data_availability_boundary_slot,
1229+
};
12211230

1222-
if request_start_slot < oldest_data_column_slot {
1231+
if request_start_slot < earliest_custodied_data_column_slot {
12231232
debug!(
12241233
%request_start_slot,
1225-
%oldest_data_column_slot,
1226-
%data_availability_boundary_slot,
1227-
"Range request start slot is older than data availability boundary."
1234+
%earliest_custodied_data_column_slot,
1235+
%column_data_availability_boundary_slot,
1236+
"Range request start slot is older than the earliest custodied data column slot."
12281237
);
12291238

1230-
return if data_availability_boundary_slot < oldest_data_column_slot {
1239+
return if earliest_custodied_data_column_slot > column_data_availability_boundary_slot {
12311240
Err((
12321241
RpcErrorResponse::ResourceUnavailable,
1233-
"blobs pruned within boundary",
1242+
"columns pruned within boundary",
12341243
))
12351244
} else {
12361245
Err((

0 commit comments

Comments
 (0)