github NethermindEth/nethermind 2.0.0-rc
v2.0.0-rc

pre-release5 hours ago

Release notes

623 changes since 1.39.3 from 39 contributors.

Nethermind 2.0.0 is a hardened, faster, archive-capable execution client, built for Ethereum, its L2s, and beyond.

New Archive Layout

Running an archive node used to mean a heavyweight, separate database and a lot of disk. Nethermind 2.0.0 puts archive-grade history on the flat state database (#12943), and that changes the trade-offs:

  • No separate archive database, no new protocol. History is built up by ordinary syncing — the same node, the same peers. You don't run a different node type or transfer data between nodes.
  • Header-verifiable. The state root at any retained height can be reconstructed from the flat rows and checked against that block's header. Historical answers are provable, not best-effort.
  • You choose how much history you pay for. Three shapes, one feature:
    • Full archive — retain every historical state.
    • Rolling window (FlatDb.HistoryRetentionBlocks) — answer historical queries for the last N blocks and reclaim older state.
    • Per-address (FlatDb.HistorySliceAddresses=…) — retain deep history only for the contracts you query while keeping the general window small.
  • Correct by design at the edges. Below the retained floor, reads fail closed with an explicit “not retained” response instead of silently answering from live state.
  • A competitive footprint. A full Ethereum mainnet archive is approximately 2.1 TB today, substantially smaller than legacy trie/hash-based archives.

The upshot: teams that previously ran a full archive “just in case” can instead use a bounded window—or retain deep history only for selected contracts—to reduce disk and operational overhead without giving up the historical answers they need.

How much disk to expect now

Measured on live nodes, mainnet at ~block 25.88M (2026-09-01). Numbers grow slowly as the chain grows — treat them as "today's floor," not a fixed ceiling.

Configuration Retained history Execution DB Total node disk Provision
Full mainnet archive Historical state from genesis; historical proofs are served only close to the chain tip ~2.1 TB ~2.3 TB 3 TB
Windowed mainnet archive ~2 months of state and ~1 year of blocks; block pruning measurement pending ~0.9 TB (926 GB; provisional) ~1.0 TB (provisional) 1.5 TB
Per-address mainnet archive Deep history for 6 of the busiest contracts + a 256-block base ~1.8 TB ~1.9 TB 2.5 TB
Full Gnosis archive Historical state from genesis; historical proofs are served only close to the chain tip ~0.94 TB (941 GB) ~0.94 TB 1.5 TB

Current measured saving: retaining ~2 months of state while keeping ~1 year of blocks takes the execution DB from ~2.1 TB → ~0.9 TB — roughly 60% less disk. The figure for a fully pruned ~2-month block window is still being measured.

Per-address disk scales with how active your chosen contracts are — pick lower-traffic contracts and it drops sharply. It's a "keep deep history cheaply" tool.

Rule of thumb for planning:

  • Need full mainnet history → provision 3 TB (2.2 TB DB + CL + room to grow).
  • Only need recent history → the current measurement is ~0.9 TB for ~2 months of state with ~1 year of blocks retained. The fully pruned ~2-month figure is pending; size your window with HistoryRetentionBlocks.
  • Need forever-history for a few specific contracts → budget by those contracts' activity, plus a small base window.

Performance

Flat state at chain tip

A 12-hour Ethereum mainnet measurement across six fully synced, warm nodes found the flat state layout on 2.0.0-rc to be the fastest configuration at chain tip on both hardware tiers. Against the same-tier 1.39.2 half-path baseline, flat processed blocks at 1.80× the throughput on 8 vCPU standard machines and 2.55× on 16 vCPU premium machines.

The comparison used three configurations—2.0.0-rc flat, 2.0.0-rc half-path, and 1.39.2 half-path—on each hardware tier, all over the same 12-hour window. Each node contributed 2,880 samples and processed 3,587–3,588 blocks, with zero bad blocks, zero sample gaps, and zero restarts. RAM, storage, region, and OS image were identical; core count was the only hardware difference between tiers.

Mean block processing time at chain tip

Mean block processing time at chain tip

The largest improvement is in tail latency, not the typical block. Flat's p99 was 351 ms on standard and 208 ms on premium—only 4.3× and 4.2× its own median. The 1.39.2 baseline reached 1,849 ms and 1,646 ms at p99, or 21× and 24× its median. 2.0.0-rc half-path also substantially reduced the tail, showing that part of the gain comes from 2.0.0-rc generally and part from the flat layout.

Median, p90, and p99 block processing time

Median, p90, and p99 block processing time

Flat also benefited most from additional cores: mean processing time improved from 96.5 ms on 8 vCPU to 57.6 ms on 16 vCPU, a 1.67× improvement. The equivalent gain was 1.13× for 2.0.0-rc half-path and 1.18× for 1.39.2 half-path.

The trade-off is initial sync time. Flat took 192.0 minutes on standard and 128.6 minutes on premium—about 75% longer than the same-tier 1.39.2 half-path baseline. Once synced, it delivered the best and most consistent chain-tip performance measured here; 2.0.0-rc half-path was the fastest configuration to reach tip.

Time to sync to chain tip

Time to sync to chain tip

Faster eth_call under load

Across the completed benchmark cells, 2.0.0-rc answers the internal 497-record eth_call corpus 15–27% faster than 1.39.3, with byte-identical responses on all 497 records in every layout and architecture measured. It also sustains 22–25% more heavy high-gas multicalls per second.

Both versions ran against the same mainnet snapshot at block 25,490,000, using the same seeded request sequences and runner, interleaved over overlay mounts on pristine snapshots. Figures come from the run-rpc-benchmarks workflow. These measurements preserve the tested build label, 2.0.0-rc.

Latency on the 497-record corpus

The corpus represents heavy simulation traffic: every record carries state overrides, and the median request is about 331 KiB. Each arm replayed 20,000 seeded requests at 100 requests per second after a discarded 60-second warm-up.

eth_call latency percentiles, 1.39.3 vs 2.0.0-rc

eth_call latency percentiles, 1.39.3 vs 2.0.0-rc

The gain widens into the tail on the flat layout: amd64 p99 drops 29.5%, from 104.79 ms to 73.92 ms. This reflects real work saved rather than scheduling luck—CPU time per request falls 25.5% on amd64 flat and 17.7% on arm64 flat. Paired per-record medians agree with the aggregate: −20.1% on amd64 (95% CI −20.6% to −19.6%; 451 of 497 records faster) and −25.2% on arm64 (95% CI −25.7% to −24.3%; 476 faster).

Throughput

Closed-loop throughput was measured over 40 passes across all 497 records at concurrency 16. Compared with 1.39.3, 2.0.0-rc delivered 29.6% more throughput on amd64 flat, 36.4% more on arm64 flat, and 20.6% more on amd64 halfpath.

Closed-loop eth_call throughput, 1.39.3 vs 2.0.0-rc

Closed-loop eth_call throughput, 1.39.3 vs 2.0.0-rc

Heavy high-gas multicalls

Three EthCallChaos high-gas Multicall3 aggregate3 scenarios—roughly 34 KB payloads carrying about 500 ms of EVM work each—ran in isolation at 100 and 300 requests-per-second targets, in ABBA order, with 512 virtual users. Both versions saturated at both target rates, so achieved throughput is the relevant measure; p99 values in the 19–37 second range represent queue depth, not call latency.

Heavy high-gas Multicall3 capacity, 1.39.3 vs 2.0.0-rc

Heavy high-gas Multicall3 capacity, 1.39.3 vs 2.0.0-rc

Repeats within a version varied by about 1 request per second, against a between-version gap of about 5 requests per second on flat and 3.5 on halfpath. Every multicall cell completed with zero failed requests, while the accompanying light eth_call contract mix remained sub-millisecond on both versions.

Results summary

Cell Architecture Layout Mean latency Paired median Throughput Response parity
497-record corpus amd64 flat −27.3% −20.1% +29.6% 497/497
497-record corpus arm64 flat −23.6% −25.2% +36.4% 497/497
497-record corpus amd64 halfpath −15.5% −16.3% +20.6% 497/497
Heavy multicall amd64 flat Saturated +22–25%
Heavy multicall amd64 halfpath Saturated +23%

Other optimizations

  • Keccak-256 ~30% faster via AVX-512VL and batched hashing. (#12844)
  • Single-call RocksDB point reads remove a value-sized native allocation and copy on every read. (#12986)
  • EVM stops redundantly zeroing memory on overwrites and fresh allocations — large wins on memory-heavy execution. (#12953)
  • eth_call state overrides applied without merkleization. (#12904)
  • ARM64-specific: EVM byte-swap fast path (eth_call latency and block-processing improvements) and a per-thread EVM call-pool free list. (#12798, #12905)
  • Plus hot-path loop/atomics cleanups. (#13000, #12998, #12870, #12905)

Highlights

  • Flat-history archive (#12943). The flat state database can now serve archive-grade, header-verifiable history in three shapes, all built from ordinary syncing — no separate archive database, no new P2P protocol:

    • Full archive — reconstruct and verify state at any historical block.
    • Rolling window (FlatDb.HistoryRetentionBlocks) — answer historical queries for the last N blocks and reclaim the rest.
    • Per-address (FlatDb.HistorySliceAddresses) — keep deep history only for the contracts you care about while the general window rolls.

    Below the retained floor, reads fail closed (correct-by-design) rather than silently answering from live state.

  • Streaming snapshot download (#12862). Import an archive snapshot without first storing the full archive locally, lowering peak disk during bring-up. Provision free disk equal to at least 1.5× the snapshot size; the import fails if less space is available.

  • Standalone bootnode tool (#12601). A dedicated discv4/discv5 bootnode with REST APIs, Prometheus metrics, and Docker/Grafana assets.

  • EIP-7805 (FOCIL) inclusion lists (#8003) and a sparse blob pool with eth/72 cell-level exchange + engine_getBlobsV4 (#11094). Both are implemented and fork-gated (activate with their respective forks).

⚠️ Breaking changes

If you run a node (config)

  • Db.FlushOnExit is now an enum, not a boolean. Values: None, WalOnly, Full. The default changes from full-flush to WalOnly. If your config, env var, or CLI still sets true/false, the node fails to start — change trueFull, falseNone.
  • Blocks.PreWarmStateOnBlockProcessing was replaced by Blocks.PreWarming. New enum values: None, Block, BlockAndMempool (default BlockAndMempool). The old key is now silently ignored (you'll get a warning, not a crash) — rename it or you lose your setting.
  • Numeric config keys are now unsigned. Negative values are rejected and the node fails to start. The one common case: Receipt.TxLookupLimit: -1 (the old "never index" sentinel) must become 18446744073709551615.
  • Receipt.MaxBlockDepth default lowered from 10000 → 1000. A single eth_getLogs spanning more than 1000 blocks is now rejected unless the log index is enabled. If you rely on wide ranges: raise Receipt.MaxBlockDepth, split the query, or enable the log index.
  • sepolia and hoodi default configs are now discv5-only (hoodi's static bootnode list was removed). Stock-config nodes on those networks discover peers via discv5 + DNS. Custom DiscoveryConfig is unaffected.
  • Mainnet ancient-history barrier raised (block 15537394 → 24600000). Existing nodes keep all their data. Only new or resyncing nodes retain less pre-24.6M history by default.

If you run an archive node

  • Archive configs now enable the flat-database backend with history (see Flat-history archive below). Your existing patricia archive DB keeps working (the new flag is ignored on an existing DB — nothing corrupts). To actually run the new flat archive you must resync, or set FlatDb.ImportFromPruningTrieState=true for an in-place trie→flat import. Enabling flat history is forward-only — there is no backfill below the point you enable it.

If you integrate over JSON-RPC / Engine API

  • engine_newPayloadV5: a malformed block-access-list envelope now returns {"status":"INVALID", ...} (HTTP 200) instead of JSON-RPC error 32602. (#13012)
  • trace_simulateV1: the response field stateChanges was renamed to stateDiff. (#12892)
  • Receipt JSON on the t8n / direct-serialization path now emits root or status (mutually exclusive), not both. The standard eth_getTransactionReceipt path is unchanged. (#12867)
  • debug_traceCall now uses a base fee of 0 for unpriced calls, matching go-ethereum. Reported gas figures change accordingly. (#12804)
  • eth_getStorageAt position parsing is stricter — spec-compliant hex-quantity clients are fine, but a client sending a bare number or un-prefixed string may now get a parse error. (Verify against your integrations.)
  • Amsterdam-gated (not active on mainnet yet, relevant if you test against devnets): eth_call now returns errors (out-of-gas, address collision, EF-prefix) where it previously returned 0x; eth_estimateGas and eth_createAccessList return updated values. (#12806, #12971, #12970)

If you build against Nethermind (plugin / library authors)

  • Many IConfig numeric properties changed from long/int to ulong. This is source-breaking — recompile your plugins against 2.0.0.

Consensus / protocol

  • EIP-7610 support removed. (#12935) No change on any live network — the storage-collision check is superseded by EIP-684 and was never activated as a fork. Only affects state-test / collision fixtures.
  • Stricter RLPx/Snappy frame validation. (#12896) Malformed frames are now rejected/disconnected. Conformant peers (Geth, Besu, older Nethermind, CL relays) are unaffected — this is DoS hardening.
  • Optimism engine_signalSuperchainV1 V0 byte layout corrected (7→8 bytes) to match op-geth/op-node. (#12805) OP-Stack operators only.

Dropped

  • ethernity-sepolia network removed (ethernity-mainnet is retained).

Networking & protocol

  • ENR bootnodes accepted in discv4. (#12992)
  • Conservative block-body transaction count limit; inbound RLP byte-list caps. (#12990, #12914)
  • eth/72 announced cell-mask fix; local backpressure no longer charged to peers. (#13007)
  • Restored eth/68 blob-violation handling; IPv6 enode text endpoints. (#12605, #12678)
  • Fixed a peer-update timer shutdown race. (#13010)

Sync, database & state

  • Fixed false header < body block-tree corruption after an ungraceful restart during beacon sync. (#12876)
  • Flat warmer correctness: isolate warmer misses and safely publish verified reads (resolves InvalidStateRoot waves); restore the trie-warmer negative cache without poisoning live reads. (#12951, #12877)
  • A malformed snap AccountRange no longer strands a sync partition. (#12979)
  • Auto-update fast-sync settings. (#12962)

JSON-RPC & Engine API (non-breaking fixes)

  • Browser POSTs are routed past the trusted fast lane so CORS headers are emitted. (#12900)
  • Fixed a flaky eth_simulateV1 parent when a block-body write is pending. (#12984)
  • Documentation-generation fixes for RPC response schemas. (#12892, #12869, #12866)

Consensus correctness (state-affecting fixes)

  • Preserve the RIPEMD touch across nested reverts (go-ethereum parity). (#13016)
  • Reject deposit logs with non-canonical ABI offsets (stricter EIP-6110 validation; honest blocks unaffected). (#12895)
  • Detect Geth genesis format independent of property order. (#12784)

L2 & other chains

  • Optimism: OP Superchain chain registry refreshed (~40 chainspecs); OP payload decoding hardened against a malicious offset table; protocol-version signaling fix. (#12963, #12920, #12805)
  • XDC: epoch resolution below the fast-sync pivot, archive start at the XDPoS v2 switch, blacklisted-address pool rejection, rewards read as XDC amounts, and several reliability fixes. (#12974, #12917, #12879, #12852, #12872, #12878)

Upgrade checklist

  1. Stop the node. No resync needed for a normal full node.
  2. Audit your config for the breaking keys above — the ones that crash on start are Db.FlushOnExit (bool→enum), any negative numeric value, and Receipt.TxLookupLimit: -1.
  3. Rename Blocks.PreWarmStateOnBlockProcessingBlocks.PreWarming (otherwise it's silently ignored).
  4. eth_getLogs users: check whether Receipt.MaxBlockDepth (now 1000) affects your queries.
  5. Archive operators: decide between keeping your existing patricia archive (works as-is) or resyncing/importing to the new flat archive with history.
  6. Plugin/library authors: recompile against 2.0.0 (IConfig numeric types changed).
  7. Start the node and confirm the version in the startup logs.

Build signatures

The packages are signed with the following OpenPGP key: AD12 7976 5093 C675 9CD8 A400 24A7 7461 6F1E 617E

What's Changed

New Contributors

Full Changelog: 1.39.3...2.0.0-rc

Don't miss a new nethermind release

NewReleases is sending notifications on new releases.