Skip to content

DataColumnSidecarsByRange lacks per-batch slot width cap, causing massive single-batch DB reads #17314

Description

@1033309821

Describe the bug

A remote peer can request data-column sidecars over a very wide slot range via the PeerDAS /eth2/beacon_chain/req/data_column_sidecars_by_range/1/ssz_snappy protocol.

Unlike the handlers for blocks-by-range and blobs-by-range, the validateDataColumnsByRange function in beacon-chain/sync/rpc_data_column_sidecars_by_range.go does not cap the size of the batch loaded from the database.

It currently sets rangeParams.size to the entire requested window (up to the peer’s rate-limit burst, defaulting to 16384 slots):

rangeParameters := &rangeParams{start: startSlot, end: endSlot, size: uint64(size)}
// `size` is essentially `endSlot - startSlot + 1` without batch clamping
return rangeParameters, nil

Because the shared blockRangeBatcher uses rangeParams.size as the per-batch slot width, this results in a single, massive synchronous DB read (db.Blocks(start, end)) over the full width of the window before the stream write quota stops it.

For comparison, in the same repository, validateBlobsByRange correctly clamps this:

limit := min(blobBatchLimit(current), maxRequest)
if rp.size > limit {
    rp.size = limit
}
return rp, nil

Other clients (e.g., Lodestar, Lighthouse) also clamp the requested count or reject requests that are too large. While the rate-limiter prevents infinite bounds (capping at burst ~16384), pulling up to 16384 slots in a single DB batch causes measurable transient CPU and disk I/O spikes on the node.

Has this worked before in a previous version?

N/A. This is related to the upcoming Fulu / PeerDAS data columns implementation.

🔬 Minimal Reproduction

Run a Prysm beacon node on a Fulu devnet (or with Fulu enabled via Kurtosis).

Establish a libp2p connection to the node.

Send a data_column_sidecars_by_range request with a large count parameter that is within the rate-limiter's burst limit but much larger than typical batch sizes.

Example parameters: start_slot = head_slot - 20000 (within DA window), count = 4096 or 16384, columns = 0..127.

Observe the node's disk read and CPU usage during the request, as well as the Prometheus metric rpc_data_columns_by_range_response_latency.

The wall-clock time for a single inbound request with count=4096 is significantly higher than a baseline count=128 because the node is fetching all 4096 slots in a single DB batch rather than chunking them into batches of 64/128.

Error

No application crash or explicit error is printed, but this creates a performance bottleneck. The node will experience severe I/O blocking during the massive DB fetch.

Platform(s)

No response

What version of Prysm are you running? (Which release)

No response

Anything else relevant (validator index / public key)?

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions