Lesson 2 — Batch posting and data availability
Question
A sequencer's state root on L1 is a commitment. Without the underlying tx data, no one else can re-execute and verify — which is what makes data availability (DA) the load-bearing layer. Where does the data go (L1 calldata / blobs / off-chain DA), and what does each choice cost?
Principle (minimum model)
- Three DA strategies. (1) Post tx data to L1 calldata (most expensive, most secure). (2) Post to L1 blobs (EIP-4844 — 90 %+ cheaper). (3) Post to an alt-DA (Celestia / EigenDA / Avail — cheapest, weaker security).
- EIP-4844 blobs. 128 KB blobs separate from calldata, pruned after ~2 weeks. Sufficient because rollup state-root proofs only need the data for the challenge window. ~90 % cheaper than calldata.
- Alt-DA chains (Celestia / EigenDA / Avail). Specialised DA chains with their own consensus. Cheapest option but a separate trust assumption (the DA chain). Suitable for low-value rollups.
- Batching cuts L1 costs. Compress 100s of L2 txs into one L1 post; amortise the gas across them. Modern OP batcher =
OptimismPortal+ compressed channel format. - Compression. zstd for op-stack, brotli for some others. ~5–10× compression on typical L2 traffic.
- Force-include rescues users from sequencer censorship. If the sequencer doesn't post a user's tx, the user can post it directly to L1, and the next batch must include it.
- Data-Availability Sampling (DAS). Future ZK rollups will use DAS — sample random pieces of the data and verify Merkle proofs. Doesn't download full data; verifies the data is available. Enables much larger rollup throughput.
Worked example + steps
Batch posting and data availability
Before March 2024, posting 1MB of rollup data to Ethereum cost roughly $300 per batch. After EIP-4844, that same megabyte costs roughly $3-$30. The 10× drop is the single biggest cost improvement in rollup history — and it's why Base txs cost cents instead of dollars.
That improvement rests on a deeper question: why does a rollup have to post any data to L1 at all? The answer is data availability (DA — the property that anyone, not just the sequencer, can get hold of the transaction data). Without it, the sequencer's state root is unverifiable and you're back to trusting one company. This lesson covers what DA is, the four DA models, the EIP-4844 blob trick that made it cheap, and how op-batcher actually posts it.
1. Why data availability matters
A rollup commits to its L2 state via a state root on L1. But the state root is just 32 bytes — it doesn't tell you what the L2 state is. To reconstruct the L2 state, you need:
- The state root (cheap — 32 bytes per batch)
- The transaction data that produced it (expensive — every byte of every tx)
If only (1) is on L1, the sequencer can lie about (2) and there's no way to detect it. If both are on L1, anyone can re-execute the txs and verify they produce the state root.
Data availability = "the transaction data is published somewhere everyone can read it."
2. The four DA models
| Model | Where data lives | Trust | Examples |
|---|---|---|---|
| Rollup | Posted to L1 calldata or blobs | L1 consensus | Optimism, Arbitrum, all "true" rollups |
| Validium | Posted to a separate DA committee | Multisig / PoS | StarkEx, dYdX v3 |
| Volition | User picks per tx (rollup or validium) | Mixed | dYdX v4-style hybrid |
| Optimium | DA committee with fraud proofs | DA committee + fraud proof | Newer designs |
For Tempo, Hyperliquid, and most chains we care about: rollup model. Data goes to L1 in some form.
3. EIP-4844 — the blob revolution
Before March 2024, rollups posted data as calldata (the input bytes of a regular Ethereum transaction) on L1. Calldata costs 16 gas per byte ($0.02/byte at 50 gwei). For 1MB per batch: ~$300.
EIP-4844 added a brand new transaction type — blob transactions — with its own fee market, priced for one use case: rollup DA.
| Property | Calldata | Blob (4844) |
|---|---|---|
| Cost per byte | ~16 gas | Variable, typically ~0.1-1 gas |
| Lifetime on L1 | Forever | ~18 days (then pruned) |
| Verification | Anyone can read | Anyone can read during 18 days |
| Max per block | ~125KB practical | 128KB × 6 = 768KB |
The trade-off: blobs are cheap but pruneable. After 18 days, the blob data is dropped from L1 nodes. Anyone needing it long-term must archive it separately (e.g., on IPFS, on dedicated archive nodes).
For 18-day proof window: enough time for fraud proofs to be submitted. After that: the rollup state is final, the data doesn't need to be on L1 anymore.
The catch: blobs are available but competing for blockspace. As more rollups post blobs, blob gas price rises. The current equilibrium gives 10x reduction; if every rollup moves to blobs, it could compress to 3-5x. Plus: not all chains use Ethereum as DA. Celestia, EigenDA, Avail are alternatives.
4. The batch posting flow
For an OP Stack rollup posting to Ethereum:
sequenceDiagram
participant Seq as Sequencer
participant Batcher
participant L1 as Ethereum
participant Proposer
Note over Seq: Build many L2 blocks
Seq->>Batcher: L2 blocks produced
Note over Batcher: Compress + batch
Batcher->>L1: Submit blob tx with batch data
Note over L1: Blob included in L1 block
Note over Seq: Compute new state root for batch
Seq->>Proposer: Latest state root
Proposer->>L1: Submit state root to OutputOracle
Note over L1: Challenge period begins (7 days)
Three different services, three different cadences:
| Service | Frequency | Purpose |
|---|---|---|
| Sequencer | Every L2 block (~2s) | Build blocks |
| Batcher | Every ~60s | Submit compressed batches to L1 |
| Proposer | Every ~1 hour | Submit state root commitments |
The L1 cost driver is the batcher (lots of data) and the proposer (less data, but every commitment costs gas).
5. Reading op-batcher
OP Stack's batcher is in ethereum-optimism/optimism/op-batcher (Go). The Rust equivalent for Reth-based chains is in development.
The core loop:
// Pseudo-Go for clarity
for {
// 1. Fetch new L2 blocks since last batch
blocks := fetchL2BlocksSince(lastBatchEnd)
// 2. Compress with zlib
compressed := zlib.Compress(blocks)
// 3. Split into blob-sized chunks (~128KB each)
chunks := chunk(compressed, BLOB_SIZE)
// 4. Submit blob tx to L1
for _, chunk := range chunks {
submitBlobTx(chunk)
}
// 5. Update local state
lastBatchEnd = blocks.LastBlock
}
That's the gist. The complexity is in:
- Reorg handling (L2 reorg = batches must be re-sent)
- Gas pricing (when to retry with higher fee)
- Throughput tuning (how aggressively to fill blobs)
🔍 Find in repo. Open op-batcher's main.go and trace the main loop. Where does it decide to submit? What's the trigger?
6. Compression — the silent winner
Rollup batches are highly compressible. Typical compression ratios:
| Data | Compression |
|---|---|
| Raw transactions | 1.0x |
| RLP-encoded | 1.0x |
| zlib over batch | 3-5x |
| Custom (zlib + addresses/etc compressed) | 5-10x |
Each compression ratio doubles the throughput at the same blob cost. Production rollups use custom compression that beats vanilla zlib by 2-3x.
For Tempo (payment-focused): payment txs are very repetitive (same merchants, same patterns). Compression ratios likely better than generic rollups. This is a hidden cost advantage for Tempo's specific use case.
7. The DA alternatives
Rollups don't have to post to Ethereum:
7.1 Celestia
celestia is a dedicated DA layer. Rollups post data to Celestia, get a DA attestation, then post the attestation to L1.
Cost: cheaper than Ethereum blobs (~$0.0001 per byte vs ~$0.001 for blobs).
Trade-off: depend on Celestia's security (not Ethereum's). Smaller validator set. Younger ecosystem.
7.2 EigenDA
eigenda is EigenLayer-based DA. Restakers of ETH on EigenLayer provide DA services. Inherits Ethereum's economic security partially.
7.3 Avail
avail is Polygon's DA layer. Similar to Celestia structurally.
For Tempo: as a Paradigm-built L1, Tempo likely uses Ethereum DA initially. Switching to Celestia/EigenDA would lower cost but reduce decentralization (smaller DA validator set).
8. Practice
- Calculate: at 1MB batch per minute, ~$0.1/MB blob cost, what's daily DA cost for a rollup?
- If the rollup processes 100 tx/s and each tx is 200 bytes: how much does each user tx cost in DA?
- Open op-batcher source — find the compression call
- Identify: when would a chain pick Celestia over Ethereum blobs?
9. Reading list
- EIP-4844 spec — the blob standard
- op-batcher — production batcher
- Celestia docs — DA layer alternative
Final check: in one sentence, why is data availability the load-bearing security assumption of a rollup, and what happens to user funds if DA fails? If your answer doesn't reference "anyone can reconstruct L2 state from L1 data," re-read §1.
Summary (3 lines)
- DA strategies: L1 calldata (most secure, expensive) / L1 blobs (EIP-4844, 90 % cheaper, sufficient for challenge windows) / alt-DA (Celestia / EigenDA / Avail, cheapest, weaker trust).
- Batching + compression cuts L1 cost ~100×. Force-include via L1 escape-hatch keeps users safe from sequencer censorship.
- DAS (Data-Availability Sampling) enables much larger rollup throughput by sampling availability. Next: read op-rbuilder, the canonical Rust sequencer.