Skip to content

feat(prover): batch_splitter — split sealed batches into two Airbender pieces - #4861

Open
deniallugo-claude wants to merge 1 commit into
matter-labs:mainfrom
deniallugo-claude:feat/batch-splitter
Open

feat(prover): batch_splitter — split sealed batches into two Airbender pieces#4861
deniallugo-claude wants to merge 1 commit into
matter-labs:mainfrom
deniallugo-claude:feat/batch-splitter

Conversation

@deniallugo-claude

Copy link
Copy Markdown
Contributor

Why

Boojum can prove heavier batches than Airbender's geometry allows. To migrate such batches to Airbender we want to: prove the whole batch, and on failure split it into two pieces and prove each — recursively, until each piece fits Airbender's geometry.

This PR adds a batch_splitter binary (core/bin/batch_splitter) that splits a sealed L1 batch N into two independently-provable AirbenderVerifierInput pieces.

What it does

For batch N spanning L2 blocks [first, last], it cuts at the midpoint (even by block count, whole blocks only) into piece A [first, mid) and piece B [mid, last], such that old_root_N →(A) root_A →(B) new_root_N.

  • Witness-input level, not a slice. A witness input is one bootloader program; the per-op arrays can't be cut at a block boundary. So each half is re-executed over its block range (mirroring BasicWitnessInputProducer / AirbenderVerifierInput::verify), seeded from the in-witness storage snapshot (piece B overlaid with A's writes).
  • Non-invasive. Reads only Postgres (MVCC) and immutable object-store blobs; never writes the canonical chain, re-commits to L1, re-numbers batches, or touches the Merkle-tree RocksDB.
  • Merkle paths from N's own multiproof. Sibling hashes come from batch N's immutable WitnessInputMerklePaths blob — the only non-invasive source. A sparse binary Merkle tree is reconstructed from it (N-1 leaf values from each key's first occurrence; off-trie siblings are invariant during N), then A's and B's writes are re-applied to regenerate each piece's paths + root_A. Hashing reuses Blake2Hasher's hash_leaf/hash_branch/empty_subtree_hash, so roots/paths match exactly.
  • Output. Two self-contained AirbenderVerifierInput CBOR blobs (airbender_split_input_{N}_a.cbor / _b.cbor).

Correctness self-checks

Two root checks bracket the reconstruction and fail loudly rather than emitting a bad witness:

  1. reconstructed N-1 root == N's previous_batch_hash;
  2. post-B root == N's committed root hash.

Scope / follow-ups

  • Commitment chaining for piece B (computing piece A's synthetic Airbender commitment) is gated behind --commitment-chaining. Off by default, B is emitted with commitment_input = None, which is enough to verify each half fits Airbender's geometry — the immediate goal. The full L1BatchCommitment assembly for the intermediate batch is the one piece left for a follow-up (clearly isolated in commitment.rs).
  • Validation: the binary builds and is type-checked; the next step is a run on a real heavy batch to exercise the root self-checks (empirical proof the reconstruction is exact). Not yet run against live data.

See core/bin/batch_splitter/README.md for the full design.

Usage

batch_splitter --l1-batch <N> --database-url <pg> --artifacts-path <object-store> --l2-chain-id <id> [--commitment-chaining]

🤖 Generated with Claude Code

Boojum can prove heavier batches than Airbender's geometry allows. This
adds a `batch_splitter` binary that splits a sealed L1 batch N into two
independently-provable Airbender pieces (and, via the caller's retry loop,
into quarters/eighths/...), until each piece fits Airbender's geometry.

The split is witness-input level and non-invasive: it reads node Postgres
(MVCC) and the immutable object-store witness blobs only, never touches the
canonical chain or the Merkle-tree RocksDB. It re-executes each half of the
batch's L2 blocks, reconstructs a sparse binary Merkle tree from batch N's
own `WitnessInputMerklePaths` to regenerate each piece's paths and the
intermediate root, and emits two self-contained `AirbenderVerifierInput`
blobs. Two root self-checks (reconstructed N-1 root == previous_batch_hash,
post-B root == committed root) validate the reconstruction.

Commitment chaining for piece B is gated behind --commitment-chaining;
without it, pieces are emitted with commitment_input=None for geometry-
feasibility checks.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant