fix(PRIV-2006): seed AnchorStateRegistry with real L3 genesis output root#349
Merged
Merged
Conversation
…root
Dev-multiproof deploys settle to an anchor (the L2 genesis output root) that
is only known after L2 genesis, so the main deploy seeded the
AnchorStateRegistry with a placeholder root (0x..01). The TEE prover then
rejects every proof from that anchor ("Output root does not match L2 head"),
so the proposer creates zero dispute games and withdrawals never finalize.
Extend the existing AggregateVerifier deferral (PRIV-1997, #345) to the
AnchorStateRegistry: when MULTIPROOF_DEFER_REGISTRATION is set, the main deploy
upgrades the ASR proxy implementation but skips initialize(); the post-genesis
registerAggregateVerifier(bytes32) one-shot then initializes it exactly once
with the real genesis output root (read from cfg, regenerated post-genesis)
before deploying the AggregateVerifier. The init is idempotent (guarded on a
zero starting anchor) so one-shot retries are safe.
Also drop the now-stale assertion that Base Sepolia (84532) reverts in
test_deploy_devMultiproof_onProductionChain_reverts (PRIV-2004 made it a valid
dev-multiproof target).
Co-authored-by: Cursor <cursoragent@cursor.com>
hughy
approved these changes
Jun 23, 2026
robriks
added a commit
to base/base
that referenced
this pull request
Jun 23, 2026
…2006) (#3712) * fix: seed AnchorStateRegistry with real L2 genesis output root (PRIV-2006) The dev-multiproof anchor (L2 genesis output root) is only known after L2 genesis, so the main deploy seeded the AnchorStateRegistry with a placeholder (0x..01). The TEE prover then rejects every proof from that anchor ("Output root does not match L2 head"), so the proposer creates zero dispute games and withdrawals never finalize. - deploy-config.json.template: make multiproofGenesisOutputRoot substitutable. - setup-l2.sh: export a non-zero placeholder default so the main deploy passes SystemDeploy's startingAnchorRoot validation (the real root is unknowable pre-genesis). - register-aggregate-verifier.sh: post-genesis, compute the real output root from the L2 EL using the standard OP formula keccak256(0x0 ++ stateRoot ++ messagePasserStorageRoot ++ blockHash) at block 0 (op-node is being deprecated), then inject it into the regenerated deploy-config so registerAggregateVerifier initializes the registry with the true anchor. Pairs with base/contracts#349 (deferred ASR initialization). Co-authored-by: Cursor <cursoragent@cursor.com> * Apply suggestion from @hughy Co-authored-by: Hugh Cunningham <hugh.e.cunningham@gmail.com> --------- Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: Hugh Cunningham <hugh.e.cunningham@gmail.com>
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.
Summary
Dev-multiproof L3 deploys settle to an anchor — the L2 genesis output root — that is only known after L2 genesis. The main deploy runs before genesis, so it seeded the
AnchorStateRegistrywith a placeholder root (0x00..01). The TEE prover then rejects every proof built from that anchor (Output root does not match L2 head), the proposer creates zero dispute games, and L3→L1 withdrawals never finalize.This extends the existing AggregateVerifier deferral pattern (PRIV-1997, #345) to the
AnchorStateRegistry, so the registry is initialized exactly once with the real genesis output root.Linear: PRIV-2006
Changes (
scripts/deploy/SystemDeploy.s.sol)_initializeOPChain: whenMULTIPROOF_DEFER_REGISTRATIONis set (dev-multiproof only), upgrade the ASR proxy implementation via_upgradeTobut skipinitialize(). Nothing else in the deploy reads the registry's state. Non-deferred deploys are unchanged.registerAggregateVerifier(bytes32)(the post-genesis one-shot): initialize the ASR withcfg.multiproofGenesisOutputRoot()(regenerated post-genesis with the real root) before deploying theAggregateVerifier, whose constructor readsANCHOR_STATE_REGISTRY.disputeGameFactory(). Idempotent — guarded on a zero starting anchor, so one-shot retries are safe — and guarded against the placeholder/zero root._runConfigured: skip the guardiansetRespectedGameTypecall when deferring (the one-shot'sinitializesets it)._deferAggregateVerifierRegistrationmadevirtualso tests can force-enable deferral without mutating the process-global env.This reuses the existing config flow:
_configuredOPChainInputalready sourcesstartingAnchorRootfromcfg.multiproofGenesisOutputRoot()/cfg.multiproofGenesisBlockNumber(), so the deferred init is identical to the inline one — just executed post-genesis with the real value. No changes toAnchorStateRegistry.solor its interface.Tests
test_deploy_devMultiproof_deferred_anchorInitializedPostGenesis: asserts the deferred main deploy leaves the registry uninitialized (zero anchor, game type unregistered), then a post-genesisinitializeseeds the real anchor and respected game type. Uses aSystemDeployDeferredHarnesssubclass (overriding the deferral hook) instead ofvm.setEnv, which is process-global and races forge's parallel test contracts.test_deploy_devMultiproof_onProductionChain_reverts— PRIV-2004 (fix(PRIV-2004): allow dev multiproof on Base Sepolia (84532) #348) made 84532 a valid dev-multiproof target, leaving that assertion failing onl3-changesindependent of this PR.forge test --match-path test/deploy/SystemDeploy.t.sol: 13 passed.Companion PRs
The post-genesis root computation + deploy-config regeneration land in
base(register-aggregate-verifier.sh,deploy-config.json.template,setup-l2.sh) andprivacy-enclave(vendoredsetup-l2.sh,services.yml).Made with Cursor