Skip to content

Remove sequencer batch write paths and unused NewL2Block batch hash#319

Merged
FletcherMan merged 3 commits intomainfrom
remove-sequencer-batch-generation
May 6, 2026
Merged

Remove sequencer batch write paths and unused NewL2Block batch hash#319
FletcherMan merged 3 commits intomainfrom
remove-sequencer-batch-generation

Conversation

@FletcherMan
Copy link
Copy Markdown
Collaborator

@FletcherMan FletcherMan commented Apr 23, 2026

Summary

  • remove the sequencer batch write path from go-ethereum by deleting the engine batch write handlers, backend batch handler wiring, rawdb write helpers, and authclient write methods
  • keep the historical rollup batch read surface for batch payloads/signatures, but remove the obsolete L1-fee read surface because geth no longer writes RollupBatchL1DataFeeKey
  • drop the unused NewL2Block batchHash argument from the live executable block path; newly live-sequenced blocks intentionally keep Header.BatchHash zero because batch boundaries are no longer produced by the sequencer
  • preserve Header.BatchHash itself for RLP/wire compatibility and keep the safe-block compatibility path (NewSafeL2Block / SafeL2Data.BatchHash) unchanged

Test plan

  • go build ./...
  • go test ./eth/catalyst ./ethclient/authclient -short -count=1
  • go test ./eth ./ethclient ./core/rawdb -run '^$' -count=1
  • Full go test ./... -short -count=1 (the repo currently has unrelated baseline failures outside this diff)

Summary by CodeRabbit

  • Refactor

    • Removed CollectedL1Fee field from rollup batch RPC responses
    • Simplified L2 block creation API by removing batchHash parameter
    • Removed batch-based rollup processing subsystem integration
  • Chores

    • Removed GetRollupBatchL1FeeByIndex RPC method
    • Removed BatchHandler() public method
  • Tests

    • Updated test coverage to reflect L2 block creation API changes

fletcher.fan added 2 commits April 23, 2026 16:18
Drop geth's sequencer batch write handlers and storage helpers so batch creation is fully removed from the execution client while historical read surfaces stay intact.

Made-with: Cursor
Drop the unused batchHash parameter from engine_newL2Block so the sequencer execution path only carries executable block data while BatchHash remains confined to the safe block compatibility flow.

Made-with: Cursor
@FletcherMan FletcherMan requested a review from a team as a code owner April 23, 2026 11:04
@FletcherMan FletcherMan requested review from SecurityLife and removed request for a team April 23, 2026 11:04
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 23, 2026

📝 Walkthrough

Walkthrough

This PR removes batch processing subsystem integration from the Ethereum protocol backend by eliminating the batchHandler infrastructure, simplifying RPC types, removing batchHash parameters from L2 block creation, and deleting unused batch utility functions across multiple components.

Changes

Batch Processing Removal

Layer / File(s) Summary
Backend Infrastructure
eth/backend.go
Batch handler field, initialization, and lifecycle management (Start/Stop calls) removed from Ethereum struct. New imports added for unrelated functionality (enode, params, rlp). Public BatchHandler() method deleted.
RPC API Updates
eth/api.go, ethclient/ethclient.go
RPCRollupBatch simplified by removing CollectedL1Fee field and reordering Sidecar before Signatures. Sidecar now populated from stored rollupBatch in GetRollupBatchByIndex. GetRollupBatchL1FeeByIndex RPC method removed from client.
L2 Block Creation
eth/catalyst/l2_api.go, ethclient/authclient/engine.go
NewL2Block and executableDataToBlock signatures updated to remove batchHash parameter. Block header construction eliminates BatchHash field. NextL1MessageIndex mapped to NextL1MsgIndex in header.
Batch Utilities Cleanup
rollup/batch/block_context.go
BlockContext type and utility functions (DecodeBlockContext, BlockContextsFromBytes) deleted entirely.
Import Updates
core/rawdb/accessors_rollup_batch.go
Added bytes and encoding/binary imports to support existing code using bytes.NewReader and binary.BigEndian.
Tests
eth/catalyst/l2_api_test.go
Test calls to NewL2Block updated to single-parameter form (batchHash argument removed).

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~30 minutes

Suggested reviewers

  • SecurityLife
  • secmgt

Poem

🐰 The batches fade like morning dew,
No more handlers in the queue,
L2 blocks now skip the hash,
Cleaner code, a tidier stash—
Rollup dreams give way anew! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately summarizes the two main changes: removal of sequencer batch write paths and removal of the unused batchHash parameter from NewL2Block.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch remove-sequencer-batch-generation

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 golangci-lint (2.12.1)

Error: can't load config: unsupported version of the configuration: "" See https://golangci-lint.run/docs/product/migration-guide for migration instructions
The command is terminated due to an error: can't load config: unsupported version of the configuration: "" See https://golangci-lint.run/docs/product/migration-guide for migration instructions

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

chengwenxi
chengwenxi previously approved these changes Apr 28, 2026
Kukoomomo
Kukoomomo previously approved these changes Apr 28, 2026
@panos-xyz
Copy link
Copy Markdown
Contributor

Code review

