Avoid unnecessary database lookups in data column RPC requests (#7897)

This PR is an optimisation to avoid unnecessary database lookups when peer requests data columns that the node doesn't custody (advertised via `cgc`).

e.g. an extreme but realistic example - a full node only store 4 custody columns by default, but it may receive a range request of 32 slots with all 128 columns, and this would result in 4096 database lookups but the node is only able to get 128 (4 * 32) of them.


  - Filter data column RPC requests (`DataColumnsByRoot`, `DataColumnsByRange`) to only lookup columns the node custodies
- Prevents unnecessary database queries that would always fail for non-custody columns
This commit is contained in:
Jimmy Chen
2025-08-20 15:08:53 +10:00
committed by GitHub
parent f6859b1137
commit 2d223575d6
3 changed files with 136 additions and 2 deletions

View File

@@ -364,11 +364,19 @@ impl<T: BeaconChainTypes> NetworkBeaconProcessor<T> {
request: DataColumnsByRootRequest<T::EthSpec>,
) -> Result<(), (RpcErrorResponse, &'static str)> {
let mut send_data_column_count = 0;
// Only attempt lookups for columns the node has advertised and is responsible for maintaining custody of.
let available_columns = self.chain.custody_columns_for_epoch(None);
for data_column_ids_by_root in request.data_column_ids.as_slice() {
let indices_to_retrieve = data_column_ids_by_root
.columns
.iter()
.copied()
.filter(|c| available_columns.contains(c))
.collect::<Vec<_>>();
match self.chain.get_data_columns_checking_all_caches(
data_column_ids_by_root.block_root,
data_column_ids_by_root.columns.iter().as_slice(),
&indices_to_retrieve,
) {
Ok(data_columns) => {
send_data_column_count += data_columns.len();
@@ -1070,8 +1078,14 @@ impl<T: BeaconChainTypes> NetworkBeaconProcessor<T> {
self.get_block_roots_for_slot_range(req.start_slot, req.count, "DataColumnsByRange")?;
let mut data_columns_sent = 0;
// Only attempt lookups for columns the node has advertised and is responsible for maintaining custody of.
let request_start_epoch = request_start_slot.epoch(T::EthSpec::slots_per_epoch());
let available_columns = self
.chain
.custody_columns_for_epoch(Some(request_start_epoch));
for root in block_roots {
for index in &req.columns {
for index in available_columns {
match self.chain.get_data_column(&root, index) {
Ok(Some(data_column_sidecar)) => {
// Due to skip slots, data columns could be out of the range, we ensure they