Skip to main content

Crate reth_snap_sync

Crate reth_snap_sync 

Source
Expand description

§reth-snap-sync

snap/2 state synchronization, as specified by EIP-8189.

Instead of executing every block from genesis, a node downloads the state of a recent block from peers and verifies it against that block’s state root. snap/2 keeps that state current with EIP-7928 block access lists (BALs), which record every field each block changes, replacing snap/1’s trie-node healing.

This crate owns the synchronization logic and its progress. Requests and proof checks come from reth-downloaders, and running the sync inside a node is left to node integration.

§How a sync runs

SnapBootstrap drives one sync from start to hand-off:

  1. Pick a pivot. A recent finalized block is preferred, since it cannot be reorged; otherwise the pivot sits 64 blocks behind the head by default, the EIP’s example distance. With no eligible block the sync waits.
  2. Download the state at the pivot. Accounts are fetched in key-order ranges, proved against the pivot’s state root. A range commits only once its contracts’ storage and code are persisted, whether supplied with it or stored beforehand.
  3. Advance the pivot. Peers only keep recent state, so once the pivot lags more than 96 blocks by default the sync re-anchors to a newer block. BALs of the blocks in between carry the state already downloaded forward, applied strictly in block order, and the remaining ranges download at the new root.
  4. Repair what BALs cannot. BALs only overwrite the fields their blocks change, so entries left stale for another reason are scheduled for repair. Once the BALs reach the pivot, each scheduled account and slot is fetched again on its own, proved against the pivot’s root.
  5. Hand off. Once every account is downloaded, the BALs reach the pivot and no repairs remain, the state goes to the merkle stage, which rebuilds the trie. It is accepted only when the root matches the pivot’s header.
use reth_snap_sync::SnapPivotPolicy;

let policy = SnapPivotPolicy::default();
// Without a finalized block, anchor at the EIP's example distance.
assert_eq!(policy.pivot_block(1_000, None), Some(936));
// A recent finalized block is anchored to directly.
assert_eq!(policy.pivot_block(1_000, Some(950)), Some(950));
// Stalled finality falls back to the example distance.
assert_eq!(policy.pivot_block(1_000, Some(500)), Some(936));
// A chain shorter than the head distance has no pivot yet.
assert_eq!(policy.pivot_block(4, None), None);

§Design choices

  • State is written in place. Downloads land directly in the hashed state tables, so there is no staging copy to move afterwards. An attempt record owns that state: every write carries the attempt and pivot it was fetched for, and responses to an older attempt or pivot are refused.
  • Progress commits with its data. Each range, storage chunk or BAL commits in the same transaction as the progress it advances, so a stopped sync resumes from what the database holds.
  • Nothing counts before its dependencies. An account range commits only with storage matching its accounts’ roots and code matching their hashes. Storage too large for one response is kept ahead of its range, tied to the attempt and pivot.
  • BALs never skip a block. A block whose BAL no peer serves holds back every later one, and a BAL only applies on top of its parent.
  • The trie is rebuilt once, at the end. The existing merkle stage builds it from the downloaded state, instead of maintaining one during the download.
  • Starting over is the fallback. An attempt restarts when catch-up falls behind the BALs peers still serve, or when a reorg across its pivot cannot be repaired.

§Reorgs across the pivot

A reorg that orphans the pivot leaves the downloaded state holding the abandoned branch’s changes. The attempt keeps the headers of the last 64 blocks through its pivot, so it can find the last block both branches share and fetch the orphaned blocks’ BALs:

  • Every field and storage slot those BALs changed is scheduled for repair, catch-up rewinds to the shared block, and the attempt re-anchors to a new canonical pivot.
  • Applying the new branch’s BALs drops whatever they overwrite, so only entries changed on the orphaned branch alone stay scheduled.
  • Once catch-up reaches the new pivot, those entries are fetched again on their own, proved against its root, and the hand-off waits until none remain.

