Skip to content

fix(PRIV-2006): resolve ASR initialize args before vm.broadcast#350

Merged
robriks merged 1 commit into
l3-changesfrom
markusosterlund/priv-2006-fix-broadcast-order
Jun 23, 2026
Merged

fix(PRIV-2006): resolve ASR initialize args before vm.broadcast#350
robriks merged 1 commit into
l3-changesfrom
markusosterlund/priv-2006-fix-broadcast-order

Conversation

@robriks

@robriks robriks commented Jun 23, 2026

Copy link
Copy Markdown

Summary

registerAggregateVerifier armed vm.broadcast(msg.sender) and then passed artifacts.mustGetAddress(...) / cfg.multiproofGenesisBlockNumber() directly as anchorStateRegistry.initialize(...) arguments. Solidity evaluates those cheatcode staticcalls after the broadcast is armed, which Foundry forbids:

VM::broadcast(0x609a88…)
Artifacts::mustGetAddress("SystemConfigProxy") [staticcall]
  └─ [Revert] `staticcall`s are not allowed after `broadcast`; use `startBroadcast` instead

So the post-genesis one-shot reverted and the AnchorStateRegistry was never seeded — the anchor stayed uninitialized and the proposer/prover could not generate proofs.

Fix

Hoist the SystemConfig/DisputeGameFactory lookups and the starting-anchor Proposal into locals before vm.broadcast, so only the initialize() call itself is broadcast. (Locals are anchor-prefixed to avoid shadowing the later disputeGameFactory in the same function.)

Evidence

Verified live on web3-shared-dev with the deployed image (Commit hash cd6c8a2d): the register one-shot correctly computed the real genesis output root (multiproofGenesisOutputRoot() → 0xa53d466c…, gameType 621) and the ASR was correctly deferred/uninitialized — only the initialize() call reverted on this cheatcode ordering.

Type

Bug fix.

Risk

Low — reordering of local variable resolution; no behavioral change to the on-chain initialize call. forge build passes.

Follow-up

The existing deferred-init unit test calls ASR.initialize directly and so didn't exercise the broadcast path; a follow-up could drive registerAggregateVerifier end-to-end.

Made with Cursor

registerAggregateVerifier armed vm.broadcast(msg.sender) and then passed
artifacts.mustGetAddress(...) / cfg.* directly as initialize() arguments.
Solidity evaluates those cheatcode staticcalls after the broadcast is armed,
which Foundry rejects ("staticcalls are not allowed after broadcast"), so the
post-genesis one-shot reverted and the AnchorStateRegistry was never seeded
(anchor stayed uninitialized -> proposer/prover could not generate proofs).

Hoist the SystemConfig/DisputeGameFactory lookups and the starting-anchor
Proposal into locals before vm.broadcast so only the initialize() call is
broadcast. Verified on web3-shared-dev: the real genesis output root was
computed (0xa53d466c...) but initialize reverted on this ordering.

Co-authored-by: Cursor <cursoragent@cursor.com>
@linear

linear Bot commented Jun 23, 2026

Copy link
Copy Markdown

PRIV-2006

@robriks robriks self-assigned this Jun 23, 2026
@robriks robriks merged commit 25ac730 into l3-changes Jun 23, 2026
3 checks passed
@robriks robriks deleted the markusosterlund/priv-2006-fix-broadcast-order branch June 23, 2026 20:47
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.

3 participants