Skip to content

fix(node): fork-aware getWorldState that fails closed on sync errors#24563

Open
spalladino wants to merge 3 commits into
merge-train/spartan-v5from
spl/a-1339-getworldstate-fails-open-on-sync-error-returns-stale-state
Open

fix(node): fork-aware getWorldState that fails closed on sync errors#24563
spalladino wants to merge 3 commits into
merge-train/spartan-v5from
spl/a-1339-getworldstate-fails-open-on-sync-error-returns-stale-state

Conversation

@spalladino

Copy link
Copy Markdown
Contributor

Context

getWorldState backs most node RPC tree/witness queries, and had three related problems:

  • World-state sync failures were swallowed (logged and ignored), so queries were served from whatever state the node had — stale reads with no signal to the caller.
  • For tag and number queries, the target block was resolved after syncing, so an archiver tip advancing mid-request (routine during catch-up) made valid queries fail spuriously with "not yet synced".
  • Resolution pinned only a block height, never a fork: a reorg replacing the block at that height between resolution, sync, and snapshot read was served silently — e.g. a proven query could be answered with a same-height block from a new fork that is not proven.

Approach

  • Every query variant (number, hash, archive, tag) now resolves up front to a concrete (block number, block hash) via the archiver's getBlockData, and the sync is driven to that exact block and hash so the synchronizer barriers on it and detects fork mismatches.
  • A new WorldStateSynchronizer.getVerifiedSnapshot(blockNumber, blockHash) verifies the snapshot's own archive view matches the requested fork before handing it out (block 0 is checked against the initial header hash, since its snapshot predates the genesis archive leaf), closing the remaining window between sync and snapshot read.
  • Sync and fork-verification failures surface as WorldStateSynchronizerError and are retried a few times with the query re-resolved each time, so prunes and fork flips heal onto the current chain instead of failing or serving wrong-fork state. Hash and archive resolution misses stay terminal with a clear reorg error; tag and number misses are treated as transient.
  • proposed/latest queries keep their "latest on the current fork" semantics: plain sync plus the committed db, unverified.

API changes

  • WorldStateSynchronizer gains getVerifiedSnapshot(blockNumber, blockHash), implemented by ServerWorldStateSynchronizer (fork-verified) and TXESynchronizer (passthrough, no reorgs). Other getSnapshot callers are unchanged.
  • Node RPC queries at a block now fail instead of silently returning stale state when world state cannot sync, and the error messages for unknown or unsyncable blocks have changed accordingly.

Fixes A-1339

The txe bundle stubs @aztec/world-state; node_world_state_queries.ts now
imports WorldStateSynchronizerError from it, which broke the esbuild
bundling step.
…ed history

getVerifiedSnapshot classified every unreadable archive leaf as a retryable
WorldStateSynchronizerError, so queries against historically pruned blocks
burned all sync retries and surfaced 'Unable to read block hash' instead of
the established 'Unable to find leaf' error callers match on. Distinguish a
block that predates oldestHistoricalBlock (permanent, terminal plain Error)
from a transient fork flip (retryable).
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.

1 participant