Skip to content

feat(PRIV-1997): defer + register AggregateVerifier for runtime config_hash#345

Merged
robriks merged 4 commits into
l3-changesfrom
markusosterlund/priv-1997-systemdeploy-deferred-aggregateverifier-registration-for
Jun 17, 2026
Merged

feat(PRIV-1997): defer + register AggregateVerifier for runtime config_hash#345
robriks merged 4 commits into
l3-changesfrom
markusosterlund/priv-1997-systemdeploy-deferred-aggregateverifier-registration-for

Conversation

@robriks

@robriks robriks commented Jun 17, 2026

Copy link
Copy Markdown

Summary

The L3 infra currently starts a fresh chain on every boot, so its config_hash (which commits to genesis.l1.hash, genesis.l2.hash, and l2_time) is not known until after L2 genesis is generated and the execution layer initializes. Since
AggregateVerifier.CONFIG_HASH is an immutable in a solady CWIA clone, it can't be set up-front in that scenario (unlike settling an already-genesised chain such as Base, whose genesis is a frozen historical fact).

This adds a deferral + post-genesis registration path to SystemDeploy:

  • _deferAggregateVerifierRegistration — dev-multiproof only, opt-in via the
    MULTIPROOF_DEFER_REGISTRATION env var. When set, _deployMultiproofContracts
    deploys the TEE prover registry + TEE/ZK verifiers but skips the AggregateVerifier
    deployment and setImplementation. Production / precompute flows are unchanged.
  • registerAggregateVerifier(bytes32) — resumable post-genesis entrypoint.
    Reloads config params from cfg and deployed addresses from artifacts, reuses
    the existing _newAggregateVerifier to build the verifier with the real hash, then
    disputeGameFactory.setImplementation(gameType, impl).

Because the proposer is the only game creator and starts only after registration, no game is ever cloned from a wrong-hash implementation (setImplementation only swaps the blueprint for future clones)

Context

The matching base-side wiring (compute the hash via nitro-host config-hash and invoke this entrypoint in a one-shot after genesis) lands in PRIV-1984; this PR provides the entrypoint and the pinned CONTRACTS_COMMIT.

robriks and others added 3 commits June 17, 2026 11:57
…V-1997)

A dev multiproof devnet mints a fresh chain on every boot, so its
config_hash (which commits to genesis.l1.hash, genesis.l2.hash, l2_time)
is not known until after L2 genesis is generated and the EL initializes.
AggregateVerifier.CONFIG_HASH is an immutable in a solady CWIA clone, so
it cannot be set up front in that scenario.

- _deferAggregateVerifierRegistration: dev-multiproof only, opt-in via the
  MULTIPROOF_DEFER_REGISTRATION env var. When set, _deployMultiproofContracts
  deploys the registry + TEE/ZK verifiers but skips the AggregateVerifier +
  setImplementation. Production / precompute flows are unchanged.
- registerAggregateVerifier(bytes32): re-entrant post-genesis entrypoint that
  reloads config params from cfg and deployed addresses from artifacts, reuses
  _newAggregateVerifier to build the verifier with the real hash, then
  setImplementation(gameType, impl). Broadcast by the factory owner
  (finalSystemOwner == deployer in devnet).

Co-authored-by: Cursor <cursoragent@cursor.com>
registerAggregateVerifier hardcodes the dev ZK sentinel (0xdead), so it must
never run against a production (Base<>Ethereum) config. Require the configured
input to be dev multiproof (no real nitroEnclaveVerifier) and run
_assertValidMultiproofInput, which also blocks production chain IDs.

Co-authored-by: Cursor <cursoragent@cursor.com>
@robriks robriks self-assigned this Jun 17, 2026
@linear

linear Bot commented Jun 17, 2026

Copy link
Copy Markdown

PRIV-1997

…ier (PRIV-1997)

registerAggregateVerifier runs in a fresh forge process (the deferred
post-genesis one-shot), where Artifacts._namedDeployments is empty because
setUp() only seeds predeploys and the map is otherwise populated by save()
within the same process. As a result mustGetAddress() reverted, and even a
successful save() would clobber the deploy outfile (whole-file writeJson with
only the AggregateVerifier key).

Add Artifacts.load() to read the existing outfile back into _namedDeployments
and re-seed forge's stateful JSON object so a later save() appends instead of
overwriting, and call it at the top of registerAggregateVerifier. Add a unit
test covering the reload + append-without-clobber behavior.

Co-authored-by: Cursor <cursoragent@cursor.com>
@robriks robriks merged commit 65dd69c into l3-changes Jun 17, 2026
2 of 3 checks passed
@robriks robriks deleted the markusosterlund/priv-1997-systemdeploy-deferred-aggregateverifier-registration-for branch June 17, 2026 18:12
robriks added a commit that referenced this pull request Jun 23, 2026
…root (#349)

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>
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