Skip to content

fix(pxe): advance anchor past genesis when chain has moved (merge-train/spartan)#22710

Closed
AztecBot wants to merge 1 commit intomerge-train/spartanfrom
claudebox/spartan-merge-train-fix
Closed

fix(pxe): advance anchor past genesis when chain has moved (merge-train/spartan)#22710
AztecBot wants to merge 1 commit intomerge-train/spartanfrom
claudebox/spartan-merge-train-fix

Conversation

@AztecBot
Copy link
Copy Markdown
Collaborator

Fixes the merge-train/spartan CI failure in e2e_epochs/epochs_invalidate_block.parallel.test.ts (proposer invalidates previous checkpoint with multiple blocks while posting its own) failing with Circuit execution failed: Proving public value inclusion failed.

Root cause

Same class of bug as #22679: a PXE anchored at the initial header while the world state advances past genesis. PR #22679's TS-side fix in AztecNodeService.getWorldState replaced getSnapshot(BlockNumber.ZERO) with getCommitted() for the genesis-hash early return, but getCommitted() returns the latest committed tree state (WorldStateRevision.LATEST), not the genesis state. Once the chain advances past block 0, the witness comes from the latest tree but the kernel circuit validates it against the genesis root in historical_header.state.partial.public_data_tree.root, and assert(is_leaf_in_tree, ...) in storage_read.nr:44 fires.

The race was made tighter by #22586 enabling enableProposerPipelining: true, inboxLag: 2 in this test: the world state advances past genesis well before the first chain-checkpointed event reaches the PXE, so a PXE with syncChainTip: 'checkpointed' can be stuck at the initial header while the node has already moved on.

The full node-side fix requires either C++ support for genesis-state queries or a new "genesis snapshot" API and is non-trivial. This PR applies a targeted PXE-side workaround.

Fix

In BlockSynchronizer.doSync, after blockStream.sync(), if the anchor is still at block 0 but the node's L2 tips have advanced, advance the anchor to the appropriate tip. Tip selection respects syncChainTip, with a fallback to proposedCheckpoint/proposed when the configured tip is still at genesis. The helper short-circuits once the anchor is past block 0 (no-op on every subsequent sync) and is defensive against getL2Tips() failures.

Verification

  • yarn workspace @aztec/pxe test src/block_synchronizer/block_synchronizer.test.ts — 12/12 pass.
  • e2e_epochs/epochs_invalidate_block.parallel.test.ts "proposer invalidates previous checkpoint with multiple blocks while posting its own" — passes locally (~280 s).
  • e2e_epochs/epochs_mbps_redistribution.test.ts (the test fix(world-state): treat historical block 0 queries as historical, not latest #22679 originally targeted) — 2/2 pass.

Links

Follow-up

The underlying bug in AztecNodeService.getWorldState (returning latest tree state for genesis-hash queries) should be properly fixed in the node, not the PXE. This PR unblocks merge-train/spartan; the node-side fix can be tracked separately.

ClaudeBox log: https://claudebox.work/s/3a5c7418b1f6595c?run=1

@AztecBot AztecBot added ci-draft Run CI on draft PRs. claudebox Owned by claudebox. it can push to this PR. labels Apr 21, 2026
@AztecBot
Copy link
Copy Markdown
Collaborator Author

Automatically closing this stale claudebox draft PR (no updates for 5+ days). Re-open if still needed.

@AztecBot AztecBot closed this Apr 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci-draft Run CI on draft PRs. claudebox Owned by claudebox. it can push to this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant