Alert Source Discuss
⚠️ Draft Standards Track: Networking

EIP-8371: RowDAS - Distributed Blob Reconstruction

Distribute reconstruction load in the network through row-level cell messaging.

Authors Csaba Kiraly (@cskiraly), Marco Munizaga (@MarcoPolo)
Created 2026-08-05
Discussion Link https://ethereum-magicians.org/t/eip-8371-rowdas-distributed-blobspace-reconstruction/29320
Requires EIP-7594, EIP-8136

Abstract

PeerDAS (Peer Data Availability Sampling, EIP-7594) requires supernodes to provide reconstruction, and this puts a high burden on supernodes that scales linearly with blob count. RowDAS enables distributed blobspace reconstruction using partial-message-based row topics, allowing all nodes to contribute to reconstruction, while significantly reducing the load on supernodes, leading to a more efficient and more resilient DAS construct.

Motivation

EIP-7594 PeerDAS was designed with a simple but powerful-enough erasure coding based reconstruction model where any node receiving at least half of the 128 columns should reconstruct the whole extended blob content belonging to a block. As the number of blobs grows, however, the reconstruction burden on every supernode also grows linearly with blob count.

Moreover, supernodes execute largely redundant work: each one of them reconstructing all missing blobs, without the means to distribute this work efficiently in the network.

This EIP introduces distributed blobspace reconstruction, where different nodes prioritize the reconstruction of different parts of the blobspace, leading to a faster, less CPU-intensive, and more resilient construct.

Specification

The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “NOT RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in RFC 2119 and RFC 8174.

The EIP introduces new Gossipsub topics, changes to the rules of reconstruction, and a few minor changes to how current column topics operate.

In this document, a supernode is a node subscribed to all 128 column subnets, following the customary use of the term. A row reconstructor is any node subscribed to 64 or more of the 128 column subnets, and thus holding enough cells to reconstruct any row on its own; every supernode is also a row reconstructor. On mainnet, the row reconstructor class notably includes staking nodes whose validator custody requirement reaches 64 or more custody groups.

Parameters

Constant Value
ROW_SUBNET_COUNT 128

Column topics

Regarding column topics EIP-7594 already mandates the following:

Once the node obtains a column through reconstruction, the node MUST expose the new column as if it had received it over the network. If the node is subscribed to the subnet corresponding to the column, it MUST send the reconstructed DataColumnSidecar to its topic mesh neighbors. If instead the node is not subscribed to the corresponding subnet, it SHOULD still expose the availability of the DataColumnSidecar as part of the gossip emission process.

This is extended to allow cell-level operation towards peers that support it using the following rules:

  • Prior to reconstructing, a node MAY also use advertisements received as part of the Gossipsub “fanout” mechanism to collect relevant cells from other peers across column subnets it is not subscribed to.

  • After reconstruction, a node SHOULD use the Gossipsub “fanout” mechanism to provide cells from the reconstructed blob to peers across column subnets it is not subscribed to. A node MAY choose to only advertise to a random subset of these columns rather than all columns. This allows the node to provide another path for cell dissemination to the network. A node MAY choose to delay these fanout messages in order to conserve bandwidth by not competing with other nodes who are subscribed to the column topic, and can provide the cell instead.

Row topics

Similar to column subnets, we introduce new row subnets: data_row_{subnet_id}. These resemble, but are not to be confused with, the deprecated blob_sidecar_{subnet_id} topics. Their properties:

  • A row subnet MUST use Cell-Level Deltas (EIP-8136) without eager push. Like for Cell-Level Deltas in column subnets, the GroupID for a message in the row subnet is the block root. Since cells might arrive from three different sources (getBlobs, columns, rows) a node MAY choose to delay the request of cells from rows.
  • The number of row subnets is ROW_SUBNET_COUNT, a fixed constant independent of the blob count. Blob rows are mapped to subnets with a per-slot pseudo-random permutation, reusing the consensus-layer swap-or-not shuffle:

    def get_blob_row_subnet(blob_index: BlobIndex, slot: Slot) -> RowSubnetIndex:
        seed = hash(b"ROW_SUBNET" + uint_to_bytes(uint64(slot)))
        return RowSubnetIndex(
            compute_shuffled_index(
                uint64(blob_index) % ROW_SUBNET_COUNT, uint64(ROW_SUBNET_COUNT), seed
            )
        )
    

    Being a permutation, the mapping assigns distinct subnets to the blobs of a slot as long as the blob count does not exceed ROW_SUBNET_COUNT. Changing every slot, it distributes load evenly across the network, including which subnets are idle when the blob count is below ROW_SUBNET_COUNT. The seed depends only on the slot, so the mapping is computable without access to chain state. If the blob count exceeds ROW_SUBNET_COUNT, blob indices that are equal modulo ROW_SUBNET_COUNT share a subnet, so a subnet carries up to ceil(blob_count / ROW_SUBNET_COUNT) rows in a slot; the bitmap of a row subnet covers the cells of all rows mapped to it, ordered by blob_index.

  • Each node derives a single designated row subnet from its node ID, reusing the hash-based derivation of custody column selection in EIP-7594, but with a different byte window for domain separation:

    def get_row_subnet(node_id: NodeID) -> RowSubnetIndex:
        return RowSubnetIndex(
            bytes_to_uint64(hash(uint_to_bytes(uint256(node_id)))[8:16])
            % ROW_SUBNET_COUNT
        )
    

    Since custody group derivation uses bytes [0:8] of the same hash, taking bytes [8:16] keeps the row assignment decorrelated from custody assignment at no extra hashing cost. A row reconstructor MUST subscribe to its designated row subnet. Other nodes SHOULD subscribe to theirs if they support Cell-Level Deltas. Subscription carries no custody obligation.

