ERC-8179: Blob Space Segments (BSS)

ERC-XXXX: Blob Space Segments (BSS)

Category: ERCs | Type: Standards Track | Status: Draft

Authors: Vitalik Buterin (@vbuterin), Skeletor Spaceman
(@skeletor-spaceman)

Abstract

This ERC defines a minimal interface for declaring field element sub-ranges (“segments”) within
EIP-4844 blobs. One function — declareBlobSegment — emits an event binding a [startFE, endFE)
half-open range to a blob’s versioned hash. Zero storage, ~3,500 gas per declaration.

Multiple protocols can share a single blob. This gives them a standard way to say who’s using which
field elements without inventing their own coordination mechanism.

The Problem

EIP-4844 blobs are 128 KiB (4,096 field elements). Most blob submitters don’t fill them. An
empirical study of 26 rollups over six months (arXiv:2410.04111)
found a bimodal distribution (large rollups near full utilization, small rollups below 5%), with
80-99% DA cost savings achievable through sharing.

Worth noting: the cited study reflects pre-PeerDAS blob economics (target 3 blobs/block). PeerDAS
and future scaling upgrades will increase blob throughput and lower per-blob costs. That doesn’t
eliminate the coordination problem — it makes sharing cheaper, not unnecessary. As blob costs drop,
more protocols can justify blob transactions, making sub-blob coordination more relevant, not less.

There’s no standard for protocols to coordinate sub-blob usage. Every project that wants to share
blob space invents its own thing — proprietary events, custom registries, bespoke indexing. Indexers
can’t track segment usage across protocols, tooling can’t compose, and the ecosystem loses the
network effects that come from standardization.

This ERC addresses one specific problem: declaring who is using which field elements. It does not
cover blob construction (how to pack data), fee splitting (who pays), or segment negotiation (how
protocols agree on ranges before submitting). Those are separate coordination layers that can build
on this primitive.

Design Summary

Interface (BSS = Blob Space Segments)

interface IERC_BSS {
    event BlobSegmentDeclared(
        bytes32 indexed versionedHash,
        address indexed declarer,
        uint16 startFE,
        uint16 endFE,
        bytes32 indexed contentTag
    );

    error InvalidSegment(uint16 startFE, uint16 endFE);
    error NoBlobAtIndex(uint256 blobIndex);

    function declareBlobSegment(
        uint256 blobIndex,
        uint16 startFE,
        uint16 endFE,
        bytes32 contentTag
    ) external returns (bytes32 versionedHash);
}

Key Design Decisions

Event-only (zero storage). No SSTORE operations. A declaration costs ~3,500 gas vs ~25,600 for
a stateful alternative (cold SSTORE at 22,100 gas post-EIP-2929) — roughly 7x cheaper. Segment
declarations happen alongside blob transactions that already cost 21,000+ gas, so keeping overhead
minimal matters.

Half-open ranges [startFE, endFE). Standard CS convention. Ranges compose without gaps:
[0, 2000) + [2000, 4096) = [0, 4096). No off-by-one errors when tiling.

BLOBHASH binding. The BLOBHASH opcode only returns non-zero values for blobs in the current
transaction. Segments can only be declared for blobs in the executing transaction (all contracts in
the call chain share access to BLOBHASH). No access control logic needed.

bytes32 contentTag. Protocol identification via keccak256("protocol.version")
collision-free without a governance-managed registry. Indexed in the event for efficient log
filtering by protocol.

Off-chain overlap detection. Overlapping declarations are permitted on-chain. Overlaps are
self-punishing (both protocols’ data gets garbled), and on-chain enforcement would require storage
plus governance for dispute resolution. Indexers detect and flag overlaps trivially.

uint16 for FE indices. 4,096 FEs needs 12 bits. uint16 is the smallest standard Solidity
integer type that fits and enables tighter packing in storage-backed extensions. The FE count per
blob is tied to the KZG polynomial degree — future scaling increases blob count per block, not
individual blob size.

On-chain events, not in-blob headers. An alternative design embeds segment metadata directly in
the blob (e.g., a header in the first few field elements). We considered this and went with on-chain
events because: (1) blobs are opaque to the EVM — you can’t read a blob header from a contract
without KZG proofs (though KZG verification is possible for small segments; see On-Chain
Verification via KZG Proofs
below); (2) on-chain events use existing indexer infrastructure
(eth_getLogs); (3) protocols can adopt this without changing their blob encoding. The tradeoff is
an extra contract call per declaration (~3,500 gas). For protocols that already coordinate blob
construction tightly, an in-blob header might be simpler — but a general-purpose standard should use
the primitive that’s easiest to index and adopt.

