github NethermindEth/nethermind 2.1.0
v2.1.0

3 hours ago

Release notes

359 merged pull requests since 2.0.0, from 29 contributors.

Upgrade every Sepolia node to 2.1.0 before the Glamsterdam fork on Tue, 06 Oct 2026, 13:53:36 UTC.

For most nodes this is an in-place upgrade with no resync. Read Breaking changes first if you run on the flat backend with a custom sync config, run poacore, run a Flashbots relay, parse Parity-style traces, or build plugins against Nethermind. **

Highlights

  • Glamsterdam on Sepolia. Final EIP-8037 state-gas rules, the TX_MAX_TOTAL_GAS_LIMIT transaction cap, and Engine API alignment for Amsterdam. (#13140, #13484, #13627, #13554, #13583, #13586, #13755)
  • Faster EVM. The interpreter loop is replaced by tail-call chain dispatch, stack words stay in UInt256 limb layout, storage values stay as UInt256 until they are persisted, and JUMPDEST analysis is rewritten. (#13128, #13323, #13420, #13189, #13810)
  • Lower engine_newPayload latency. The response goes out as soon as the block has executed and its roots match, before the commit. engine_forkchoiceUpdated still waits for that head's commit. GC pauses no longer stall payloads the way they did. (#13647, #13711, #13476, #13334)
  • Per-transaction changeset index for flat archives (opt-in). A single-transaction trace starts at its target transaction instead of replaying the whole block before it: debug_traceTransaction went from ~7.1 s to ~28 ms in the PR's measurements. Whole-block traces run their transactions in parallel (6–10× faster). Enable with FlatDb.HistoryTransactionIndexEnabled=true. (#13454, #13426)
  • BAL healing after snap sync (flat backend). On the flat backend, the state left by snap sync is healed by replaying block access lists instead of downloading trie nodes. It is on by default (Sync.BalHealing=true); set it to false to go back to trie-node healing. snap/2 is advertised only when BAL healing can run. (#12945)
  • Dual-stack IPv4/IPv6 networking. RLPx, discv4 and discv5 listen on both families, ENRs advertise both, and there is a new Network.ExternalIpV6 override. (#12679, #12982, #12983, #13731)
  • Flat backend safety rails. A flat DB that RocksDB had to auto-repair is now re-synced instead of trusted. Unsafe flat activations are refused at start instead of silently corrupting or discarding state. (#13645, #13644)
  • Reclaim the patricia trie after a trie→flat conversion. FlatDb.DropPruningTrieState=true deletes the old trie store on the next start once the flat DB owns the state (~227 GB on mainnet). Off by default. (#13572)
  • RocksDB 11 through Nethermind's own bindings. The RocksDB package is replaced with Nethermind.RocksDbBindings (RocksDB v10 → v11): source-generated P/Invoke with no marshalling stubs, and every native handle held in a SafeHandle. (#12853)
  • New EF bootnodes. The EF bootnode entries for mainnet, Sepolia and Hoodi are replaced with the new NodeOps fleet: five dual-stack nodes running both discv4 and discv5. (#13313)
  • More zkVM targets. Stateless guests for SP1 and OpenVM ship alongside ZisK, and the ZisK toolchain moves to 1.3.0-alpha. (#13435, #13769, #13743)

Performance

  • EVM dispatch and call frames: 3.8–4.5% faster block processing on the superblocks, realblocks and fusaka benchmark sets. (#13189)
  • Storage values held as UInt256: SLOAD 9–18%, SSTORE 42% and TSTORE ~50% faster, with no allocations on those paths. (#13420)
  • EVM stack in limb layout: 45–53% faster ADD, 16–36% faster SUB, and 9–18% faster shifts. (#13323)
  • JUMPDEST analysis: worst-case analysis of 64 KiB initcode (a 200 MGas block of PUSH1/JUMPDEST patterns) drops from 0.4–3.2 s to 22–153 ms, depending on the SIMD tier. Initcode is analysed on first use. (#13810)
  • Trie and storage-key hashing: 35–80% less time on transaction and receipt-root workloads. (#13552)
  • Prewarming: a single fan-out while senders arrive gives superblocks processing a median −4.4%, P99 −27.9%, and +7.6% MGas/s. Prewarming and trie concurrency caps are removed, and parallel work is budgeted across the state root, blooms, the receipts root and prewarming (2–4% faster processing). (#13640, #13388, #13770)
  • Carried caches: pre-block account and storage caches are carried across blocks. (#13100)
  • Discovery traffic: on a warm-started Hoodi node, discovery traffic fell by 90% (152 KiB/s → 15 KiB/s), and the standalone bootnode uses ~44% less working set. (#13122)
  • Snap sync: downloads are bounded and overlap with response processing. Whale-storage verification in FlatTrieVerifier is parallelised. (#12623, #12615)
  • RPC: eth_call, eth_estimateGas and eth_createAccessList no longer hash the transaction on every run (~0.2 ms on large calldata) (#13804). the stream interpreter is off by default because it lost on every measured eth_call shape. eth_getFilterChanges is served from shared block logs. (#12999, #13742)
  • Intel hybrid CPUs: block processing is pinned to the performance cores by default (Blocks.ProcessingCores). Nothing changes on other CPUs. (#13717)

⚠️ Breaking changes

If you run a node (config and startup)

  • poacore / poacore_validator now ship FlatDb.Enabled=false because they use FastSync without SnapSync (#13644). A node on those configs that synced on 2.0.0 is on the flat backend, since flat is 2.0.0's default. On 2.1.0 it refuses to start (Refusing --FlatDb.Enabled=false on an existing flat DB). Either pass -FlatDb.Enabled=true, or delete the flat, flatHistory and persistedSnapshot directories and resync the state.
  • -FlatDb.Enabled=false on an existing flat DB is refused. In 2.0.0 the node silently discarded the state and resynced (#13428). It now stops with an error. (#13644)
  • Flat + Sync.FastSync=true + Sync.SnapSync=false is refused on a fresh node. Legacy tree sync on the flat backend can leave holes in the state. An already-synced node keeps running and logs a warning. The exception is importing from patricia (FlatDb.ImportFromPruningTrieState=true on a datadir that holds patricia state). (#13644)
  • New FlatDb.OnRepair setting, default Resync. If RocksDB auto-repairs the flat DB, the node now wipes the flat state and runs state sync again. Headers, bodies and receipts are kept. Archive nodes synced from genesis cannot snap-resync. Set FlatDb.OnRepair=Ignore and plan a resync yourself if a repair is ever reported. (#13645)
  • Receipt.MaxBlockDepth default raised back from 1,000 to 10,000, and the limit is now also enforced on eth_getFilterLogs. On nodes with the log index, only blocks the index cannot serve count towards the limit. A filter created by eth_newFilter over a wider range is still accepted, but eth_getFilterLogs on it fails with 32602. (#13131)
  • Removed config keys: FlatDb.EnablePreimageRecording, Db.PreimageDbRocksDbOptions, Db.PreimageDbAdditionalRocksDbOptions (#13690), LogIndex.VerifyRpcResponse (#13131), and Grpc.Enabled, Grpc.Host, Grpc.Port along with the gRPC endpoint (#13330). A JSON config that still sets them logs Invalid configuration settings at startup. Remove them from configs, environment variables and command-line flags.
  • Merge.CompactMemory default changed from Yes to No. This removes GC compaction stalls from engine_newPayload. Steady-state RSS may be somewhat higher. (#13476)
  • Init.LogRules no longer routes to Seq, and Seq.MinLevel is now the floor for the Seq target. To send a namespace's Trace output to Seq, add an explicit writeTo="seq" rule in NLog.config. (#13419)
  • Dual-stack by default. With Network.LocalIp unset, the P2P TCP and discovery UDP listeners now try to bind [::] on Linux and Windows, so the P2P port may now be reachable over IPv6. Check your firewall. macOS stays IPv4-only. Set Network.LocalIp=0.0.0.0 to keep IPv4-only. (#12982)
  • Pruning.FullPruningTrigger=VolumeFreeSpace with a threshold too low to ever trigger now logs a startup warning. Automatic pruning was already not running in that case, so nothing new is broken. (#13485)

If you run a Flashbots relay

  • Flashbots.EnableValidation now defaults to true. flashbots_validateBuilderSubmissionV3 checks the submitted block's state root, receipts root, gas used and logs bloom against its execution. Set it to false explicitly to get the old behaviour. (#13452)

If you integrate over JSON-RPC / Engine API

  • eth_getHeaderByNumber("pending") returns null, matching go-ethereum and execution-apis#877. (#13082)
  • proof_getTransactionByHash / proof_getTransactionReceipt return result: null for a transaction they cannot serve, instead of a 32000 error. proof_getTransactionReceipt returns 32002 when the block can no longer be retraced. (#13366)
  • Parity vmTrace stack pushes are hex quantities (0x0, 0x1), not byte strings. Word operations now report their pushes. (#13750, #13487)
  • Other trace output changes. Empty trace selections are accepted. trace_get keeps lookup errors instead of replacing them. trace_filter returns an error when the requested history is unavailable, and buffered trace_filter now applies a single JsonRpc.Timeout to the whole request. Deleted-account fields carry deletion markers. callTracer omits to on a failed top-level CREATE. (#13667, #13676, #13677, #13668, #13078)
  • EIP-3155 / structLogs traces are corrected: gasUsed is the top-level execution-gas delta, refunds are cumulative, and opcode names follow Geth (0x44 is reported as DIFFICULTY). (#12981)
  • eth_estimateGas runs entirely against the requested block, the way eth_call does, with a single deterministic search. Before, the first run used a synthetic next-block header. Estimates can differ from 2.0.0 within the error margin. Invalid-opcode and stack failures now return the standard error texts (for example invalid opcode: INVALID, stack underflow (0 <=> 2)), and eth_call uses the same texts. (#13899)
  • eth_call with maxPriorityFeePerGas above maxFeePerGas (after London) fails before any gas is bought, with the same max priority fee per gas higher than max fee per gas error execution returns. eth_createAccessList fills the fee cap as the priority fee plus twice the base fee when only a priority fee is given. (#13904)
  • Call requests with gasPrice and a type-specific field (accessList, blobVersionedHashes, authorizationList) but no explicit type are no longer decoded as legacy transactions. eth_call, eth_estimateGas, eth_createAccessList and eth_simulateV1 results change for those requests. (#13450)
  • eth_subscribe("logs") delivers logs for every block that becomes canonical, and removed: true logs for every block that leaves the canonical chain. A subscriber that falls more than 1,000 blocks behind (or 10,000 events for pending-transaction and peer subscriptions) is disconnected. (#13451)
  • No state for a block now returns 32002 from every method, and guard-rail rejections (32002, 32005, 4444) are no longer logged at WARN. (#13643)
  • The SSZ-REST Engine API moves from /engine/v2/... to /engine/v1/..., per execution-apis#793. The JSON-RPC engine_* surface is unchanged. (#13023)
  • engine_newPayload rejects a post-Shanghai payload with a null withdrawals list (MissingWithdrawals). (#13501)
  • /data/events accepts ?events=. A client that only needs processing statistics should pass ?events=processed. (#13334)

If you build against Nethermind (plugin / library authors)

These are source-breaking changes: rebuild your plugins against 2.1.0.

  • IBackgroundTaskScheduler.TryScheduleTask now takes a request type that implements IBackgroundTaskRequest<TReq>, and the source string is gone. (#9956)
  • ISyncPeerPool.Free is removed. SyncPeerAllocation is now IDisposable, so dispose it with using. (#13094)
  • World-state scopes are opened with TryBeginScope / TryBeginScopeAtTarget, which return false for an unavailable base instead of throwing. (#13522)
  • Storage APIs take UInt256 values instead of byte arrays. SlotValue is removed. (#13420)
  • EVM extension API: the gas-policy methods are TryConsume*, the OutOfGas flag is removed, and the EvmStack constructors require a CodeInfo. (#13189)
  • ProcessingOptions.Trace is removed. Use TraceProcessingOptions.ReadOnlyReplay. (#13443)
  • Value-hash and protocol API changes in the txpool and networking code. (#13592)
  • Nullable reference types are enabled in EVM, Trie, State and 7 foundation projects. (#13099, #12155)

Consensus / protocol

  • Glamsterdam (Amsterdam-gated, Sepolia from 10-06): the EIP-8037 spill is repaid after a child frame merges, and a restored spill is burnt on a top-level halt (#13140, #13484). TX_MAX_TOTAL_GAS_LIMIT (2³² − 1) is enforced in the pool, in block validation and in eth_estimateGas (#13627). The unknown-original storage flag is kept across repeated writes (#13554). The EL no longer enforces slot ordering on engine_forkchoiceUpdatedV4 (#13583). Orphaned headers are checked for a slot number (#13586). engine_getPayloadV5 is rejected from Amsterdam on (#13755).
    EIP-7928 receipt event metadata is corrected (#13509), and AuRa keeps existing accounts in BAL preprocessing (#13047).
  • XDC: randomize-contract transactions now pay and burn gas (#13359), and sign-transaction receipts are encoded as legacy in the receipts trie. The receipts change fixes a consensus divergence on typed transactions (#13375).

Sync, database & state

  • Recovery of missing contract code. (#9417)
  • A fast-sync body could be dropped by the block cache, which left the receipts stage stuck. Fixed. Nodes already stuck on this need a bodies resync. (#13474)
  • Flat persistence keeps going when the committed state is off the canonical chain. MinReorgDepth stays reachable after folding to the finalized boundary. Flat state is retained across Engine-X reorgs. (#13591, #13550, #13402)
  • A gather whose state was just persisted is retried instead of refused (fixes an occasional 32002 No state available at the block being folded). (#13763)
  • VerifyWithTrie no longer reports a false positive when an account is deleted that the trie still holds. (#13521)
  • debug_resetHead prunes flat snapshots that are unreachable from the new head. (#13524)
  • New FlatDb.EnableCarryForwardCache (default true) to turn off the cross-head read cache. (#13752)
  • The history-walk ETA overflow no longer kills progress or discards a finished archive-proof walk (this bug is present in 2.0.0). The walk also reports the replay block of a storage range. (#13761, #13791, #13604, #13754, #13620)
  • SyncServer range-broadcast serialised. Pooled lists from trie path recovery are disposed. (#12728, #13266)
  • ElapsedMicroseconds overflow on long-running stopwatches fixed. (#13416)
  • The history pruner is created before the block processor starts. (#13285)
  • When a block wipes a contract's storage, the pre-block storage cache now invalidates only that contract. Before, it dropped the whole cache and logged an Info line each time, which on pre-Cancun history meant tens of thousands of lines an hour during a full sync from genesis. (#13850)
  • The disk-space probe is skipped when the availability check is disabled. (#13456)
  • Code from a reverted CREATE no longer reaches the code DB, and code-write counters roll back with it. (#13074, #13432, #13433)

JSON-RPC & tracing

  • Malformed JSON-RPC batch items no longer abort the rest of the batch. (#12537)
  • eth_syncing reports the beacon tip as the highest block. (#12739)
  • debug_traceTransactionByBlockAndIndex resolves block tags and hashes. (#13138)
  • eth_feeHistory reward percentiles use post-refund receipt gas. (#13563)
  • eth_sendRawTransactionSync no longer misses a receipt included in the next block. (#13736)
  • Simulation cache is reset when the real chain advances. (#13444)
  • Single-transaction traces no longer replay the transactions after the target. (#13426)
  • Discarded block traces in debug_traceTransactionInBlockByIndex are disposed. (#13324)
  • EIP-7708 finalization logs are reported to tracers, and the previous transient value shows up in TSTORE traces. (#13567, #13504)
  • Account-creation results are preserved in traced and BAL-backed execution. (#13574)
  • eth_simulateV1 child headers and payload attributes inherit the parent slot number (for Amsterdam SLOTNUM). (#13584, #13585)

Engine API & block processing

  • engine_forkchoiceUpdated waits for the head's own commit, including when blocks are queued behind it, a second copy of the head is queued, or the commit is slow. (#13711)
  • Fixed a missed drain of the block processing queue. (#13749)
  • Null required Cancun payload fields are rejected. (#13747)
  • Custody columns are applied on forkchoiceUpdatedV5. (#13109)
  • FOCIL: engine_getInclusionListV1 accepts the parent block hash. (#13097)
  • The block processor split (main-only BlockchainProcessor, separate OneTimeChainProcessor), with a follow-up fix for transaction-index replay. (#13449, #13629)
  • Blocks are processed while sender recovery finishes. (#13597)

Networking & protocol

  • A Hello whose node ID differs from the authenticated peer is rejected. (#13348)
  • Outgoing receipts are capped under the devp2p message size limit. Trie-node and receipts requests have bounded lookups. The receipt log limit is derived from the block gas ceiling. (#13595, #13596, #13288)
  • Connect workers no longer dial past MaxActivePeers. (#13302)
  • Discovery event loop shutdown is bounded. (#13617)
  • Startup external-IP resolution retries before it gives up. Persisted peers keep the endpoint that was actually dialled. (#13731)

Stability & hardening

  • A malformed EthStats ping no longer terminates the node. (#13353)
  • BN254 Add/Mul input length is checked in release builds. (#13208)
  • Keccak output sizes the sponge cannot serve are rejected. (#13187)
  • A stateless rejection no longer terminates DEBUG-enabled hosts. Execution requests are recovered correctly in stateless RPC inputs. (#13535, #13346)
  • The Docker images carry Nethermind's OCI labels (source, revision, version) instead of Ubuntu's. (#13694)

L2 & other chains

  • XDC: nine XDC-specific eth_* methods are added (block signers and finality, candidates, staking ROI, token stats) (#12950). XDPoS header fields are returned over JSON-RPC and newHeads, and AuRa's step and signature are restored on newHeads (#13055). eth_getAccountInfo returns the XDC shape (#13228). Transactions under the minimum gas price are rejected at pool admission (#13222). eth_gasPrice is floored at the pool minimum (#13633). SyncInfo QC and TC are verified independently (#13296). Unsupported eth versions are no longer advertised (#13018). State sync starts without waiting for headers back to genesis (#13609).
  • Optimism: after Jovian, payload attributes from op-node (8-byte eip1559Params plus a separate minBaseFee) are accepted. Before, every engine_forkchoiceUpdatedV3 with attributes failed with 38003, which broke block building behind op-node (#13813). Blocks Nethermind builds after Isthmus now keep the L2ToL1MessagePasser storage root as withdrawalsRoot instead of the empty-list root, which op-geth and Nethermind itself reject (#13814). OP Superchain chain registry refreshed (#13043, #13179, #13430, #13606).
  • Taiko: Taiko mainnet (Alethia) uses the 0.01 gwei Shasta base-fee floor that taiko-geth and alethia-reth enforce. Before, Nethermind rejected current Alethia blocks with Invalid baseFee (#13812). Unzen zk-gas metering for failed steps matches REVM, so canonical blocks that end a step out of gas are no longer rejected (#13824).
  • Plataberget: new archive config, -config plataberget_archive. (#13073)

Glamsterdam fork on Sepolia

Network Epoch Start slot Unix UTC
Sepolia 353024 11296768 1791294816 Tue, 06 Oct 2026, 13:53:36 UTC

Your consensus client must support Glamsterdam as well. Check your CL's release notes for a Sepolia Glamsterdam release before the fork. Hoodi and mainnet dates are still TBD.

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: 2.0.0...2.1.0

Don't miss a new nethermind release

NewReleases is sending notifications on new releases.