contracts-bedrock: remove SystemConfig batchInbox and setGasConfig - #21641
Merged
Conversation
This was referenced Jul 8, 2026
Contributor
|
Preview deployment for your docs. Learn more about Mintlify Previews.
|
Contributor
|
This pr has been automatically marked as stale and will be closed in 5 days if no updates |
mds1
force-pushed
the
mds/systemconfig-remove-unused-getters
branch
from
July 27, 2026 15:31
cb71d80 to
4a40aa3
Compare
mds1
added a commit
to ethereum-optimism/superchain-ops
that referenced
this pull request
Jul 27, 2026
…deV800 op-contracts/v8.0.0 removes `batchInbox()` from the SystemConfig and clears the legacy slot during reinitialization, so a direct `sysCfg.batchInbox()` call reverts once a chain is on SystemConfig 4.0.0. Read it with a staticcall that works against both 3.14.x and 4.0.0 instead, resolving to `address(0)` when the selector is missing. A missing selector reverts with empty return data, so we still surface any revert that carries data rather than treating it as the post-removal case. Same change in the SuperRootMigrate integration test, which duplicates the EOA-etching loop. See ethereum-optimism/optimism#21641 and ethereum-optimism/optimism#21614. This carries forward the fix from the now-obsolete #1492, which targeted the V800 templates before they were removed from main in #1501.
During U19, OPCMv2's reinit-everything path recomputed the batch inbox address via `_chainIdToBatchInboxAddress` (the new-chain scheme) instead of preserving the existing value, rotating it for every pre-OPCM chain. Nothing in the OP Stack reads it, since derivation takes the batch inbox from the rollup config, so it was harmless, but it showed the onchain copy is a redundant source of truth that can silently drift. Remove the copy rather than fix the reinit path. Closes #21614. `batchInbox()` and the `_batchInbox` initializer param are gone, and `initialize` clears the legacy slot. OPCMv2 no longer computes a batch inbox, the migrator no longer reads and re-passes one, and the now-unused `_chainIdToBatchInboxAddress` helper is removed. `OPContractsManagerUtils.chainIdToBatchInboxAddress` stays because op-deployer still derives new-chain batch inboxes with the same convention. `setGasConfig` goes for the same reason. It could only write version-0 scalars and did not update the `basefeeScalar`/`blobbasefeeScalar` mirrors that OPCMv2's `_loadFullConfig` reads, so calling it desynchronized `scalar` from those mirrors and the next upgrade silently reverted the change. Because `_setGasConfigEcotone` writes all three atomically, removing the only other writer makes them agree by construction, so OPCM needs no change. `overhead` is therefore immutable, which is fine because op-node zeroes it after Ecotone. `startBlock` is deliberately kept: `_setStartBlock()` only writes when the slot is 0, so reinitialization preserves it, unlike the batch inbox which was overwritten unconditionally. Two new tests cover the difference. Keeping it also means `op-node genesis l2` needs no change, and keeping `overhead` means no storage layout change. Removes the `GPOParamsChange` action test, which drove a pre-Ecotone GPO change through `setGasConfig`. Action tests deploy contracts from local source, so there is no longer a function to call. The derivation path it covered keeps unit coverage in the `GasConfig` case of op-node/rollup/derive/system_config_test.go. Semver 3.14.2 -> 4.0.0, init version 3 -> 4, OPCMv2 7.2.2 -> 7.2.3.
Deleting all of GPOParamsChange threw away coverage that did not depend on `setGasConfig`. Its first half checks the pre-Ecotone L1 data fee end to end against the genesis gas config: op-node derives the fee parameters, the sequencer applies them through the L1 attributes transaction, and they surface on the receipt. Restore that as GPODefaultParams. Only the second half needed the removed setter, and that scenario is unreachable now — no live chain is pre-Ecotone, and nothing can write a version-0 scalar once `setGasConfig` is gone. Drops the L2Batcher setup along with it, since only the removed half submitted batches.
mds1
force-pushed
the
mds/systemconfig-remove-unused-getters
branch
from
July 27, 2026 19:56
a898283 to
5651432
Compare
mds1
commented
Jul 27, 2026
mds1
commented
Jul 27, 2026
develop independently reached 7.2.3, so this PR's OPCMv2 changes need a new dev-work patch bump to satisfy the semver-diff check. Co-Authored-By: Claude
sebastianst
reviewed
Jul 28, 2026
maurelian
reviewed
Jul 28, 2026
`_setGasConfigEcotone` now encodes `uint256(0)` instead of the legacy `overhead` value. op-node zeroes the overhead after Ecotone, so the emitted value was already ignored, and the word cannot be dropped because the event data is expected to be 64 bytes long. The `overhead` variable and its getter stay, so the ABI is unchanged and offchain readers (superchain-registry's L1 staging report, op-analytics) keep working. `setGasConfig` was its only writer, so it is now immutable.
OptimismBot
force-pushed
the
mds/systemconfig-remove-unused-getters
branch
from
July 28, 2026 17:29
e2c7104 to
14e2268
Compare
Mark `overhead` with `@custom:deprecated`, trim the comments this PR added, and put a TODO on the legacy batch inbox slot clear so it and the constant come out after U20 (maurelian). Per seb: remove `op-chain-ops/cmd/ecotone-scalar` outright rather than reword its README, source the batch inbox from the rollup config in the data glossary, and rebuild the deleted half of `GPOParamsChange` on Ecotone as `TestGPOParamsChangeEcotone` with `setGasConfigEcotone` instead of dropping its assertions. The rebuilt test cannot compare the derived config against `Genesis.SystemConfig` wholesale the way the old one did: `initialize` calls `_setGasConfigEcotone`, so on an Ecotone chain the derived config is already on the versioned scalar encoding with a zeroed overhead while the genesis config still carries the pre-Ecotone encoding. It compares the scalars instead. Also point the custom gas token guide's fee bullets at `setMinBaseFee` and `setOperatorFeeScalars`, the actual setters for those parameters. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Stale sourceCodeHash came from comment-only edits made after the last regen. Co-Authored-By: Claude
6 tasks
mds1
commented
Jul 29, 2026
maurelian
reviewed
Jul 29, 2026
maurelian
reviewed
Jul 29, 2026
maurelian
reviewed
Jul 29, 2026
maurelian
approved these changes
Jul 29, 2026
ajsutton
approved these changes
Jul 30, 2026
sebastianst
approved these changes
Jul 30, 2026
sebastianst
left a comment
Member
There was a problem hiding this comment.
🤖 GPT-5.6 says: Approved. The inline comments are non-blocking.
…emove-unused-getters # Conflicts: # packages/contracts-bedrock/snapshots/semver-lock.json
mds1
enabled auto-merge
July 30, 2026 23:28
sbvegan
approved these changes
Jul 31, 2026
claude Bot
pushed a commit
that referenced
this pull request
Jul 31, 2026
Resolves conflicts with #21641 (SystemConfig batchInbox/setGasConfig removal): SystemConfig keeps upstream's 4.0.0 major version, which subsumes the minor bump from this branch, and semver-lock.json is regenerated from the merged sources. Co-Authored-By: Claude Co-authored-by: John Mardlin <john@oplabs.co>
claude Bot
pushed a commit
that referenced
this pull request
Jul 31, 2026
The merge from develop brought in #21641, which had already taken 4.0.0, so this branch's SystemConfig changes (initVersion removal) need their own version bump for the semver-diff check to pass. Co-Authored-By: Claude Co-authored-by: John Mardlin <john@oplabs.co>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
During U19, OPCMv2's reinit-everything path recomputed the SystemConfig batch inbox address via
_chainIdToBatchInboxAddress(the new-chain scheme) instead of preserving the existing value, rotating the onchain batch inbox for all pre-OPCM chains (OP, Unichain, Mode, Metal, Zora). Nothing in the OP Stack reads it — derivation takes the batch inbox from the rollup config — so it was harmless, but it showed the onchain copy is a redundant source of truth that can silently drift. This PR removes the copy rather than fixing the reinit path. Closes #21614.Two removals, both eliminating a duplicate write path instead of patching its symptom:
batchInbox()and the_batchInboxinitializer param are gone, andinitializenow clears the legacy slot so the stale value is zeroed for every chain at the next upgrade.OPContractsManagerV2._makeSystemConfigInitArgsno longer computes a batch inbox (the exact line that caused the U19 rotation),OPContractsManagerMigratorno longer reads and re-passes one, and the now-unused_chainIdToBatchInboxAddresshelper is removed fromOPContractsManagerUtilsCaller.OPContractsManagerUtils.chainIdToBatchInboxAddressstays — op-deployer still derives new-chain batch inboxes with the same convention.setGasConfigand_setGasConfigare gone.setGasConfigcould only write version-0 scalars (therequireblocks a nonzero top byte) and did not update thebasefeeScalar/blobbasefeeScalarmirrors. OPCMv2's_loadFullConfigreads those mirrors, notscalar(), so callingsetGasConfigdesynchronized them and the next upgrade silently reverted the operator's change — the same recompute-instead-of-preserve bug class as the batch inbox. op-node accepts version-0 scalars after Ecotone (CheckEcotoneL1SystemConfigScalarallowsL1ScalarBedrock), so this was live rather than theoretical. Because_setGasConfigEcotonewritesbasefeeScalar,blobbasefeeScalar, andscalaratomically, removing the only other writer makes the mirrors agree withscalarby construction — no OPCM change needed.overheadstays, now marked@custom:deprecated.setGasConfigwas its only writer, so it is no longer writable, and_setGasConfigEcotonehardcodesuint256(0)in its place instead of re-emitting the stored value: op-node ignores the overhead after Ecotone, and theFEE_SCALARSpayload has to stay 64 bytes, so the word cannot simply be dropped. Keeping the getter also means superchain-registry's L1 staging report, which callsoverhead()on every chain, needs no change. Removing the variable outright is deliberately deferred to a future tech-debt pass rather than scope-creeping this one.op-chain-ops/cmd/ecotone-scalaris deleted. It existed to compute thescalarargument forsetGasConfig; thejust ecotone-scalarrecipe and theop-chain-opsREADME entry go with it. An old monorepo commit can be checked out if it is ever needed for historical purposes.Semver 3.14.2 → 4.0.0, init version 3 → 4. OPCMv2 gets the dev-work patch bump to 7.2.4.
Test coverage
GPOParamsChangeinop-e2e/actions/derivation/system_config_test.gohad two halves, and only one of them usedsetGasConfig. Both survive, split in two.The half that never touched the setter is now
GPODefaultParams. It builds a Delta-only chain, sends one L2 transaction, and checks the pre-Ecotone L1 data fee end to end against the genesis gas config:L1GasPricematches the L1 origin basefee,L1Fee == basefee * L1GasUsed * FeeScalar,L1Feematchestypes.L1Cost(L1GasUsed - 2100, basefee, 2100, 1_000_000), andFeeScalaris 1. That exercises op-node deriving the fee parameters, the sequencer applying them through the L1 attributes transaction, and the values surfacing on the receipt.The half that changed the gas config mid-chain is rebuilt on Ecotone as
TestGPOParamsChangeEcotone, usingsetGasConfigEcotoneinstead ofsetGasConfig. It activates Ecotone as the latest fork, moves the basefee scalar 1_000_000 → 2_300_000 and the blobbasefee scalar 0 → 800_000, and checks the same three points in time the old test did: the derived scalars are unchanged in the last L2 block before the L1 origin with the update is adopted, they change in the exact block that adopts it, and they persist across a later L1 origin. At each point the receipt's L1 data fee is recomputed independently withopfees.L1CostEcotonefrom the fee parameters the receipt itself reports, and the receipt'sL1BaseFeeScalar/L1BlobBaseFeeScalarare checked against the values written on L1. It is not parameterized over batch type, because Ecotone implies Delta and the singular-batch case is unreachable.One assertion could not be carried over as-is: the old test compared the derived config against
Genesis.SystemConfigwholesale. On an Ecotone chain that never holds, becauseinitializecalls_setGasConfigEcotone, so the derived config is already on the versioned scalar encoding with a zeroed overhead while the genesis config still carries the pre-Ecotone encoding from the deploy config. The new test compares the scalars instead.testFuzz_setGasConfigEcotone_succeedsnow seeds theoverheadslot with 2100 before calling the setter, so the event assertion proves the emitted zero is hardcoded rather than read from storage, and assertsoverhead()still returns 2100 afterwards.Why removal is safe
I audited the monorepo (Go, Rust, Solidity), superchain-registry, superchain-ops, monitorism, security-tools, op-txverify, ecosystem, specs, and docs, plus a GitHub code search across the org.
batchInbox()has zero contract-level readers:op-node/cmd/batch_decoderusesrollupCfg.BatchInboxAddress, superchain-registry'sstaging.gouses the deploy config, and op-geth'ssuperchain/types.gois a config struct field. No monitor readsstartBlock()either — monitorism'swithdrawals-v2StartBlockis a--start.blockCLI flag for backfill scanning.No superchain-ops change needed
OPCMUpgradeV800andOPCMUpgradeV700both callsysCfg.batchInbox()while etching code at EOA-valued slots, but they do it from_templateSetup, which runs before the upgrade executes. The SystemConfig is still on the pre-V800 version at that point, so the getter is there, and neither template reads it afterwards. ethereum-optimism/superchain-ops#1492 was opened on the assumption that a version-tolerant read was needed and has been closed as unnecessary; its target file had also since been removed frommainin ethereum-optimism/superchain-ops#1501.Note for third parties
Reading
batchInbox()or callingsetGasConfigstops working at op-contracts v8.0.0. The batch inbox address remains in the superchain registry and in each chain's rollup config, which are the values the OP Stack actually uses.overhead()keeps working, butFEE_SCALARSConfigUpdateevents now carry a zero in its slot.Companion PR: ethereum-optimism/specs#922.