Row subnets carry partial messages only; no full-message equivalent is defined for them. A node MUST NOT subscribe to a row subnet unless it supports the Partial Messages Extension, and the subscription requirements above apply only to nodes with such support. A node MAY prune row subnet mesh peers that do not support the extension. Note that the non-discrimination guidance of EIP-8136 applies to column topics, where full-message fallback exists; on row subnets there is nothing to fall back to, while column topics and getBlobs remain fully available to nodes without the extension.

Row subnet membership is computable from a peer’s node ID alone, so no ENR extension is needed for discovery. A node SHOULD locate peers of its designated row subnet by applying get_row_subnet to the node IDs it discovers (e.g., through discv5 lookups), and SHOULD maintain enough connections to same-subnet peers to sustain a healthy Gossipsub mesh, keeping in mind that subnet members are a small fraction (approx. 1 / ROW_SUBNET_COUNT) of the overall node population and are unlikely to appear in sufficient numbers among randomly selected peers.

The exact wire format — SSZ containers, bitmap encoding, and GroupID derivation — is to be defined in the ethereum/consensus-specs repository, following the approach of EIP-8136. The semantics this EIP requires of it are: the bitmap of a row subnet covers the rows mapped to the subnet in blob_index order, and within a row follows cell_index order; the GroupID is derived from the block root, analogously to column topics. A cell received on a row subnet MUST be verified against the corresponding blob KZG commitment before it is forwarded or used, and peers providing invalid cells MUST be penalized under the same rules as on column subnets.

A peer MAY limit the number of cells it serves a peer on the row subnet to just half of the cells of each mapped row, as the rest of that row can be reconstructed. The limit applies per row: serving fewer than 64 cells of a row does not allow its reconstruction, regardless of cells served from other rows.

As a node receives cells from any source (either from row subnets, column subnets, or getBlobs), it SHOULD send updated bitmap states to its peers. A node MAY choose to debounce these updates.

Reconstruction

A node, even if not a row reconstructor, SHOULD collect at least 64 cells on each row mapped to its designated row subnet and expose these in updated bitmap states to its peers. Note that these cells need not come from the node’s own custody: the row subnet pools the custody cells of all its members, so sufficient cells can be collected through the row subnet itself.

Similar to PeerDAS, reconstruction duties attach to nodes holding enough columns, but reconstruction becomes a phased process. Reconstruction of a row is REQUIRED only once a node holds at least 64 distinct verified cells of that row; subscription alone does not imply possession, so all reconstruction obligations below are conditional on this.

  • 1st phase: a row reconstructor MUST reconstruct each row mapped to its designated row subnet for which it holds sufficient cells, and it MUST send updated bitmap states to its peers. Note that a row reconstructor can satisfy this phase from its own column subscriptions, without foreign row information. A small random delay (recommended range TBD) before reconstruction is allowed to desynchronise nodes in the network and reduce overall load.
  • 2nd phase: after a slightly longer random delay (recommended range TBD), during which cells are collected from getBlobs, columns, and rows, a supernode SHOULD — and any other row reconstructor MAY — do a second reconstruction phase, reconstructing all missing rows for which it holds sufficient cells, and sharing the results as defined above. This matches the reconstruction behavior PeerDAS already recommends for nodes holding half the columns, with an added delay. The stronger expectation is placed on supernodes because only a node subscribed to all column subnets can observe rows completing elsewhere and cancel the redundant work; row reconstructors with fewer subscriptions lack this signal.
  • 3rd phase: after a delay longer than the 2nd-phase delay (recommended range TBD), any node subscribed to a row subnet SHOULD reconstruct the rows mapped to that subnet that are still incomplete and for which it holds sufficient cells, sharing the results as defined above. This provides a reconstruction path that does not depend on row reconstructors or supernodes at all. Its expected CPU cost is near zero, since this phase activates only when the earlier phases have failed to complete a row.