Orphaned BALs no peer serves are waited for while the head is within the served-state window (128 blocks) of the ancestor. A reorg reaching further back than the kept headers, orphaned BALs still unserved past that window, or a reorg after the hand-off to the merkle stage starts the attempt over instead.

snap/1 synchronization is not covered: this design keeps the state current with BALs, which only snap/2 serves, rather than with snap/1’s trie-node healing.

Structs§

AccountCoverage
How far the account key space has been downloaded.
AccountRangeDownload
Downloads the account ranges an attempt still needs, one at a time in key order.
BalStateUpdate
Changes one block access list makes to the downloaded state.
BlockAccessListCatchUp
Applies the lists of the canonical blocks after the applied one, one request at a time.
BytecodeDownload
Downloads the code an account range still needs, one request at a time.
CatchUpProgress
How far past the pivot the downloaded state has been carried.
SnapBootstrap
Drives snap synchronization until its downloaded state is ready for the trie rebuild.
SnapGeneration
One attempt at downloading state, anchored to the pivot block it targets.
SnapPivotPolicy
Distance and history bounds that decide where a generation is anchored.
SnapReorg
Where a reorg left an attempt: the last block both branches share and the orphaned blocks after it.
SnapSyncSession
One snap synchronization attempt, from the pivot it targets to the work it owns.
SnapWrite
What a write presents to prove it belongs to the attempt owning the persisted state.
StateRepairs
Accounts and storage slots to fetch again at the pivot, in key order.
StorageChunk
Verified slots of one contract, from the slot they were requested at.
StorageProgress
How far the contracts of the account range being downloaded have their storage persisted.
StorageRangeDownload
Downloads the storage an account range’s contracts still need, and repaired slots again.
VerifiedRange
A verified range with the write it was fetched under.
VerifiedSnapState
Downloaded state whose trie root matched the header of the block it is anchored to.

Enums§

AccountRangeStep
What one request of an AccountRangeDownload produced.
BytecodeStep
What one request of a BytecodeDownload produced.
CatchUpStep
What one request of a BlockAccessListCatchUp produced.
DownloadedAccount
What the downloaded state holds for an account a list changes.
SnapBootstrapOutcome
How a SnapBootstrap run ended.
SnapPhase
The stage a SnapGeneration has reached.
SnapSyncError
Error returned while assembling a snap state generation.
SnapSyncSessionState
What a SnapSyncSession is doing.
StorageRangeStep
What one request of a StorageRangeDownload produced.

Constants§

DEFAULT_BAL_RESPONSE_BYTES
Default soft response limit for block access list requests, as EIP-8189 recommends.
DEFAULT_CATCH_UP_BLOCKS
Default number of blocks asked for per request, chosen so that many average 60M gas lists still fit under DEFAULT_BAL_RESPONSE_BYTES.
DEFAULT_CODE_HASHES
Default number of code hashes asked for per request.
DEFAULT_RANGES_PER_CHECK
Default number of account ranges committed between pivot checks.
DEFAULT_REPAIR_SLOTS
Default number of scheduled slots fetched again per repair batch.
DEFAULT_RESPONSE_BYTES
Default soft response limit for snap requests, matching common peer limits.
DEFAULT_SCAN_CHUNK
Accounts scanned between cancellation checks, bounding how long a cancelled session keeps running.
DEFAULT_STORAGE_ACCOUNTS
Default number of contracts asked for per storage request.
MAX_HASH
Inclusive upper bound covering the full trie keyspace.

Traits§

SnapAccountStore
Persistence for the account ranges an attempt downloads.
SnapAttemptStore
Persistence for the attempt that owns downloaded snap state.
SnapBytecodeStore
Persistence for the code an attempt’s accounts reference.
SnapCatchUpStore
Persistence for the block access lists an attempt applies to its downloaded state.
SnapStateVerifier
Decides whether downloaded state can be trusted as the node’s state.
SnapStorageStore
Persistence for contract storage downloaded ahead of its account range.
SnapSyncContext
What a SnapBootstrap needs to know about the chain and peers it synchronizes from.