Skip to content

fix(tx-submitter): re-check submitter activity before each submit, and never rough-estimate past a revert - #1048

Merged
SegueII merged 2 commits into
mainfrom
fix/submitter-activity-recheck
Aug 28, 2026
Merged

fix(tx-submitter): re-check submitter activity before each submit, and never rough-estimate past a revert#1048
SegueII merged 2 commits into
mainfrom
fix/submitter-activity-recheck

Conversation

@SegueII

@SegueII SegueII commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

Problem

commitBatch / commitState / finalizeBatch all carry onlyActiveSubmitter
(Rollup.sol:119-120, applied at :257, :275, :598),
but tx-submitter probed activity exactly once — PreCheck() at Start()
(rollup.go:148). The rollup() and finalize() loops then submitted forever
against that stale startup result.

A submitter can leave the active set at any point after startup:
removeSubmitter (Submitter.sol:83), self-service withdraw() (:120),
slash after a successful challenge (:146), or setMinimumStake raising the
bar (:92).

With rough_estimate_gas enabled this is a funds leak, not just a stall:

  1. eth_estimateGas fails on the revert.
  2. The rough fallback swallowed that failure and guessed a gas limit
    (rollup.go:1013, :844).
  3. The tx was signed and sent anyway, and reverted on-chain.

A revert refunds unused execution gas, but a commitBatch blob tx
(createBlobTx, rollup.go:1088) is charged its full blob fee regardless of
whether execution reverted — that is the real drain.

Nothing broke the cycle. The failed receipt only produces a log.Warn
(rollup.go:696-706); after 6 confirmations the tx leaves the pending pool
(rollup.go:421), the loop re-derives the same batchIndex (rollup.go:923-931)
and resends. MaxTxsInPendingPool caps in-flight txs, not cumulative attempts,
and wallet balance is only exported as a metric — there is no low-balance guard.

Fix

  • Extract ensureActiveSubmitter() and call it at the top of rollup() and
    finalize(). An RPC failure on the probe also stops submission, rather than
    assuming the wallet is still eligible.
  • Gate both rough-estimate fallbacks on a new utils.IsExecutionRevertErr, so
    the flag still does what it was added for (flaky / unreachable node) but never
    guesses past a contract rejection.

The added per-tick eth_call is one extra read per rollup/finalize interval.

Tests

tx-submitter/services/rollup_submitter_activity_test.go,
tx-submitter/utils/errors_test.go. Each new test was confirmed to fail with the
fix reverted. go test ./tx-submitter/... passes.

mock.L1ClientWrapper gains an EstimateGasErr field so the estimate-failure
paths are reachable from tests.

Note on the second audit finding

The same audit reported, at LOW, that InitAndSyncFromDatabase's committed-window
loop validates middle batches only against the persisted Hash field without
independently recomputing header.Hash(). On verification this is a false
positive and no change is included for it.

LoadAllSealedBatchesAndHeader — the first step of InitAndSyncFromDatabase
already re-hashes every loaded header and compares it to that batch's persisted
Hash (common/batch/batch_storage.go:209-221). Composed with the window loop's
batches[i].Hash == CommittedBatches(i), this yields
keccak(headers[i]) == CommittedBatches(i) across the whole committed window.
There is no gap, and adding a second re-hash in batch_cache.go would be dead
weight.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Transactions are no longer submitted when the configured wallet is inactive.
    • Activity-check failures now stop submission instead of proceeding.
    • Contract-reverted gas estimates are no longer bypassed with rough estimates.
    • Rough gas estimation remains available for non-revert estimation failures.
  • Tests
    • Added coverage for inactive submitters, activity-check errors, and gas-estimation behavior.

…d never rough-estimate past a revert

commitBatch / commitState / finalizeBatch all carry onlyActiveSubmitter on L1,
but the activity probe only ran once, in PreCheck at Start(). A submitter can be
removed, slashed, priced out by a raised minimum stake, or start withdrawing at
any point afterwards, and the rollup / finalize loops kept submitting against a
stale startup result.

With rough_estimate_gas enabled this became a funds leak rather than a stall:
eth_estimateGas fails on the revert, the rough fallback swallowed that failure
and guessed a gas limit, and the tx was signed and sent anyway. The reverting tx
refunds unused execution gas, but a commitBatch blob tx is charged its full blob
fee regardless of revert. Nothing broke the cycle — the failed receipt only logs
a warning, and once the tx leaves the pending pool the loop re-derives the same
batch index and resends, with no low-balance guard.

- extract ensureActiveSubmitter and call it at the top of rollup() and
  finalize(); an RPC failure on the probe also stops submission rather than
  assuming the wallet is still eligible
- gate both rough-estimate fallbacks on utils.IsExecutionRevertErr, so the flag
  still covers a flaky/unreachable node but never guesses past a contract
  rejection

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@SegueII
SegueII requested a review from a team as a code owner August 28, 2026 06:52
@SegueII
SegueII requested review from twcctop and removed request for a team August 28, 2026 06:52
@coderabbitai

coderabbitai Bot commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: a83306f2-c346-4f0a-a8df-d600dd4a843c

📥 Commits

Reviewing files that changed from the base of the PR and between 6cdd638 and fbf9ef6.

📒 Files selected for processing (5)
  • tx-submitter/mock/l1client.go
  • tx-submitter/services/rollup.go
  • tx-submitter/services/rollup_submitter_activity_test.go
  • tx-submitter/utils/errors.go
  • tx-submitter/utils/errors_test.go

Included review availability: Your plan provides up to 1 included review per hour; 0 remain after this review.


📝 Walkthrough

Walkthrough

Changes

Rollup submitter safety

Layer / File(s) Summary
Execution revert classification
tx-submitter/utils/errors.go, tx-submitter/utils/errors_test.go
Adds IsExecutionRevertErr to classify known execution-revert messages. Tests cover nil, transport, timeout, and revert errors.
Submitter activity and gas estimation flow
tx-submitter/services/rollup.go, tx-submitter/mock/l1client.go, tx-submitter/services/rollup_submitter_activity_test.go
rollup() and finalize() now verify active submitter status before submission. Rough gas estimation no longer bypasses execution reverts. Tests cover inactive submitters, activity probe failures, and transport fallback behavior.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Merge Risk: 🟡 Moderate · up to fbf9e

The change reduces repeated submissions after submitter deactivation and recognized execution reverts, but pending transaction replacements can still be sent after deactivation, and some contract-rejection responses may still be mistaken for temporary estimation failures. This can cause unauthorized or reverted fee-bearing transactions, so the PR needs follow-up or explicit owner acceptance before merge.

Suggested reviewers: twcctop, dylancai9

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 57.14% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 7 functions across 5 files. 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 title clearly and concisely summarizes both primary changes: re-checking submitter activity before submission and preventing rough gas estimation after execution reverts.
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.
  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/submitter-activity-recheck

Warning

Billing warning: we have not been able to collect payment for this subscription for more than 72 hours. Please update the payment method or pay any pending invoices in Billing to avoid service interruption.


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.

@SegueII
SegueII merged commit ad4fd55 into main Aug 28, 2026
9 checks passed
@SegueII
SegueII deleted the fix/submitter-activity-recheck branch August 28, 2026 07:28
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.

2 participants