All delays are measured from the moment the node first obtains the block root of a valid block for the slot. Reconstruction obligations attach to at most one block root per slot: the block root on the node’s current head branch, or the first valid block root seen. For any additional (equivocating or competing) block roots of the same slot, reconstruction is OPTIONAL, so that equivocation cannot amplify reconstruction work. A node MUST cancel a pending reconstruction of a row that completes through other means before the timer fires. The delays MUST be bounded by a maximum (value TBD), so that the recovery path is not postponed indefinitely under network degradation.

Rationale

Row topics were part of the DAS discussion from the early days, well before PeerDAS was designed. FullDAS (described in the ethresear.ch post “FullDAS: towards massive scalability with 32MB blocks and beyond”) introduced cell-level messaging over both column and row topics, with cross-seeding and in-network reconstruction. It also introduced bitmap representations of partial IHAVE messages, but without the exact protocol details.

The Gossipsub Partial Message Extension introduced the mapping of bitmap-based partial message representations into Gossipsub, opening the way to use them on columns in EIP-8136, which builds on that extension and cites its specification.

Until now, while we have developed the tools to implement better schemes, we remained with the original simplified PeerDAS construct. At the same time, blob count scaling made the CPU and bandwidth requirement of supernodes more of a point of contention. Reliance on supernodes, while abundant on current mainnet, is also a point of concentration leading to a protocol with less resilience than desirable.

This EIP corrects some of these shortcomings, making sure supernodes are not doing (as much) useless work, and reconstruction is possible (although not yet mandated) even without supernodes.

What it is not

This EIP is not FullDAS. It does not introduce sub-linear (cell-level) sampling. The bandwidth requirement of sampling nodes is still proportional to the number of blobs.

It also does not introduce column-wise encoding, so protection and reconstruction is still only along the row axis.

Finally, it does not directly help L2 nodes retrieve individual blobs (although there are possible extensions in that direction). However, it helps them run supernodes with fewer resources, leading to a net gain.

Possible extension to retrieve individual blobs

With the introduction of PeerDAS, L2 nodes have the problem that retrieving a specific blob from a CL client requires them to either be a supernode, or to download it on request through columns. By introducing row topics with allocation rooted in the nodeID, it is easier for nodes to identify which node they can download the relevant blob from. We reserve this for further consideration.

Design decisions

Why are nodes without reconstruction duties part of the row topics?

This is to enable the possibility of reconstructing without supernodes. Even custody-minimum nodes contribute: with roughly 94 members each custodying at least 4 randomly assigned columns, a row subnet collectively covers well over 64 distinct columns with high probability, forming a virtual reconstructor even when no individual member could reconstruct alone. The additional traffic of one row, most probably already suppressed by getBlobs, is worth it in our opinion.

Why are ordinary nodes not required to reconstruct?

While mandated (MUST) reconstruction would be desirable from the perspective of not relying on supernodes at all, it would introduce unconditional CPU load on ordinary nodes. Instead, the 3rd reconstruction phase is a SHOULD, with a delay long enough that it activates only in the rare case when the earlier phases have not completed a row: the expected load is near zero, while the network retains a reconstruction path that works without row reconstructors.

Why a fixed number of row subnets, instead of one per blob?

Tying the subnet count to the maximum blob count would change every node’s subnet assignment at each Blob Parameter Only fork, tearing down and re-forming all row meshes simultaneously, exactly when network stability matters most. A fixed count keeps node-to-subnet assignments stable across forks, and the blob count only affects the stateless per-slot blob-to-subnet mapping. The cost is somewhat thinner per-subnet coverage (nodes are spread over ROW_SUBNET_COUNT subnets even when fewer rows exist) and having to define the multi-row-per-subnet general case.

Why ROW_SUBNET_COUNT = 128?

The constant is chosen to keep the expected number of nodes per subnet in a healthy band across plausible participation scenarios. Since each node subscribes to a single row subnet, the expected team size behind a subnet is the number of participating nodes divided by ROW_SUBNET_COUNT. This team size has a floor: it must stay several times the Gossipsub mesh degree (accounting for the binomial spread of hash-based assignment and for churn), and it should give a high probability of at least one row reconstructor — a node with a mandatory 1st-phase duty — per subnet. Pushing the constant higher than needed thins subnets towards this floor, while a lower constant increases traffic duplication, as each active subnet’s row flows to its entire team.

With approx. 12K nodes and 3K supernodes on mainnet, ROW_SUBNET_COUNT = 128 yields ~94 nodes and ~23 supernodes per subnet at full participation, and remains workable even at partial early adoption of Cell-Level Deltas. The value is also above currently planned maximum blob counts, so in practice each subnet carries at most one row per slot, while the construct remains well defined for higher blob counts: per-node row load is bounded by ceil(blob_count / ROW_SUBNET_COUNT) rows per slot. If the network size changes by an order of magnitude, raising or lowering the constant remains possible, at the cost of a one-time reshuffle of subnet assignments.