Optional Extensions

  • Queryable (IERC_BSS_Queryable): On-chain segment lookup via storage with pagination
    (getSegments(versionedHash, offset, limit)). More expensive; only for contracts that need to
    verify declarations on-chain.
  • Batch (IERC_BSS_Batch): Declare multiple segments in one call. Useful when an L2 and a
    social protocol declare their respective portions atomically.

Use Cases

L2 + Social Protocol

An L2 sequencer uses FE [0, 2000) for rollup batch data. The remaining [2000, 4096) is unused but
paid for. A social protocol fills the leftover space at zero marginal blob cost.

bss.declareBlobSegment(0, 0,    2000, keccak256("optimism.bedrock"))     // L2
bss.declareBlobSegment(0, 2000, 4096, keccak256("social-blobs.v4"))      // Social

Both indexers discover their respective segments by filtering on contentTag. ~50% DA cost saving
if the social protocol reimburses half the blob fee.

Multi-Protocol Tiling

Three protocols share one blob with zero waste:

FE [0,    1500)  ->  Base rollup data       (46,500 bytes)
FE [1500, 3000)  ->  Social-Blobs messages  (46,500 bytes)
FE [3000, 4096)  ->  Celestia namespace     (33,976 bytes)

126,976 usable bytes, 3 protocols, 1 blob. Each indexer filters by its contentTag.

Backward Compatibility

Protocols using full blobs adopt this by adding a single declaration:

bss.declareBlobSegment(0, 0, 4096, keccak256("myprotocol.v1"));

No change to blob usage — just a declaration on top of the existing transaction.

Atomic Tiling via Batch Extension

An aggregator contract uses the batch extension to declare an L2 + social protocol split atomically:

IERC_BSS_Batch.BlobSegmentParams[] memory segments =
    new IERC_BSS_Batch.BlobSegmentParams[](2);
segments[0] = IERC_BSS_Batch.BlobSegmentParams({
    blobIndex: 0, startFE: 0, endFE: 2000,
    contentTag: keccak256("optimism.bedrock")
});
segments[1] = IERC_BSS_Batch.BlobSegmentParams({
    blobIndex: 0, startFE: 2000, endFE: 4096,
    contentTag: keccak256("social-blobs.v4")
});

bytes32[] memory hashes = bssBatch.declareBlobSegments(segments);
// Both succeed or fail atomically — no partial tiling

On-Chain Verification via KZG Proofs

Segment declarations do more than coordinate blob sharing. Because BlobSegmentDeclared emits
(versionedHash, startFE, endFE), and EIP-4844’s point evaluation precompile (0x0A) takes a
versioned hash and field element index as input, any declaration also serves as an anchor for
on-chain data verification.

A verifier contract reads a BlobSegmentDeclared event to obtain the versioned hash and FE range
for the segment it cares about. A prover generates a KZG proof for the relevant field element(s)
within that range. The verifier calls the precompile with
(versionedHash, z, y, commitment, proof). If it succeeds, the bytes at that field element index
are cryptographically proven to match what was committed in the blob.

Consider a social protocol that declared [2000, 4096). A governance contract wants to prove a
26-byte message was in that blob. It reads the BlobSegmentDeclared event for the versioned hash,
takes a KZG proof for the single field element containing the message, and calls the precompile.
Cost: ~50,000 gas. The contract now has a cryptographic guarantee that those bytes were in the blob,
without trusting any oracle or indexer.

Costs scale linearly: 4 FEs run ~200k gas, 10 FEs ~500k gas. A full blob [0, 4096) would cost
~200M gas (exceeds block gas limit), so this only works for small segments. Smart contracts that
need to act on proven blob content (governance, disputes, DeFi triggers) can use it. Bulk reads
should still go through off-chain indexers.

A working implementation exists on Sepolia: KZGVerifier.sol wraps the precompile, and
BLSExposer.sol uses it to verify and extract individual messages from blob segments.

The ERC does not define verification. It provides the anchor. How to verify is up to the consuming
contract.

Relationship to Existing Work

ERC-7588 (Blob Transaction Metadata). Complementary.
ERC-7588 describes what is in a blob (metadata about the blob transaction). This ERC declares who
is using which field elements
. A blob could carry both — they address different coordination
concerns.