Found 1 issue:

  1. Header.BatchHash is now silently always zero for live-sequenced blocks — behavioral change not described in the PR

safeDataToBlock (used by NewSafeL2Block) still sets BatchHash from the safe-block payload, but executableDataToBlock (used by NewL2Block, the live sequencer path) does not set it at all. After this PR, any block built via the sequencer's normal NewL2Block path will always have BatchHash == common.Hash{}. The field is still present in the block header and exposed via eth/api.go as fields["batchHash"], so downstream indexers or explorers that relied on a non-zero BatchHash to identify batch boundaries on the canonical chain will silently see zeros. If this is intentional (batch boundaries now tracked elsewhere, e.g. by tx-submitter), it should be documented in the PR body.

func (api *l2ConsensusAPI) executableDataToBlock(params ExecutableL2Data) (*types.Block, error) {
header := &types.Header{
ParentHash: params.ParentHash,
Number: big.NewInt(int64(params.Number)),
GasUsed: params.GasUsed,
GasLimit: params.GasLimit,
Time: params.Timestamp,
Coinbase: params.Miner,
BaseFee: params.BaseFee,
NextL1MsgIndex: params.NextL1MessageIndex,
}
header.Difficulty = l2.Difficulty
header.Nonce = l2.Nonce
header.UncleHash = types.EmptyUncleHash
header.Extra = []byte{}
if api.eth.BlockChain().Config().Morph.FeeVaultEnabled() {
header.Coinbase = types.EmptyAddress
}
txs, err := decodeTransactions(params.Transactions)
if err != nil {
return nil, err
}
header.TxHash = types.DeriveSha(types.Transactions(txs), trie.NewStackTrie(nil))
header.ReceiptHash = params.ReceiptRoot
header.Root = params.StateRoot
header.Bloom = types.BytesToBloom(params.LogsBloom)
return types.NewBlockWithHeader(header).WithBody(txs, nil), nil
}

(Compare with safeDataToBlock which still sets it at line 266–290, showing the asymmetry.)

🤖 Generated with Claude Code

- If this code review was useful, please react with 👍. Otherwise, react with 👎.

@panos-xyz
Copy link
Copy Markdown
Contributor

Code review (additional finding)

[Important] morph_getRollupBatchL1FeeByIndex RPC and its read path should be deleted, not preserved

With rollup/batch/handler.go (and its Start / fillMissingFeeCalc / calculateL1FeeForBatch goroutine) removed, the write side for RollupBatchL1DataFeeKey is gone. GetRollupBatchL1FeeByIndex will now return nil for every batch on any new node — and for batches committed post-merge on existing nodes as well, since nothing ever writes the key again.

Cross-repo search (org:morph-l2) confirms no external consumers:

  • morph_getRollupBatchL1FeeByIndex / GetRollupBatchL1FeeByIndex references exist only inside morph-l2/go-ethereum itself (the RPC definition + the ethclient convenience wrapper).
  • morph-l2/morph, tx-submitter, oracle, and all other repos in the org: zero callers.

Preserving "historical-only backfill / on-demand recompute" is only valuable when there is a consumer that needs the data. There isn't one. Keeping an API that always returns nil for new batches is effectively dead code and is misleading to anyone who later integrates against it.

Recommend deleting, as a follow-up to this PR (or within it):

🤖 Generated with Claude Code

- If this code review was useful, please react with 👍. Otherwise, react with 👎.

@FletcherMan
Copy link
Copy Markdown
Collaborator Author

Addressed panos' review feedback in 0acdcf548:

  • Documented in the PR body that live-sequenced blocks intentionally keep Header.BatchHash zero after removing sequencer-side batch generation. Header.BatchHash remains for RLP/wire compatibility, and the NewSafeL2Block / SafeL2Data.BatchHash compatibility path is unchanged.
  • Removed the obsolete L1-fee read surface: morph_getRollupBatchL1FeeByIndex, the ethclient wrapper, RPCRollupBatch.CollectedL1Fee, rawdb L1-fee readers, and the now-unused rollup/batch/block_context.go decoder.

Validation:

  • go test ./eth/catalyst ./ethclient/authclient -short -count=1
  • go test ./eth ./ethclient ./core/rawdb -run '^$' -count=1

New reference tag: morph-v2.2.2-alpha.3.

Drop the L1 fee RPC/read helpers and leftover block context decoder now that sequencer batch fee collection is no longer written by geth.

Co-authored-by: Cursor <cursoragent@cursor.com>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
eth/catalyst/l2_api.go (1)

293-321: ⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Clarify the design intent for Header.BatchHash across live and safe block paths.

ExecutableL2Data deliberately omits BatchHash (per its documented design: "fields which need to be signed...and affect state calculation"). As a result, blocks constructed via the live sequencer path (NewL2Block / AssembleL2Block / ValidateL2Block) will have Header.BatchHash == common.Hash{}, while the safe path (NewSafeL2Block with SafeL2Data) populates it. Since BatchHash remains exposed in RPC output (eth/api.go:545), the same logical block built through different paths will have different hashes and different RPC representations.

