Skip to content

fix(PRIV-2006): seed AnchorStateRegistry with real L3 genesis output root#349

Merged
robriks merged 1 commit into
l3-changesfrom
markusosterlund/priv-2006-defer-asr-init
Jun 23, 2026
Merged

fix(PRIV-2006): seed AnchorStateRegistry with real L3 genesis output root#349
robriks merged 1 commit into
l3-changesfrom
markusosterlund/priv-2006-defer-asr-init

Conversation

@robriks

@robriks robriks commented Jun 22, 2026

Copy link
Copy Markdown

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 AnchorStateRegistry with 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: when MULTIPROOF_DEFER_REGISTRATION is set (dev-multiproof only), upgrade the ASR proxy implementation via _upgradeTo but skip initialize(). 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 with cfg.multiproofGenesisOutputRoot() (regenerated post-genesis with the real root) before deploying the AggregateVerifier, whose constructor reads ANCHOR_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 guardian setRespectedGameType call when deferring (the one-shot's initialize sets it).
  • _deferAggregateVerifierRegistration made virtual so tests can force-enable deferral without mutating the process-global env.

This reuses the existing config flow: _configuredOPChainInput already sources startingAnchorRoot from cfg.multiproofGenesisOutputRoot() / cfg.multiproofGenesisBlockNumber(), so the deferred init is identical to the inline one — just executed post-genesis with the real value. No changes to AnchorStateRegistry.sol or its interface.

Tests

  • New test_deploy_devMultiproof_deferred_anchorInitializedPostGenesis: asserts the deferred main deploy leaves the registry uninitialized (zero anchor, game type unregistered), then a post-genesis initialize seeds the real anchor and respected game type. Uses a SystemDeployDeferredHarness subclass (overriding the deferral hook) instead of vm.setEnv, which is process-global and races forge's parallel test contracts.
  • Drops the now-stale assertion that Base Sepolia (84532) reverts in 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 on l3-changes independent 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) and privacy-enclave (vendored setup-l2.sh, services.yml).

Made with Cursor

…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>
@linear

linear Bot commented Jun 22, 2026

Copy link
Copy Markdown

PRIV-2006

@robriks robriks merged commit cd6c8a2 into l3-changes Jun 23, 2026
3 checks passed
@robriks robriks deleted the markusosterlund/priv-2006-defer-asr-init branch June 23, 2026 17:59
@robriks robriks self-assigned this 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>
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