Blob Aggregation / Blobsy
(ethresear.ch).
The Shared Blob Registry prototype uses on-chain allocation with storage-backed
state for rollup-specific blob aggregation. This ERC takes a different approach: event-only
declarations, no on-chain state, general-purpose (not rollup-specific), no allocation governance.
The tradeoff is that overlap resolution is delegated to off-chain indexers.

Blob Sharing for Based Rollups
(Nethermind).
A working demo using EIP-7702 fan-out for shared blob submission. This ERC could
serve as the segment declaration layer for approaches like this — it standardizes the “who owns
what” part without prescribing how the blob is constructed or submitted.

BlobFusion / Ephema. Blob space sharing service with bid-based pricing. This ERC is agnostic to
pricing; it provides the declaration primitive that a marketplace could build on.

ERC-3722 (Poster). Philosophically similar — minimal
social media on Ethereum. Poster uses calldata with no blob awareness. This ERC addresses the
blob-specific coordination problem that Poster doesn’t need to solve, but the protocols share the
“minimal footprint, event-driven” design ethos.

arXiv:2410.04111. The empirical analysis that motivates this
work. 26 rollups, six months, 80-99% DA cost savings from blob sharing.

Reference Implementation

A standalone reference implementation is available (~20 lines of Solidity). The full source
(contract, interfaces, tests) is included in the ERC PR under assets/. Key files:

  • BlobSpaceSegments.sol — Reference contract
  • IERC_BSS.sol — Core interface
  • IERC_BSS_Queryable.sol — Optional queryable extension (with pagination)
  • IERC_BSS_Batch.sol — Optional batch extension

The reference implementation is deployed on Sepolia and validated with a full Forge test suite
including fuzz tests and gas benchmarks.

Limitations & Open Questions

To be upfront about what this doesn’t solve:

  1. No on-chain exclusivity. Multiple parties can declare overlapping segments. By design (avoids
    storage and governance), but coordination is an off-chain concern.
  2. No fee-splitting mechanism. Declares segments but says nothing about who pays for the blob.
  3. No blob construction standard. How protocols actually pack data into a shared blob (ordering,
    padding, encoding) is out of scope. This only declares the result.
  4. BLOBHASH dependency. Only works on chains with EIP-4844. Can’t be used on L2s or chains
    without the BLOBHASH opcode.
  5. Reorg sensitivity. Segment declarations have the same finality as the containing blob
    transaction. Indexers need to handle reorgs.
  6. Over-claiming. A protocol can declare a larger range than it actually fills. The EVM can’t
    inspect blob content, so declarations are claims, not proofs. Indexers should treat them
    accordingly.
  7. Blob pruning. Blob data is pruned after ~18 days. Segment declarations persist as on-chain
    events, but the underlying data they reference may be unavailable from consensus-layer nodes.
  8. Declarer authenticity for a contentTag. Anyone can emit declarations for any tag. Consumers
    should maintain canonical declarer allowlists per (chainId, contentTag).

Call for Feedback

Looking for community input on:

  1. Event-only vs storage. We think the 7x gas savings justify event-only, but teams building
    blob space marketplaces or allocation systems that need on-chain queries might disagree.

  2. Content tag convention. Is keccak256("protocol.version") the right approach? A lightweight
    registry could prevent accidental collisions, but adds governance overhead.

  3. Overlap handling. Current design treats overlaps as self-punishing and leaves detection to
    indexers. Would any use case benefit from on-chain overlap prevention?

  4. Extension design. Are the Queryable and Batch extensions the right optional add-ons? Are
    there other extension points the community needs?

  5. Negotiation layer. This ERC declares segments after the fact but doesn’t help protocols agree
    on ranges before submitting. Is a separate negotiation standard needed? Or do you expect
    aggregators to handle pre-submission coordination off-chain?

  6. PeerDAS economics. As PeerDAS increases blob throughput and lowers costs, does sub-blob
    sharing remain valuable? Our assumption is that cheaper blobs attract more protocols, making
    coordination more relevant — but we’d like to hear from teams planning around post-PeerDAS
    economics.

  7. Integration experience. If your protocol submits blobs and has unused space, we’d like to
    hear about your coordination challenges and whether this interface addresses them.

  8. On-chain verification use cases. Do protocols need smart contracts to act on proven blob
    content (e.g., governance, disputes, DeFi triggers), or is off-chain indexing sufficient for most
    use cases? We’d like to understand demand for KZG-based on-chain verification of declared
    segments.

Links