Skip to main content
Version: Next

Archive nodes

Starting with Nethermind 2.0, archive functionality is built on the flat database: per-block state changesets captured during ordinary syncing answer historical queries, with no extra database and no special sync mode. Three archive shapes are available, all reached the same two ways - a full sync from genesis, or a snap sync to the tip that captures history from the pivot onwards.

Two independent groups of configuration options compose:

  • FlatDb.History* governs historical state - what answers eth_call, eth_getBalance, and eth_getStorageAt at old blocks.
  • History.* governs historical blocks and receipts - what answers eth_getBlockBy*, eth_getTransactionReceipt, and eth_getLogs. See History pruning.

Archive shapes

  • Full archive answers every historical query at every height, state and receipts, from genesis.
  • Windowed archive answers everything a full archive does, but only for the last FlatDb.HistoryRetentionBlocks blocks. Older queries are refused with a pruned-history error - never answered wrongly from live state. Disk stays bounded: the pruner reclaims continuously as the window rolls.
  • Address-slice archive is a windowed node whose named contracts additionally answer to their full slice depth - state, logs, and transactions - while everything else rolls with the window.

Configuration

Each option is documented in its own section of the configuration reference; this page is the archive-node view of them. The table shows which options make up each shape - follow the links for what every option does.

SettingFull archiveWindowed archiveAddress-slice archiveRole
FlatDb.EnabledtruetruetrueThe flat database itself.
FlatDb.HistoryEnabledtruetruetrueCaptures the per-block state changesets.
FlatDb.HistoryRetentionBlocks0 (default)the window size, in blocksthe window size, in blocksThe state-history window; 0 keeps state history from genesis.
FlatDb.HistorySliceAddressesunsetunsetthe sliced addressesContracts kept queryable beyond the general window.
History.PruningDisabled (default)RollingRollingBlock-and-receipt expiry; see History pruning.
History.RetentionEpochs-the retention window, in epochsthe retention window, in epochsHow much block-and-receipt history the rolling pruner keeps.
LogIndex.EnabledrecommendedrecommendedrecommendedThe index behind fast eth_getLogs.
Receipt.TxLookupLimit0000 keeps the transaction-hash lookup index for every stored height.
Receipt.DeriveFromStateoptional--The receiptless variant; see Receiptless archive.
Sync.AncientBodiesBarrier / Sync.AncientReceiptsBarrier0--A full archive that should serve receipts from genesis must also download them.

Every archive setting is default-off: a node that configures none of them behaves exactly as before.

Important

Setting FlatDb.HistoryRetentionBlocks to a non-zero value selects the windowed row format and requires fresh flat history: enabling it on an existing unwindowed flat-history database is refused, and there is no in-place conversion. Start with a fresh sync.

Important

Do not turn on full state pruning on an archive node, as these are two opposing features. Set Pruning.Mode to None.

Historical queries and the window

Within the window, the node answers historical RPC exactly like a full archive. Below it, queries fail closed rather than answering wrongly:

  • Historical state reads (eth_call, eth_getBalance, eth_getStorageAt) below the window return a pruned-history error instead of resolving against live state.
  • eth_getLogs over a range covering pruned heights returns an error rather than silently returning fewer logs than the range holds.
  • Block and receipt queries below the earliest block the node still serves return a pruned-history error, consistent with the block range the node advertises to its peers.

On an address-slice node, reads below the general window serve only the sliced addresses and fail closed for everything else. Log queries filtered to sliced addresses keep answering below the general boundary, served from the log index at the cost of the matches rather than the size of the range. Answering sliced logs below a previously pruned boundary requires History.Pruning to stay enabled: at startup, the pruner validates from which depth each slice's logs are provably retained, and without it those reads fail closed.

Receiptless archive

Receipt.DeriveFromState trades the receipt store for computation: receipt writes are skipped, and a receipt query re-executes the block over its parent state, serving the result only when it reproduces the block header's receipts root. It requires state history for the queried block, so it pairs with a full archive.

  • Receipts already on disk are still served, and pre-Byzantium receipts and the transaction index are always written.
  • A skipped receipt is retained in memory until history capture durably covers its block, and is persisted if capture permanently stops, so a capture breakdown does not lose receipts.
  • A query that misses the cache costs a full block execution, so a public endpoint should be rate limited; concurrency is bounded by JsonRpc.EthModuleConcurrentInstances.
  • Peers are told no receipts are available.

Notes

  • A slice retention shallower than the general window is refused at startup, because it would delete an address's rows inside the advertised window.
  • The state-history pruner paces itself with FlatDb.HistoryPruneIntervalBlocks and FlatDb.HistoryPrunePassBudgetSeconds. The pass budget must exceed the longest historical query the node serves, since deletes wait for in-flight historical reads.
  • FlatDb.HistoryVerifyEveryBlock (default off) runs a one-shot background proof on unwindowed archives: it rebuilds the state root from history rows at every covered block and compares it against the node's own headers. Memory usage follows state size.