Why a pseudo-random per-slot permutation, and not a simple rotation?

With fewer rows than subnets, some subnets are idle in a given slot, so the mapping has to change over time for every node to contribute equally. A simple rotation ((blob_index + slot) % ROW_SUBNET_COUNT) achieves this only over a full cycle: each subnet would be active for blob_count consecutive slots and then idle for the rest of the cycle, making per-node load bursty. The pseudo-random permutation redraws the active subnet set every slot, evening out load also on short time horizons. A permutation (rather than an independent hash per blob) is needed to avoid mapping two blobs of a slot to the same subnet as long as the blob count does not exceed ROW_SUBNET_COUNT; compute_shuffled_index provides one that clients already implement. Note that the mapping remains publicly predictable; unpredictability would add little, since the block builder controls blob indices and could steer a blob to any of the subnets active in that slot under any public mapping. Guarantees against targeted suppression continue to come from the column topics.

Why only a single row, and why is it not dependent on custody?

As of August 2026, mainnet has approx. 12K nodes of which 3K are supernodes. The latter is much more than what we expected initially. With current and planned blob counts, even a single row creates abundant overlap.

Backwards Compatibility

Row topics are limited to peers that have libp2p Gossipsub implementations supporting Cell-Level Deltas. The portion of peers that supports the extension is already reaching considerable numbers on mainnet, even before Glamsterdam. We expect the majority of peers to support it after the Glamsterdam fork and EIP-8136. For peers that do not support the extension, getBlobs and column topics are still fully available.

Security Considerations

The EIP changes DAS networking, but it does not change the custody allocation and the probabilistic guarantees of PeerDAS.

New Gossipsub topics might introduce new attack vectors. Since row distribution is a new additional recovery path, and the old paths are mainly intact, it is not expected that this adversely affects the system, except for a bounded traffic overhead: bitmap-based signaling, plus, when blob data is partially withheld, up to half a row of futile cell pulls per row subnet member per mapped row. Reconstruction CPU cannot be triggered by unavailable data, as all reconstruction duties are gated on holding at least 64 distinct verified cells of a row. An exception to this is the phased reconstruction process. Here the 2nd phase, the full reconstruction, is explicitly delayed. This delay is, however, something implementations already practice, and it is a one-time (instead of hop-by-hop) delay.

A withholding block producer can trigger recovery work on a doomed block: releasing 64 columns’ worth of cells for all rows except one — kept below the reconstruction threshold by withholding as little as a single cell — causes the network to reconstruct and cross-seed all recoverable rows while the block still ends up unavailable. This attack is inherited from PeerDAS rather than introduced by this EIP: under PeerDAS, every supernode performs this recovery work redundantly, while here the 1st phase distributes it at roughly one row per row reconstructor and the 2nd phase skips rows observed complete, so the total work strictly decreases. Since the 2nd phase is a SHOULD, supernodes can mitigate it further: observing the bitmaps of all column subnets, they can detect the unrecoverable row and legitimately skip collecting and reconstructing for the doomed block.

Row dissemination is an optimization and MUST NOT weaken availability guarantees: nodes MUST NOT alter sampling or availability decision rules based on row subnet state, nor delay these decisions waiting for row dissemination; column topics and request-response remain the authoritative paths.

Bitmap-based signaling introduces load of its own. Sending an update on every received cell can lead to quadratic message complexity, so nodes SHOULD debounce and rate-limit bitmap updates, and SHOULD bound the number of GroupIDs tracked per peer, in line with the guidance of EIP-8136. A peer that repeatedly advertises cells it then fails to provide SHOULD be treated in local peer scoring like a peer providing untimely messages.

Since row subnet assignment is a static, public function of the node ID, an attacker can grind node IDs to concentrate on, or eclipse, a chosen row subnet. The impact is bounded: a suppressed row subnet degrades to the status quo, as the 2nd reconstruction phase and the column topics cover the affected rows.

Since the row subnet count is a fixed constant and node-to-subnet assignments do not depend on the blob count, Blob Parameter Only forks (EIP-7892) do not affect row subnet subscriptions; only the blob-to-subnet mapping changes with the blob count, and that mapping is stateless per slot.

Copyright and related rights waived via CC0.

Citation

Please cite this document as:

Csaba Kiraly (@cskiraly), Marco Munizaga (@MarcoPolo), "EIP-8371: RowDAS - Distributed Blob Reconstruction [DRAFT]," Ethereum Improvement Proposals, no. 8371, August 2026. Available: https://eips.ethereum.org/EIPS/eip-8371.