feat(PRIV-1997): defer + register AggregateVerifier for runtime config_hash#345
Merged
robriks merged 4 commits intoJun 17, 2026
Conversation
…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>
…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>
dguenther
approved these changes
Jun 17, 2026
This was referenced Jun 17, 2026
Merged
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>
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
The L3 infra currently starts a fresh chain on every boot, so its
config_hash(which commits togenesis.l1.hash,genesis.l2.hash, andl2_time) is not known until after L2 genesis is generated and the execution layer initializes. SinceAggregateVerifier.CONFIG_HASHis 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 theMULTIPROOF_DEFER_REGISTRATIONenv var. When set,_deployMultiproofContractsdeploys the TEE prover registry + TEE/ZK verifiers but skips the
AggregateVerifierdeployment and
setImplementation. Production / precompute flows are unchanged.registerAggregateVerifier(bytes32)— resumable post-genesis entrypoint.Reloads config params from
cfgand deployed addresses fromartifacts, reusesthe existing
_newAggregateVerifierto build the verifier with the real hash, thendisputeGameFactory.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 (
setImplementationonly swaps the blueprint for future clones)Context
The matching base-side wiring (compute the hash via
nitro-host config-hashand invoke this entrypoint in a one-shot after genesis) lands in PRIV-1984; this PR provides the entrypoint and the pinnedCONTRACTS_COMMIT.