If this asymmetry is intentional (i.e., BatchHash is only relevant for finalized, L1-approved blocks), document it explicitly in the PR description and ensure indexers, RPC clients, and derivation pipelines are aware that live-sequenced blocks will report zero batchHash. If not intentional, add BatchHash to ExecutableL2Data and populate it in executableDataToBlock, or remove it from the Header type entirely.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@eth/catalyst/l2_api.go` around lines 293 - 321, The current asymmetry is that
executableDataToBlock (which consumes ExecutableL2Data) leaves Header.BatchHash
zero while the safe-path (NewSafeL2Block using SafeL2Data) sets it, causing
differing block hashes/RPC output; decide and implement one of three fixes: 1)
If zero BatchHash for live blocks is intended, add a clear note in the PR and
repository docs and update any consumers (RPC/indexers/derivation) to expect
zero batchHash for sequenced blocks (mention
NewL2Block/AssembleL2Block/ValidateL2Block and eth API consumers); 2) If it is
not intended, extend ExecutableL2Data to include BatchHash and set
header.BatchHash inside executableDataToBlock so live-built blocks match
safe-built blocks; or 3) remove BatchHash from the Header type entirely if it
must not affect block identity; implement the chosen change and update related
tests and RPC serialization code that references Header.BatchHash.
🧹 Nitpick comments (1)
eth/catalyst/l2_api_test.go (1)

191-213: ⚡ Quick win

Consider locking in the new BatchHash semantics with an assertion.

The signature update is correct. Since this PR changes a header field's behavior on the live path (Header.BatchHash is now always zero for blocks built via NewL2Block), a small assertion here would prevent silent regressions:

♻️ Suggested addition
 	err = api.NewL2Block(l2Data)
 	require.NoError(t, err)
+
+	// Live-sequenced blocks no longer carry a BatchHash.
+	currentHeader := ethService.BlockChain().CurrentHeader()
+	require.Equal(t, common.Hash{}, currentHeader.BatchHash)

Skip if you plan to remove Header.BatchHash outright in a follow-up.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@eth/catalyst/l2_api_test.go` around lines 191 - 213, Add an assertion
verifying the new BatchHash semantics: after calling api.NewL2Block(l2Data) and
again after creating a block via api.AssembleL2Block/ api.NewL2Block (using resp
from AssembleL2Block and validResp from api.ValidateL2Block), retrieve the block
header and assert that Header.BatchHash is zero (empty/zero value) to lock in
the behavior change and prevent regressions; place the checks near the existing
balance assertions that follow NewL2Block and the Assemble/Validate/NewL2Block
sequence so failures clearly tie to the new header behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@eth/catalyst/l2_api.go`:
- Around line 293-321: The current asymmetry is that executableDataToBlock
(which consumes ExecutableL2Data) leaves Header.BatchHash zero while the
safe-path (NewSafeL2Block using SafeL2Data) sets it, causing differing block
hashes/RPC output; decide and implement one of three fixes: 1) If zero BatchHash
for live blocks is intended, add a clear note in the PR and repository docs and
update any consumers (RPC/indexers/derivation) to expect zero batchHash for
sequenced blocks (mention NewL2Block/AssembleL2Block/ValidateL2Block and eth API
consumers); 2) If it is not intended, extend ExecutableL2Data to include
BatchHash and set header.BatchHash inside executableDataToBlock so live-built
blocks match safe-built blocks; or 3) remove BatchHash from the Header type
entirely if it must not affect block identity; implement the chosen change and
update related tests and RPC serialization code that references
Header.BatchHash.

---

Nitpick comments:
In `@eth/catalyst/l2_api_test.go`:
- Around line 191-213: Add an assertion verifying the new BatchHash semantics:
after calling api.NewL2Block(l2Data) and again after creating a block via
api.AssembleL2Block/ api.NewL2Block (using resp from AssembleL2Block and
validResp from api.ValidateL2Block), retrieve the block header and assert that
Header.BatchHash is zero (empty/zero value) to lock in the behavior change and
prevent regressions; place the checks near the existing balance assertions that
follow NewL2Block and the Assemble/Validate/NewL2Block sequence so failures
clearly tie to the new header behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 510a90fc-4af5-4512-a686-1a273b75bb34

📥 Commits

Reviewing files that changed from the base of the PR and between 02e49e7 and 0acdcf5.

📒 Files selected for processing (9)
  • core/rawdb/accessors_rollup_batch.go
  • eth/api.go
  • eth/backend.go
  • eth/catalyst/l2_api.go
  • eth/catalyst/l2_api_test.go
  • ethclient/authclient/engine.go
  • ethclient/ethclient.go
  • rollup/batch/block_context.go
  • rollup/batch/handler.go
💤 Files with no reviewable changes (6)
  • ethclient/ethclient.go
  • rollup/batch/block_context.go
  • rollup/batch/handler.go
  • eth/api.go
  • eth/backend.go
  • core/rawdb/accessors_rollup_batch.go

@FletcherMan FletcherMan merged commit 39e9ab6 into main May 6, 2026
9 checks passed
@FletcherMan FletcherMan deleted the remove-sequencer-batch-generation branch May 6, 2026 07:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants