Skip to content

feat(world-state): add blockHash verification to syncImmediate#21556

Merged
PhilWindle merged 1 commit intomerge-train/spartanfrom
palla/sync-immediate-block-hash-verification
Mar 16, 2026
Merged

feat(world-state): add blockHash verification to syncImmediate#21556
PhilWindle merged 1 commit intomerge-train/spartanfrom
palla/sync-immediate-block-hash-verification

Conversation

@spalladino
Copy link
Contributor

Motivation

syncImmediate syncs world state to a target block number but does not verify block identity. If a reorg occurred and the world state is at the same height but on a different fork, the method returns early without detecting the mismatch. Additionally, skipThrowIfTargetNotReached was dead code with no caller ever passing true.

Approach

Added an optional typed BlockHash parameter to syncImmediate. When at or past the target height, the implementation checks the hash via getL2BlockHash before returning early. On mismatch it falls through to trigger a resync. After syncing, if the hash still doesn't match, it throws a WorldStateSynchronizerError with reason block_hash_mismatch. Removed the unused skipThrowIfTargetNotReached parameter entirely.

Changes

  • stdlib: Updated WorldStateSynchronizer interface signature — replaced skipThrowIfTargetNotReached?: boolean with blockHash?: BlockHash
  • world-state: Implemented block hash verification in ServerWorldStateSynchronizer.syncImmediate with pre-sync and post-sync checks
  • p2p: Both tx pool v1 and v2 FeePayerBalanceEvictionRule now pass BlockHash from context.block.hash() on BLOCK_MINED events
  • prover-node: Passes last block's header hash when syncing world state before creating proving jobs
  • txe: Updated mock synchronizer parameter name and type
  • world-state (tests): Added tests for hash match (early return), hash mismatch (triggers resync), and hash mismatch after sync (throws)
  • p2p (tests): Updated mock expectations to verify blockHash is passed in BLOCK_MINED handlers

Adds an optional `BlockHash` parameter to `syncImmediate` for reorg detection.
When provided, verifies the block at the target number matches the expected hash.
On mismatch, triggers a resync; if still mismatched after sync, throws.
Also removes dead `skipThrowIfTargetNotReached` parameter (no caller passed `true`).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@spalladino spalladino added ci-no-fail-fast Sets NO_FAIL_FAST in the CI so the run is not aborted on the first failure backport-to-v4-next labels Mar 13, 2026
@spalladino spalladino mentioned this pull request Mar 13, 2026
@spalladino spalladino enabled auto-merge (squash) March 13, 2026 19:33
@PhilWindle PhilWindle disabled auto-merge March 16, 2026 09:36
@PhilWindle PhilWindle merged commit 4d53720 into merge-train/spartan Mar 16, 2026
43 of 47 checks passed
@PhilWindle PhilWindle deleted the palla/sync-immediate-block-hash-verification branch March 16, 2026 09:36
AztecBot pushed a commit that referenced this pull request Mar 16, 2026
## Motivation

`syncImmediate` syncs world state to a target block number but does not
verify block identity. If a reorg occurred and the world state is at the
same height but on a different fork, the method returns early without
detecting the mismatch. Additionally, `skipThrowIfTargetNotReached` was
dead code with no caller ever passing `true`.

## Approach

Added an optional typed `BlockHash` parameter to `syncImmediate`. When
at or past the target height, the implementation checks the hash via
`getL2BlockHash` before returning early. On mismatch it falls through to
trigger a resync. After syncing, if the hash still doesn't match, it
throws a `WorldStateSynchronizerError` with reason
`block_hash_mismatch`. Removed the unused `skipThrowIfTargetNotReached`
parameter entirely.

## Changes

- **stdlib**: Updated `WorldStateSynchronizer` interface signature —
replaced `skipThrowIfTargetNotReached?: boolean` with `blockHash?:
BlockHash`
- **world-state**: Implemented block hash verification in
`ServerWorldStateSynchronizer.syncImmediate` with pre-sync and post-sync
checks
- **p2p**: Both tx pool v1 and v2 `FeePayerBalanceEvictionRule` now pass
`BlockHash` from `context.block.hash()` on BLOCK_MINED events
- **prover-node**: Passes last block's header hash when syncing world
state before creating proving jobs
- **txe**: Updated mock synchronizer parameter name and type
- **world-state (tests)**: Added tests for hash match (early return),
hash mismatch (triggers resync), and hash mismatch after sync (throws)
- **p2p (tests)**: Updated mock expectations to verify blockHash is
passed in BLOCK_MINED handlers
@AztecBot
Copy link
Collaborator

✅ Successfully backported to backport-to-v4-next-staging #21453.

github-merge-queue bot pushed a commit that referenced this pull request Mar 16, 2026
BEGIN_COMMIT_OVERRIDE
feat: add ETHEREUM_HTTP_TIMEOUT_MS env var for viem HTTP transport
(#20919)
fix(archiver): filter tagged log queries by block number (#21388)
fix(node): handle slot zero in getL2ToL1Messages (#21386)
feat(sequencer): redistribute checkpoint budget evenly across remaining
blocks (#21378)
fix: fall back to package.json for CLI version detection (#21382)
chore: Removed multiplier config (#21412)
chore: Removed default snapshot url config (#21413)
chore: Read tx filestores from network config (#21416)
fix(node): check world state against requested block hash (#21385)
feat(p2p): use l2 priority fee only for tx priority (#21420)
feat(p2p): reject and evict txs with insufficient max fee per gas
(#21281)
revert "feat(p2p): reject and evict txs with insufficient max fee per
gas (#21281)" (#21432)
chore: Reduce log spam (#21436)
fix(tx): reject txs with invalid setup when unprotecting (#21224)
fix: orchestrator enqueue yield (#21286)
chore(builder): check archive tree next leaf index during block building
(#21457)
fix: scenario deployment (#21428)
chore: add claude skill to read network-logs (#21495)
chore: update claude network-logs skill (#21523)
feat(rpc): add package version to RPC response headers (#21526)
chore(prover): silence "epoch to prove" debug logs (#21527)
chore(sequencer): do not log blob data (#21530)
fix: dependabot alerts (#21531)
docs(p2p): nicer READMEs (#21456)
fix(archiver): guard getL1ToL2Messages against incomplete message sync
(#21494)
fix(sequencer): await syncing proposed block to archiver (#21554)
feat(ethereum): check VK tree root and protocol contracts hash in rollup
compatibility (#21537)
fix: marking peer as dumb on failed responses (#21316)
fix(kv-store): make LMDB clear and drop operations atomic across
sub-databases (#21539)
feat(world-state): add blockHash verification to syncImmediate (#21556)
chore(monitor): print out l2 fees components (#21559)
chore: rm faucet (#21538)
chore: remove old merkle trees (#21577)
feat: Implement commit all and revert all for world state checkpoints
(#21532)
chore: skip flaky browser acir tests in CI (#21596)
fix: Better detection for epoch prune (#21478)
chore: logging (#21604)
fix: Don't update state if we failed to execute sufficient transactions
(#21443)
END_COMMIT_OVERRIDE
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backport-to-v4-next ci-no-fail-fast Sets NO_FAIL_FAST in the CI so the run is not aborted on the first failure

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants