Skip to content

Bal devnet 6#11436

Merged
benaadams merged 124 commits into
masterfrom
bal-devnet-6
May 8, 2026
Merged

Bal devnet 6#11436
benaadams merged 124 commits into
masterfrom
bal-devnet-6

Conversation

@benaadams
Copy link
Copy Markdown
Member

@benaadams benaadams commented Apr 30, 2026

Brings Nethermind in line with the BAL devnet-6 spec: Block Access Lists (EIP-7928), EIP-8037 two-dimensional gas metering (with halt vs revert child-frame restoration split), and the additional Amsterdam EIPs.

Syncs bal-devnet-6 at 5Ggas/s - 10Ggas/s

image

Changes

Protocol

  • EIP-7928 (BAL)

    • Widen BlockAccessIndex and indexed-change types (BalanceChange, NonceChange, CodeChange, StorageChange) to the spec uint32.
    • Replace the legacy -1 "prestate" sentinel with Eip7928Constants.PrestateIndex = uint.MaxValue and a dedicated PrestateAwareIndexComparer so prestate entries grafted by LoadPreStateToSuggestedBlockAccessList keep iteration order.
    • Tighten RLP encoding/decoding in AccountChangesDecoder, SlotChangesDecoder, and BlockAccessListDecoder (reject empty storage_changes, reject empty AccountChanges, remap IndexOutOfRangeException/ArgumentOutOfRangeException to RlpException, dispose pooled lists on every decode failure).
    • New ValidateBlockLevelAccessListIndexBounds enforces the per-EIP-7928 [0, txCount + 1] index range; ValidateBlockLevelAccessListSize enforces the block_gas_limit / ItemCost cap.
    • BlockAccessList.Merge / mutators now correctly invalidate the cached _itemCount. (Align EIP-7928 BlockAccessIndex with uint32 spec, add validation #11362)
    • AccountChanges.GetNonce / GetBalance switched from linear scan to binary search; GetCode / GetCodeHash hardened with explicit prestate-loaded invariant guards.
  • EIP-8037 (2D gas)

    • Static cost_per_state_byte = 1174 retained from devnet-3; the value is now threaded through EthereumGasPolicy rather than inlined as a constant. Every state-gas computation goes through GasCostOf.Calculate* helpers (SSetState, CreateState, NewAccountState, CodeDepositState, PerAuthBaseState, PerEmptyAccountState, SSetReversalRefund); matching helper added to RefundOf.
    • The parameter is propagated through EvmInstructions.Storage/.Create, CodeDepositHandler, IntrinsicGasCalculator, EthereumGasPolicy, TransactionProcessor, SystemTransactionProcessor, plus the OP / Taiko / Xdc transaction processors.
  • EIP-8037 child-frame restore on halt vs revert

    • RestoreChildStateGas(parent, child, initialReservoir, childStateRefund) keeps the existing semantics on explicit REVERT (state-gas refunds burned at the revert boundary, propagate StateGasSpillBurned for top-level halt accounting).
    • New RestoreChildStateGasOnHalt returns the child's full reservoir + accumulated StateGasUsed to the parent and preserves any inline state-gas refunds, matching the spec rule that the failing call chain resets state gas back to the top-most failing call.
    • VirtualMachine.UnwindOnError and RevertRefundToHalt updated; new EthereumGasPolicy.ResetForHalt snaps state-gas back to its tx-start shape on top-level halt.
    • Regression test Eip8037_exceptional_halt_must_restore_child_inline_state_refund covers the divergence.
    • ConsumeStateGas no longer zeroes the reservoir before the regular-dimension UpdateGas fails - on OOG the reservoir is now preserved for the parent to recover.
  • EIP-8037 per-tx 2D inclusion check - new Eip8037BlockGasInclusionCheck.Validate (mirrors execution-specs PR 2703); applied in the parallel validator before gas accounting so the worker's underlying ParallelExecutionException is not masked by the block-level check. The pre-execution helper is also gated against below-intrinsic state-gas via a Math.Max(0, ...) clamp on worstCaseRegular.

  • State: introduce IBlockAccessListSource and propagate it through VirtualMachine, VmState, TransactionProcessor, and SystemTransactionProcessor so BAL data is available at the right layer for both prewarm and validation. BlockAccessListBasedWorldState.Restore now correctly forwards transient-storage snapshots (was previously a no-op). TracedAccessWorldState.Caches delegates through _innerWorldState.ScopeProvider as IPreBlockCaches and throws a clear exception when wired against an incompatible inner state.

  • Amsterdam fork - enable EIP-7976 (calldata floor 16 gas/token) and EIP-7981 in 25_Amsterdam.cs. These two are the "Amsterdam floor pricing" bundle: in ChainSpecBasedSpecProvider they fall back to chainSpec.AmsterdamTimestamp when their per-EIP transition is omitted, so they auto-enable on the Amsterdam timestamp without requiring per-EIP transitions in the chainspec. Behaviour is pinned by Amsterdam_timestamp_enables_bundled_floor_pricing_eips_when_individual_transitions_are_missing and called out inline at the call site so the divergence from every other Amsterdam EIP is obvious.

Post-review feedback

All 21 items from the linked review (high / medium / low priority + Copilot summary) have been addressed, plus a follow-up inline-review pass (12 additional comments) covering naming, comments, and small ergonomic tightenings. Highlights:

  • Hot-path allocation removal: replaced LINQ SequenceEqual with indexed loops in SlotChanges.Equals / AccountChanges.Equals; dropped [.. item.AccountChanges] in BlockAccessListDecoder.GetContentLength.
  • Decode robustness: Rlp.DecodeArrayPool<T> disposes pooled results on every failure path (not only range exceptions); BlockAccessListDecoder rejects empty AccountChanges entries up front so they cannot inflate ItemCount.
  • Defensive correctness: BlockReceiptsTracer.SetReceipt / EndBlockTrace no longer NREs on partial harvests under worker-exception conditions; the size and index-bounds BAL validators now agree on the block.BlockAccessList! precondition.
  • Spec anchors: added direct EIP-7702 / EIP-8037 / exec-specs PR-2703 references for the StateGasSpillBurned / Reclassified / Refunded accounting split, the inclusion-check asymmetry between regular and state dimensions, and the CREATE init-code-too-large SetOutOfGas / CreditStateGasRefund pairing.
  • Cleanup: deduplicated GasCostOf.BlockAccessListItem and Eip7928Constants.ItemCost; updated stale bal-devnet-4 references in GasCostOf.cs to bal-devnet-6; reordered [MethodImpl] attributes so they immediately precede their methods on RestoreChildStateGas and RestoreChildStateGasOnHalt.
  • Follow-up inline review (12 items): restored the inner-exception message in ParallelExecutionException's detail string so the underlying tx rejection reason is preserved; added class-level doc on BlockAccessListValidationIndex and ParentReaderLease; added an inline block comment over ValidateBlockAccessList distinguishing the index-based vs streaming fast-paths from the slow diagnostic path; switched the parent-state-header build in ParallelTxProcessorWithWorldStateManager to object-initializer syntax; renamed [ThreadStatic] t_currentTxTracers to _currentTxTracers in OpcodeBlockTracer to match the codebase's single-underscore field convention; dropped devnet/PR references from EIP-8037 comments; documented why the StorageLane insertion / scratch sort is bespoke (no Array.Sort overload covers three parallel arrays without boxing); restored the Amsterdam floor pricing bundle fallback in ChainSpecBasedSpecProvider with an inline comment naming the test that pins the contract.

Block processing stats

Fixed parallel block-validation ProcessingStats accounting (29e728b398): the per-block trace harvest now reaches EndBlockTrace even when the executor runs transactions in parallel, so the per-block Processed | Blocks xN | Block throughput metric line is accurate for both sequential and parallel paths. The IBlockTracer / CompositeBlockTracer / OpcodeBlockTracer / OpcodeCountingTxTracer surfaces were updated together to keep the trace-collection seam consistent.

Performance optimizations

A six-commit sweep on the parallel BAL hot path. Each lands behind the existing test suite (state, decoder, processor, validator, journal) plus dedicated regressions; functional behaviour is unchanged.

  • d9916eba Optimize - debox the BAL change journal. Replaced the polymorphic Stack<Change> (struct with object PreviousValue / object PreTxBalance etc.) with parallel typed lanes (List<ChangeType> discriminator + List<BalanceChangeDetails> / NonceChangeDetails / CodeChangeDetails / StorageChangeDetails). Renames Pop{Balance,Nonce,Code}Change to non-nullable TryPop* returning out T so the rollback path no longer round-trips through Nullable<T>. Generic PopChange<T> now constrained where T : struct, IIndexedChange. New NoPreviousBlockAccessIndex sentinel disambiguates "no in-block predecessor" from prestate. New BlockAccessListJournalTests cover the lane invariants.
  • 41bc16ad Super-optimize - drop SortedDictionary from the hot path. BlockAccessList._accountChanges is now Dictionary<Address, AccountChanges> with a lazily-built sorted snapshot (_sortedAccountChanges, invalidated on insert) exposed as ReadOnlySpan<AccountChanges> AccountChangesByAddress. Adds UnorderedAccountChanges for paths that do not need ordering, EnsureCapacity on Merge, a BlockAccessList.FromSortedAccountChanges factory for the decoder fast-path (avoids the dictionary -> sort round-trip), and GenericEqualityComparer.GetOptimized<Address>() for hash-friendly comparison.
  • e289dfeb Ultra-optimize - replace SortedList<uint, T> with IndexedChanges<T>. Custom lane stores prestate in a dedicated _hasPrestate / _prestate slot and real changes in a dense uint-sorted array. Eliminates PrestateAwareIndexComparer from the read hot path and removes the per-iteration prestate-skip branch from every foreach over balance / nonce / code changes. HasRealBefore and TryGetLastBeforeOrPrestate are O(log n) binary searches over the dense lane (was O(n) linear scan with prestate filter). New IndexedChangeValues<T> typed accessor replaces IList<T> interface dispatch in BAL surface APIs; IndexedChangesJsonConverter keeps wire JSON shape stable. Decoders (IndexedChangeDecoder, simplified AccountChangesDecoder / SlotChangesDecoder / BlockAccessListDecoder) emit straight into the new lane.
  • c598327c Turbo-optimize - reusable gas-validation handoff. New GasValidationResultSlot (lock + Monitor.PulseAll + ExceptionDispatchInfo) replaces the per-tx TaskCompletionSource<GasValidationResult> worker -> validator handoff. Pre-allocated GasValidationResultSlot[] pool reused across blocks, zero per-block TCS / Task / continuation allocations on the parallel-validation path. New readonly struct GasValidationResult carries (BlockGasUsed, BlockStateGasUsed, IntrinsicGas, Exception) so the validator's EIP-8037 inclusion check uses the worker's pre-computed intrinsic gas instead of recomputing on the main thread. Tightens BlockReceiptsTracer.SetReceipt and CompositeBlockTracer to handle partial-harvest under worker exceptions.
  • 67848bf9 Eldritch-optimize - tx execution reordering. Parallel worker now consumes _txExecutionOrder[] instead of the canonical tx index. The first max(8, ProcessorCount * 2) slots stay in canonical order so the lead window starts executing immediately; the tail is sorted by TxExecutionSortKey to reduce inter-worker contention on shared Address / StorageCell lanes. _perTxBal[] is still keyed on canonical index (txIndex + 1) so the validator sees results in spec order. New CancelIncompleteGasResults ensures a worker-side throw cancels every still-pending GasValidationResultSlot so the validator unblocks and surfaces the original exception.
  • cbb1ab1b Forbidden optimizations - lookup-time prestate. Stop eagerly mutating the wire BAL with PrestateIndex sentinels read from the live mutable state. BlockAccessListBasedWorldState reads now go through (1) BAL membership, (2) last real change before _blockAccessIndex, (3) a parent-rooted readonly IWorldState fallback. The fallback is built per-tx via PrewarmerEnvFactory + IReadOnlyTxProcessorSource, sharing PreBlockCaches with BlockCachePreWarmer.WarmupFromBal so parallel-IO warmup values feed validation reads and worker misses populate the cache for downstream workers. LoadPreStateToSuggestedBlockAccessList and the _lastLoadedBal guard are deleted. ApplyStateChanges now reads the prior balance directly from stateProvider at the correct tx-body prestate ordering. Pooled ParentReaderLease retires the per-tx readonly scope back to its env pool on processor return. Verified end-to-end against a kurtosis devnet-6 enclave (block 792 -> 3513 monotonic, zero Exception | Invalid Block | Unhandled | Fatal | ERROR | InvalidBlockLevelAccessList signals).

Tests / CI

  • Bump pyspec fixtures to snobal-devnet-6@v1.1.0 (fixtures_snobal-devnet-6.tar.gz).
  • Replace per-fork Amsterdam test files with a uniform fixture pattern in Tests.cs; add ArchiveFixtureOverrides hook for archive-version-specific patches.
  • Expand the Pyspec sharding from 4 -> 16 chunks on ubuntu-latest; the larger fixture set blew the previous 60-min job budget.
  • Drop the SkipIfNotLinuxX64Ci / SkipIfNotLinuxX64 [SetUp] guards from the abstract Pyspec fixtures (they turned macOS/ARM jobs into "Zero tests ran -> exit 1" noise) and add a single CiSentinelTests.AlwaysPasses fixture so any all-skipped shard still has one passing test.
  • New regression and unit coverage in Eip8037Tests, Eip8037RegressionTests, Eip8037BlockGasIntegrationTests, Eip8037BlockGasInclusionCheckTests, Eip7928Tests, BlockAccessListItemCountTests, PrestateAwareIndexComparerTests, AccountChangesPrestateTests, BlockAccessListDecoderTests, TransactionProcessorEip4844Tests, BlockValidatorTests, BlockAccessListBasedWorldStateTests, TracedAccessWorldStateTests, BlockReceiptsTracerTests, BlockProcessorTests, BlockhashProviderTests, ChainSpecBasedSpecProviderTests, BlockAccessListJournalTests, BlockCachePreWarmerTests, CompositeBlockTracerTests, plus engine ExecutionPayloadV4Tests.

EELS passing

image

Devnet smoke verification

The full bundle (protocol + post-review feedback + metrics fix + perf sweep) was exercised against a kurtosis devnet-6 enclave (lighthouse CL + Nethermind EL, fresh genesis, catch-up sync). Latest run reaches block 20491+ (current head) with zero AGENTS.md mandatory error signals (Exception | Invalid Block | Unhandled | Fatal | ERROR); per-block stats line shows ~9000 MGas/s, ~14,900 tps, ~250 Blk/s during catch-up.

Types of changes

  • New feature (a non-breaking change that adds functionality)
  • Bugfix (a non-breaking change that fixes an issue)
  • Build-related changes

Testing

Requires testing

  • Yes

If yes, did you write tests?

  • Yes

Notes on testing

  • Pyspec fixture suite (fixtures_snobal-devnet-6.tar.gz, snobal-devnet-6@v1.1.0) green on Linux x64; macOS/ARM shards now report at least one pass per shard via the sentinel fixture so they no longer fail with "Zero tests ran".
  • New focused tests cover EIP-8037 gas accounting (including the halt vs revert split), EIP-7928 BAL encoding/decoding/validation, the uint32 index widening, the new per-tx 2D inclusion check, the ConsumeStateGas OOG reservoir preservation invariant, BlockReceiptsTracer partial-harvest robustness, IndexedChanges<T> lane invariants, the BlockAccessList change-journal lanes, the GasValidationResultSlot worker-cancel path, the tx-execution-order sort key, the lookup-time prestate fallback through BlockAccessListBasedWorldState._parentReader, and the Amsterdam floor pricing bundle fallback in ChainSpecBasedSpecProvider.
  • Devnet-6 kurtosis cold-start (lighthouse + Nethermind) reaches 2700+ blocks with zero exceptions on the live BAL/EIP-8037 hot paths.

Documentation

Requires documentation update

  • No

flcl42 and others added 9 commits April 30, 2026 13:49
)

* fix(bal): align EIP-7928 BlockAccessIndex with uint32 spec, add validation

Widens BlockAccessIndex from uint16 to uint32 per EIP-7928 (commit 645099785a)
and geth bal-devnet-4. Hardens the BAL decoder so truncated/malformed wire
bytes produce a clean RlpException at engine_newPayloadV5 instead of crashing.
Adds the missing validation rules geth bal-devnet-4 enforces: empty
storage_changes per slot is rejected, and BlockAccessIndex is bounded by
[0, txCount + 1].

Decoder primitives:
- New Rlp.ValueDecoderContext.DecodeUInt() / RlpStream.Encode(uint) /
  Rlp.LengthOf(uint) helpers.
- Rlp.Decode<T> and Rlp.DecodeArrayPool<T> wrap IndexOutOfRangeException /
  ArgumentOutOfRangeException as RlpException so any truncated-RLP primitive
  read surfaces consistently.
- BlockAccessListDecoder rejects an empty AccountChanges entry (0xc0 inside
  the outer list) and SlotChangesDecoder rejects an empty StorageChange list
  for a slot — geth bal-devnet-4 "empty storage writes" parity.

Type widening:
- IIndexedChange.Index, BalanceChange/NonceChange/CodeChange/StorageChange.Index,
  BlockAccessList.Index and BlockAccessIndex on the Change journal record all
  become uint. SortedList<int, T> keys flip to SortedList<uint, T>; ushort
  query parameters on AccountChanges become uint.

Prestate sentinel preservation:
- Replaces the legacy -1 int sentinel with Eip7928Constants.PrestateIndex
  (uint.MaxValue). Adds PrestateAwareIndexComparer that orders the sentinel
  before all real indices, restoring the iteration semantics that
  AccountChanges.GetBalance/GetNonce/GetCode/AccountExists and
  ApplyStateChanges' [^1].Index check rely on.
- Decoder-built SortedLists also use the prestate-aware comparer so that
  LoadPreStateToSuggestedBlockAccessList grafting prestate onto the suggested
  BAL after decode keeps it sorted first.
- Loop predicates that compare change.Key directly against blockAccessIndex
  explicitly skip PrestateIndex so the raw uint comparison doesn't trigger
  on the huge sentinel value.

Validation:
- BlockValidator gains ValidateBlockLevelAccessListIndexBounds enforcing
  index <= txCount + 1 (mirrors geth's index < txCount + 2 check) with a new
  BlockLevelAccessListIndexOutOfRange error message.

Tests:
- New PrestateAwareIndexComparerTests, AccountChangesPrestateTests covering
  the comparer and prestate-fallback iteration semantics.
- BlockAccessListDecoderTests adds: empty-bytes / truncated-outer-list /
  inner-empty-list throw RlpException; empty storage_changes per slot throw;
  decoded SlotChanges accepts a later prestate graft as first; BalanceChange
  round-trips for indices 0x10_0000 and uint.MaxValue.
- BlockValidatorTests adds tx-index bound cases (0, 1 valid; 2,
  uint.MaxValue rejected for a 0-tx block).
- ExecutionPayloadV4Tests covers the engine-API decoding-error path for
  malformed BAL bytes.

* style: drop unused usings flagged by IDE0005

CI surfaced four IDE0005 warnings (treated as errors):
- BlockAccessListManager: drop `using Nethermind.Crypto;` —
  Keccak.OfAnEmptySequenceRlp comes from Nethermind.Core.Crypto, already imported.
- PrestateAwareIndexComparerTests / AccountChangesPrestateTests: drop
  `using Nethermind.Core;` — Eip7928Constants resolves via the test's parent
  namespace Nethermind.Core.Test.BlockAccessLists.
- Eip8037Tests: drop `using System;` — no System.* type referenced directly.

* fix(bal): record system pre/post-block SSTOREs as reads per EIP-7928 v5.7.0

EIP-7928 v5.7.0 specifies that SSTOREs performed during system pre-block calls
(EIP-2935 BlockHashHistory, EIP-4788 BeaconRootContract) and post-block calls
(EIP-7002 withdrawal requests, EIP-7251 consolidation requests) are recorded
in the BAL as storage reads on the touched slot — not as storage changes with
post-values. Same-value writes are skipped entirely. Without this, nethermind
generated a BAL whose Keccak256 differs from what eels-built fixtures expect,
so the BlockAccessListHash check fails for every Amsterdam block that touches
a system contract slot (most pyspec tests).

IWorldState gains an opt-in scope:

  IDisposable? BeginSystemPreBlockScope()

TracedAccessWorldState implements it via an int depth counter. While depth > 0,
Set(storageCell, value) reclassifies the recording: AddStorageRead when the
slot value would change, no-op when unchanged. The state mutation still
applies via the inner world state.

BlockAccessListManager wraps the three system contract entry points with the
scope: StoreBeaconRoot (EIP-4788 system tx), ApplyBlockhashStateChanges
(EIP-2935 fast-path Set), and ProcessExecutionRequests (EIP-7002 / EIP-7251
post-block system txs).

Parallel-mode state application:

In parallel processing, non-system slots wrap stateProvider with
BlockAccessListBasedWorldState whose Set is a no-op — actual state mutation
relies on ApplyStateChanges replaying the suggested BAL's storage_changes.
With the spec-correct BAL containing reads instead of changes for the system
slots, ApplyStateChanges has nothing to replay for them, so the canonical
state would diverge.

TxProcessorWithWorldState gains an `isSystemSlot` parameter. The
ParallelTxProcessorWithWorldStateManager passes `isSystemSlot: i == 0 || i ==
_len - 1` (pre-execution and post-execution slots). For those slots, the
TracedAccessWorldState wraps stateProvider directly, so system pre/post-block
SSTOREs mutate the canonical state regardless of BAL recording. Tx slots
(1..n) keep the BAL-backed wrapping unchanged.

Sequential pyspec tests (which is what the Ethereum.Blockchain.Pyspec.Test
suite runs) are unaffected by the parallel slot change but benefit from the
BAL recording fix; the BlockAccessListHash check now passes for blocks that
previously failed solely on system pre-block storage encoding.

Note: a residual InvalidStateRoot mismatch remains on a subset of Amsterdam
pyspec tests (~70/360 ecrecover_weird_v + a similar slice of stMemoryStress).
These were previously masked by the BAL hash error firing first. The
remaining state divergence appears unrelated to BAL recording and is left
for follow-up.

* test(jsonrpc): update Eth_get_block_access_list_by_* fixtures for EIP-7928 v5.7.0

The Eth_get_block_access_list_by_hash and _by_number tests had hardcoded the
pre-v5.7.0 shape, recording the EIP-2935 BlockHashHistory system pre-block
SSTORE as a storageChanges entry with the post-value. v5.7.0 records system
pre-block SSTOREs as storageReads (slot key only).

Updated both expected JSON strings to match the new spec-compliant output.

* Revert "fix(bal): record system pre/post-block SSTOREs as reads per EIP-7928 v5.7.0"

This reverts commit 364f294.

* Revert "test(jsonrpc): update Eth_get_block_access_list_by_* fixtures for EIP-7928 v5.7.0"

This reverts commit 937ca5d.

* review: address PR #11362 feedback

- Rlp.DecodeArrayPool<T>: dispose partially-allocated ArrayPoolList<T>
  before wrapping IndexOutOfRangeException/ArgumentOutOfRangeException
  as RlpException so the rented buffer is returned to the pool.
- Rlp.ValueDecoderContext.DecodeUInt(): collapse case 0 to a single
  `return RlpHelpers.ThrowNonCanonicalInteger(Position)` (DoesNotReturn,
  uint) to match DecodeInt and drop the dead `return default`.
- BlockAccessListManager.GetPostExecution(): use uint.MaxValue literal
  to match the uint? balIndex parameter.
- AccountChanges.SlotChangesAtIndex: build the returned SortedList with
  PrestateAwareIndexComparer.Instance so a later prestate graft sorts
  first, matching the rest of the codebase.
- PrestateAwareIndexComparer xmldoc: clarify that decoded BALs also use
  this comparer (so later prestate grafting preserves order).

* test(pyspec): skip EELS bal@v5.7.0 ported_static fixtures with legacy state-test conversion bug

EELS's `from_state_test` conversion for ported_static tests omits the
EIP-2935 / EIP-4788 system pre-block SSTORE entries from the suggested
BAL, while a real client (and Nethermind) executes them — so every such
fixture's BlockAccessListHash diverges from what we compute. 91 such
tests were the entire residual pyspec failure set on the bal-devnet-4a
branch.

Detect the conversion via the legacy difficulty value 0x20000 baked
into the post-merge mixHash field — real prevRandao would never be
exactly 0x...020000 — and Assert.Ignore those tests.

Track upstream EELS fix; remove the guard once bal@>v5.7.0 ships with
the system pre-block SSTOREs included in the BAL.

* fix(pyspec test): drop ?-annotation in non-nullable file

CS8632: PyspecTestFixture.cs is not under `#nullable enable`, so the
`string?` introduced in 6fb6527 broke the build of every pyspec
job. `string` works the same here — the value already gets a null
check on the next line.

* test(pyspec): also skip blockchain_test_engine_from_state_test variant

The first guard only walked test.Blocks, which is null for engine
fixtures. Engine fixtures keep the same legacy 0x...020000 sentinel,
just on the JSON `prevRandao` field of the engine_newPayload params.
Walk EngineNewPayloads too.

* Update tests

* fix(eip-8037): pin cost_per_state_byte at static 1174 for bal-devnet-4

bal-devnet-4 keeps cost_per_state_byte static at 1174 (carried over from
bal-devnet-3), removing the per-block-gas-limit scaling formula that an
earlier draft of EIP-8037 specified. snøbal-devnet-4 fixtures encode the
same gas usage (63574) at 1M / 5M / 10M / 30M block gas limits, confirming
the value is now invariant across blockGasLimit.

Reduce CalculateCostPerStateByte to a direct return of CostPerStateByte
and drop the dynamic-quantization helpers and BitOperations dependency.
The blockGasLimit parameter is retained on call sites in case a future
devnet revisits per-block scaling. Update the EIP-8037 unit test to pin
the static behaviour rather than asserting quantized values.
commit 3a3078f
Author: Marc Harvey-Hill <10379486+Marchhill@users.noreply.github.com>
Date:   Tue Apr 28 18:23:03 2026 +0200

    delete old tests

commit 95de888
Merge: 244c2c6 31a673a
Author: MarekM25 <marekm2504@gmail.com>
Date:   Tue Apr 28 18:08:12 2026 +0200

    Merge branch 'master' into engine-api-glamsterdam-cleanup

commit 244c2c6
Author: MarekM25 <marekm2504@gmail.com>
Date:   Tue Apr 28 18:05:32 2026 +0200

    fix lint

commit 9194b8f
Author: MarekM25 <marekm2504@gmail.com>
Date:   Tue Apr 28 18:04:19 2026 +0200

    remove tests

commit eedfbb7
Author: MarekM25 <marekm2504@gmail.com>
Date:   Tue Apr 28 17:57:46 2026 +0200

    revert formatting changes and zero hash stuff

commit dc71aa5
Author: MarekM25 <marekm2504@gmail.com>
Date:   Tue Apr 28 17:38:42 2026 +0200

    cleanups

commit ec2fce3
Author: MarekM25 <marekm2504@gmail.com>
Date:   Tue Apr 28 17:33:11 2026 +0200

    fixing

commit 90a1da8
Author: MarekM25 <marekm2504@gmail.com>
Date:   Tue Apr 28 17:15:58 2026 +0200

    remove test

commit 4451656
Author: MarekM25 <marekm2504@gmail.com>
Date:   Tue Apr 28 17:12:32 2026 +0200

    Cleanup mess

commit 2425748
Merge: 4a90460 a36154c
Author: Stavros Vlachakis <89769224+svlachakis@users.noreply.github.com>
Date:   Mon Apr 27 14:33:36 2026 +0300

    Merge branch 'master' into engine-api-glamsterdam

commit 4a90460
Merge: 3549768 18d60a4
Author: Stavros Vlachakis <89769224+svlachakis@users.noreply.github.com>
Date:   Mon Apr 27 14:08:25 2026 +0300

    Merge branch 'master' into engine-api-glamsterdam

commit 3549768
Merge: 30fcc36 b71c352
Author: Stavros Vlachakis <89769224+svlachakis@users.noreply.github.com>
Date:   Mon Apr 27 14:07:39 2026 +0300

    Merge branch 'master' into engine-api-glamsterdam

commit 30fcc36
Merge: 540e4a2 ed6a354
Author: Stavros Vlachakis <89769224+svlachakis@users.noreply.github.com>
Date:   Mon Apr 27 13:09:48 2026 +0300

    Merge branch 'master' into engine-api-glamsterdam

commit 540e4a2
Author: stavrosvl7 <stavrosvl7@gmail.com>
Date:   Sun Apr 26 04:52:49 2026 +0300

    minor fixes

commit 010547b
Author: stavrosvl7 <stavrosvl7@gmail.com>
Date:   Sun Apr 26 03:22:39 2026 +0300

    test fixes

commit 6fcc136
Author: stavrosvl7 <stavrosvl7@gmail.com>
Date:   Sun Apr 26 02:11:12 2026 +0300

    fixes

commit 0bccb06
Author: stavrosvl7 <stavrosvl7@gmail.com>
Date:   Sun Apr 26 01:52:02 2026 +0300

    test fix

commit 830c578
Author: stavrosvl7 <stavrosvl7@gmail.com>
Date:   Sun Apr 26 01:38:55 2026 +0300

    fix tests

commit 1f5fd2c
Author: stavrosvl7 <stavrosvl7@gmail.com>
Date:   Sun Apr 26 01:35:17 2026 +0300

    claude review again

commit d87491f
Author: stavrosvl7 <stavrosvl7@gmail.com>
Date:   Sun Apr 26 00:57:57 2026 +0300

    fixes

commit dd431e2
Author: stavrosvl7 <stavrosvl7@gmail.com>
Date:   Sun Apr 26 00:51:52 2026 +0300

    fix tests

commit 71dc99f
Author: stavrosvl7 <stavrosvl7@gmail.com>
Date:   Sat Apr 25 22:40:50 2026 +0300

    fixes

commit 9c03d12
Author: stavrosvl7 <stavrosvl7@gmail.com>
Date:   Sat Apr 25 22:32:58 2026 +0300

    update per 786

commit a4c4f3c
Merge: fc49e7e 9cba44c
Author: stavrosvl7 <stavrosvl7@gmail.com>
Date:   Sat Apr 25 21:38:25 2026 +0300

    Merge remote-tracking branch 'origin/master' into engine-api-glamsterdam

commit fc49e7e
Merge: bca0c63 42c551f
Author: Stavros Vlachakis <89769224+svlachakis@users.noreply.github.com>
Date:   Mon Apr 20 16:14:33 2026 +0300

    Merge branch 'master' into engine-api-glamsterdam

commit bca0c63
Author: stavrosvl7 <stavrosvl7@gmail.com>
Date:   Mon Apr 20 16:14:10 2026 +0300

    remove unused import

commit 3d2c973
Author: stavrosvl7 <stavrosvl7@gmail.com>
Date:   Mon Apr 20 16:09:17 2026 +0300

    fix taiko tests

commit b30ef5c
Author: stavrosvl7 <stavrosvl7@gmail.com>
Date:   Mon Apr 20 15:34:35 2026 +0300

    fix tests

commit 6f131cd
Merge: a8c884a 0fe41f4
Author: Stavros Vlachakis <89769224+svlachakis@users.noreply.github.com>
Date:   Mon Apr 20 14:55:46 2026 +0300

    Merge branch 'master' into engine-api-glamsterdam

commit a8c884a
Author: stavrosvl7 <stavrosvl7@gmail.com>
Date:   Mon Apr 20 14:54:40 2026 +0300

    conflicts fix

commit 96eb912
Merge: 82a1f70 425a2a3
Author: stavrosvl7 <stavrosvl7@gmail.com>
Date:   Mon Apr 20 14:52:33 2026 +0300

    Merge remote-tracking branch 'origin/master' into engine-api-glamsterdam

    # Conflicts:
    #	src/Nethermind/Nethermind.Merge.Plugin/BlockTreeExtensions.cs
    #	src/Nethermind/Nethermind.Merge.Plugin/Handlers/ForkchoiceUpdatedHandler.cs
    #	src/Nethermind/Nethermind.Taiko/Rpc/TaikoForkchoiceUpdatedHandler.cs

commit 82a1f70
Merge: 7b6133f 436c65b
Author: stavrosvl7 <stavrosvl7@gmail.com>
Date:   Mon Apr 20 13:16:55 2026 +0300

    Merge remote-tracking branch 'origin/master' into engine-api-glamsterdam

commit 7b6133f
Merge: 2f068ec 02c2026
Author: Stavros Vlachakis <89769224+svlachakis@users.noreply.github.com>
Date:   Thu Apr 16 14:49:46 2026 +0300

    Merge branch 'master' into engine-api-glamsterdam

commit 2f068ec
Merge: bdd7ee5 5464c8b
Author: Stavros Vlachakis <89769224+svlachakis@users.noreply.github.com>
Date:   Thu Apr 16 14:10:02 2026 +0300

    Merge branch 'master' into engine-api-glamsterdam

commit bdd7ee5
Merge: f09cb41 bfaaeb0
Author: Stavros Vlachakis <89769224+svlachakis@users.noreply.github.com>
Date:   Wed Apr 15 16:45:19 2026 +0300

    Merge branch 'master' into engine-api-glamsterdam

commit f09cb41
Merge: 370acdf cf03d18
Author: stavrosvl7 <stavrosvl7@gmail.com>
Date:   Wed Apr 15 16:24:17 2026 +0300

    Merge remote-tracking branch 'origin/master' into engine-api-glamsterdam

commit 370acdf
Merge: d1d0370 6cd0ea4
Author: Stavros Vlachakis <89769224+svlachakis@users.noreply.github.com>
Date:   Mon Apr 13 14:28:21 2026 +0300

    Merge branch 'master' into engine-api-glamsterdam

commit d1d0370
Author: stavrosvl7 <stavrosvl7@gmail.com>
Date:   Fri Apr 10 17:30:54 2026 +0300

    more fixes

commit c99d6cc
Merge: 4d0f215 a52cb90
Author: Stavros Vlachakis <89769224+svlachakis@users.noreply.github.com>
Date:   Fri Apr 10 17:24:06 2026 +0300

    Merge branch 'master' into engine-api-glamsterdam

commit 4d0f215
Author: stavrosvl7 <stavrosvl7@gmail.com>
Date:   Fri Apr 10 17:23:42 2026 +0300

    claude review

commit cb6defe
Merge: af63142 0057bd8
Author: Stavros Vlachakis <89769224+svlachakis@users.noreply.github.com>
Date:   Fri Apr 10 12:34:37 2026 +0300

    Merge branch 'master' into engine-api-glamsterdam

commit af63142
Merge: 1b338f3 2f24891
Author: Stavros Vlachakis <89769224+svlachakis@users.noreply.github.com>
Date:   Fri Apr 10 12:08:36 2026 +0300

    Merge branch 'master' into engine-api-glamsterdam

commit 1b338f3
Author: stavrosvl7 <stavrosvl7@gmail.com>
Date:   Fri Apr 10 12:08:13 2026 +0300

    claude review

commit 619259b
Author: stavrosvl7 <stavrosvl7@gmail.com>
Date:   Thu Apr 9 18:32:59 2026 +0300

    taiko fix

commit d067793
Author: stavrosvl7 <stavrosvl7@gmail.com>
Date:   Thu Apr 9 18:19:14 2026 +0300

    cleaner design

commit 1e27be1
Author: stavrosvl7 <stavrosvl7@gmail.com>
Date:   Thu Apr 9 18:12:04 2026 +0300

    improve tests matching the specs

commit a77e182
Author: stavrosvl7 <stavrosvl7@gmail.com>
Date:   Thu Apr 9 18:04:58 2026 +0300

    improve test

commit 4ba069c
Author: stavrosvl7 <stavrosvl7@gmail.com>
Date:   Thu Apr 9 18:01:59 2026 +0300

    fix comment

commit fe6f9b0
Author: stavrosvl7 <stavrosvl7@gmail.com>
Date:   Thu Apr 9 17:53:57 2026 +0300

    engine api changes as per ethereum/execution-apis#770
                              ethereum/execution-apis#760
@github-actions github-actions Bot added the taiko related to the taiko alethia rollup label Apr 30, 2026
@benaadams
Copy link
Copy Markdown
Member Author

@claude re-review

@claude
Copy link
Copy Markdown
Contributor

claude Bot commented May 8, 2026

Claude finished @benaadams's task in 4m 27s —— View job


PR Re-Review: BAL devnet-6 (Round 10)

  • Read rule files and gather context
  • Check new commits since Round 9 (46922f8, 7763e42, 376ea15, 688ae94)
  • Check outstanding findings from Round 9 (L1, L2)
  • Review new code changes
  • Post final findings

Summary

Four commits since Round 9. All are refactoring/dead-code removal with no new correctness issues. The "Kamil fix" revert restores the two-call pattern in EvmInstructions.Call.cs (separate TryGetDelegation + GetCachedCodeInfo rather than a combined call), which is safer given the different repository instances involved. The "Reduce code" commits eliminate dead methods, consolidate duplicated logic, and simplify internals without changing semantics.


New Commits

46922f8 fix — Tiny: changes string? _testChunk to string _testChunk in TestChunkFilterTests.cs. ✅

7763e42 Revert "Kamil fix" — Reverts 7954eaa. The combined GetCachedCodeInfo(codeSource, spec, out Address? delegated) overload exists, but the revert restores the two-call pattern (TryGetDelegation via vm.TxExecutionContext.CodeInfoRepository then GetCachedCodeInfo via vm.CodeInfoRepository). The two calls use the same underlying repository instance in practice but the original shape is more explicit about intent. ✅

376ea15 Reduce code changes — Removes verbose XML doc comments from IGasPolicy<TSelf> (replacing <summary> blocks with brief inline comments), trims dead code from AccountChanges (CheckWasChanged no-op, AccountChanged alias for HasStateChanges, ToDictionary, SeedSortedStorageCaches), and condenses Eip8037BlockGasInclusionCheckTests. Pure reduction, no semantic change. ✅

688ae94 Reduce code — Larger refactor across 17 files:

  • CompleteEip8037Halt extracted (TransactionProcessor.cs): The duplicated EIP-8037 halt sequence in FailContractCreate and Refund is now a shared [AggressiveInlining] private method. The comments about using postIntrinsicStateReservoir are now in one place. Semantically identical to the prior inline form. ✅
  • BuildUp snapshot drop (TransactionProcessor.cs:39-40): The IntrinsicGas<TGasPolicy> overload of Process no longer calls WorldState.TakeSnapshot(true) on BuildUp. The non-generic Process(Transaction, ITxTracer, ExecutionOptions) retains the snapshot (line 125-128). The generic overload is only called by the BAL parallel path which passes Commit, not BuildUp, so this is correct. ✅
  • AddressIndex.GetOrAdd via CollectionsMarshal (BlockAccessListValidationIndex.cs): CollectionsMarshal.GetValueRefOrAddDefault is a single-pass lookup+insert that avoids a double hash. Address implicitly converts to AddressAsKey (line 292 of Address.cs). The old _addresses reverse-lookup array and GetAddress were removed (no production callers). ✅
  • TryGetRow simplification (BlockAccessListValidationIndex.cs): Always sets row = (int)index, returns index <= lastIndex. All call sites use if (TryGetRow(..., out row)) { use_row; } so the unconditional set is never observed on false return. ✅
  • BlockAccessListValidationIndex constructor now requires non-null suggested; CreateMutableEmpty factory removed. The generated index is always constructed from a suggested index (only call site: BlockAccessListManager.PrepareForProcessing:103). ✅
  • HasRequiredReadAccountMissing inlined into RegisterGeneratedDelta: The static method is replaced by an inline loop with _hasGeneratedRequiredReadAccountMismatch = true; break;, gated by !_hasGeneratedRequiredReadAccountMismatch. Early-exit semantics preserved. ✅
  • Dead-code removal: AccountChanges.GetAllSlots (no callers), BlockAccessList.RemoveAccountChanges (no callers), CheckPerTxInclusion without pre-computed intrinsic (all callers now use the pre-computed overload). ✅
  • *ChangeDetailsreadonly record struct: Private journal structs now use synthesized Equals/GetHashCode/ToString. They are stored in List<T> and accessed via CollectionsMarshal.AsSpan by ref — the synthesized members are never called, so this is cosmetic-only overhead. ✅

Prior Findings — Status

Finding Status
L1 _completed.Wait() no cancellation Still present — finally _completed.Set() guarantees forward progress; catastrophic-fault path only. Not blocking.
L2 ParallelExecutionException message duplication Still present — cosmetic only.

All Medium and High findings from all prior rounds remain resolved.


Critical: 0 | High: 0 | Medium: 0 | Low: 2 (both acknowledged, non-blocking)

The PR is in the same mergeable state as Round 9. The "Reduce code" sweep is purely additive in terms of quality — cleaner, shorter, no regressions introduced. Ready to merge.

@LukaszRozmej
Copy link
Copy Markdown
Member

I think ideas that should be easy wins: 1, 2, 3, 4, 5, 6, 9, 12, 14, 15,
I think ideas that need profiling to be considered: 8 (Frozen Dictionary constructed in background), 11, 17, 18, 20, 21, 22, 24, 25, 30
I think ideas that are probably too much of a hassle: 7, 10, 13, 16, 19, 26, 27, 28,  29,

@codecov
Copy link
Copy Markdown

codecov Bot commented May 8, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 0.00%. Comparing base (db8b6e9) to head (644c447).
⚠️ Report is 1 commits behind head on master.

Additional details and impacted files
@@             Coverage Diff             @@
##           master   #11436       +/-   ##
===========================================
- Coverage   74.43%        0   -74.44%     
===========================================
  Files        2831        0     -2831     
  Lines      114624        0   -114624     
  Branches    16572        0    -16572     
===========================================
- Hits        85324        0    -85324     
+ Misses      26377        0    -26377     
+ Partials     2923        0     -2923     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 8, 2026

EXPB Benchmark Comparison

Run: View workflow run

superblocks

Scenario: nethermind-flat-superblocks-bal-devnet-6-delay0s

Client Processing (SSE)

Metric PR Master (cached) Delta
AVG (ms) 1256.77 1257.63 -0.07%
MEDIAN (ms) 1129.0 1164.9 -3.08%
P90 (ms) 1722.9 1736.8 -0.80%
P95 (ms) 2251.4 2133.2 +5.54%
P99 (ms) 3969.8 3433.0 +15.64%
MIN (ms) 804.6 783.9 +2.64%
MAX (ms) 3969.8 3433.0 +15.64%
K6 TTFB
Metric PR Master (cached) Delta
AVG (ms) 1484.92 1484.13 +0.05%
MEDIAN (ms) 1320.47 1367.54 -3.44%
P90 (ms) 1955.12 1990.19 -1.76%
P95 (ms) 2714.95 2532.57 +7.20%
P99 (ms) 3578.91 3437.59 +4.11%
MIN (ms) 929.36 920.70 +0.94%
MAX (ms) 4108.63 3602.27 +14.06%

realblocks

Scenario: nethermind-flat-realblocks-bal-devnet-6-delay0s

Client Processing (SSE)

Metric PR Master (cached) Delta
AVG (ms) 35.16 35.87 -1.98%
MEDIAN (ms) 28.7 29.5 -2.71%
P90 (ms) 64.3 65.7 -2.13%
P95 (ms) 76.4 76.7 -0.39%
P99 (ms) 124.0 124.1 -0.08%
MIN (ms) 1.6 1.5 +6.67%
MAX (ms) 252.6 229.4 +10.11%
K6 TTFB
Metric PR Master (cached) Delta
AVG (ms) 41.08 41.44 -0.87%
MEDIAN (ms) 34.23 35.55 -3.71%
P90 (ms) 73.23 73.44 -0.29%
P95 (ms) 83.30 83.73 -0.51%
P99 (ms) 133.84 128.79 +3.92%
MIN (ms) 2.59 2.26 +14.60%
MAX (ms) 257.57 259.92 -0.90%

@kamilchodola kamilchodola mentioned this pull request May 8, 2026
16 tasks
@benaadams
Copy link
Copy Markdown
Member Author

EELS passing

image

Comment thread src/Nethermind/Nethermind.Consensus/Processing/BlockAccessListManager.cs Outdated
Comment thread src/Nethermind/Nethermind.Consensus/Processing/BlockAccessListManager.cs Outdated
}

private TxReceipt[] ProcessTransactionsParallel(Block block, ProcessingOptions processingOptions, CancellationToken token)
private TxReceipt[] ProcessTransactionsParallel(Block block, ProcessingOptions processingOptions, BlockReceiptsTracer outerReceiptsTracer, CancellationToken token)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, could postpone such refactoring changes to a later PR though to prevent even more conflicts

Comment thread src/Nethermind/Nethermind.OpcodeTracing.Plugin/Tracing/OpcodeBlockTracer.cs Outdated
Comment thread src/Nethermind/Nethermind.Specs/ChainSpecStyle/GethGenesisLoader.cs Outdated
benaadams added 2 commits May 8, 2026 16:29
- BlockAccessListManager: restore inner-exception message in
  ParallelExecutionException detail; drop devnet/PR refs from EIP-8037
  comment; add fast/slow path explanation; switch BlockHeader build to
  object initializer; add ParentReaderLease doc comment.
- BlockAccessListValidationIndex: add class-level summary; document why
  the multi-array sort is bespoke.
- OpcodeBlockTracer: rename t_currentTxTracers to _currentTxTracers to
  match Nethermind's underscore-prefix field convention.
- ChainSpecBasedSpecProvider: drop inconsistent AmsterdamTimestamp
  fallback for Eip7976/Eip7981 (other Amsterdam EIPs don't have it).
- GethGenesisLoader: revert accidental ordering swap.
EIP-7976 and EIP-7981 are the "Amsterdam floor pricing" bundle: they
auto-enable on the Amsterdam timestamp without requiring per-EIP
transitions in the chainspec. Behaviour is covered by
Amsterdam_timestamp_enables_bundled_floor_pricing_eips_when_individual_transitions_are_missing.

My earlier removal in 79a1678 treated the fallback as inconsistent
with the other Amsterdam EIPs and broke that test. Restoring the
fallback with a code comment so the rationale is visible inline.
@benaadams
Copy link
Copy Markdown
Member Author

@claude re-review

@claude
Copy link
Copy Markdown
Contributor

claude Bot commented May 8, 2026

Claude finished @benaadams's task in 3m 22s —— View job


PR Re-Review: BAL devnet-6 (Round 11)

  • Read rule files and gather context
  • Check new commits since Round 10 (644c447, 3bd79ab, 79a1678, 2b8b649)
  • Review Marchhill's approval comments and benaadams responses
  • Check benchmark results
  • Post final findings

Summary

Four commits since Round 10. All are clean.


New Commits

644c447 dedupe testsPyspecTestFixture.cs refactored: introduces PyspecBlockchainFixtureBase(bool parallel, bool batchRead, bool heavy) as the shared root; PyspecEngineBlockchainTestFixture / PyspecSyncBlockchainTestFixture / PyspecAmsterdamBlockchainTestFixture all collapse to one-line () primary-constructor delegates — removes ~44 duplicate lines of [SetUp], protected override bool?, and attribute boilerplate. Clean reduction. ✅

3bd79ab Fix bad mergeHeadersSyncFeed.BuildNewBatch / ProcessPersistedPortion rework to handle the race where HeadersDestinationNumber advances above _lowestRequestedHeaderNumber mid-sync: StartNumber = Math.Max(HeadersDestinationNumber, ...) and RequestSize = Math.Min(headersLeft, requestSize) clamp correctly; the null return is eliminated (always returns a batch whose RequestSize may be 0 when the destination is already reached). ProcessPersistedPortion is widened to non-nullable. This is sync infrastructure, not BAL-related; the fix is conservative and ShouldBuildANewBatch() in PrepareRequest's outer guard prevents entering the build path when the destination is already reached. ✅

79a1678 Address PR review comments — Addresses all of Marchhill's open items:

  • ParallelExecutionException detail string restored to $"Parallel execution failure: {innerException.Message}" — inner rejection reason is now preserved. ✅
  • Devnet/PR refs dropped from EIP-8037 comment; replaced with plain "EIP-8037" reference. ✅
  • Fast/slow path block comment added over ValidateBlockAccessList explaining the index-based vs streaming fast-paths vs slow diagnostic path. ✅
  • BlockHeader build switched to object-initializer syntax in CreateParentStateHeader. ✅
  • ParentReaderLease class doc added (RAII wrapper, pooled source, returns on Dispose). ✅
  • BlockAccessListValidationIndex class-level summary added covering Build vs mutable ctor, column-oriented lane layout, and _hasOutOfRangeChange semantics. ✅
  • SortRow bespoke sort comment added explaining why Array.Sort is not used (no 3-parallel-array overload without boxing). ✅
  • OpcodeBlockTracer: t_currentTxTracers_currentTxTracers at all 5 sites. Matches the codebase convention (_threadStaticBuffer in Hash256.cs, _reusableWriteBatch in DbOnTheRocks.cs). ✅
  • ChainSpecBasedSpecProvider: Amsterdam fallback removed (then re-added in next commit — see below). ✅
  • GethGenesisLoader: accidental ordering swap reverted. ✅

2b8b649 Restore Amsterdam floor pricing EIP fallback with explanation79a1678 inadvertently broke Amsterdam_timestamp_enables_bundled_floor_pricing_eips_when_individual_transitions_are_missing by removing the ?? chainSpec.AmsterdamTimestamp fallback for EIP-7976/7981. This commit restores it with a three-line inline comment explaining the "Amsterdam floor pricing bundle" special case (auto-enables on Amsterdam timestamp without per-EIP transitions). The commit message and comment are precise about why this diverges from every other Amsterdam EIP. ✅


Prior Findings — Status

Finding Status
L2 (Round 10) ParallelExecutionException message duplication ✅ Fixed — WithDetail($"Parallel execution failure: {innerException.Message}")
L1 (Round 10) _completed.Wait() no cancellation Still present — finally _completed.Set() guarantees forward progress; catastrophic-fault path only. Non-blocking.

All Medium and High findings from all prior rounds remain resolved.


Benchmark Results

Metric Superblocks Realblocks
AVG delta -0.07% -1.98%
Median delta -3.08% -2.71%
P90 delta -0.80% -2.13%
P99 delta +15.64% -0.08%

Superblocks P99 shows +15.64% (tail variance) but median is -3.08% — consistent with single-run statistical noise at tail percentiles. Realblocks are uniformly flat or slightly improved. No performance regression.


Critical: 0 | High: 0 | Medium: 0 | Low: 1 (acknowledged, non-blocking)

All high and medium findings across all eleven review rounds are resolved or explicitly acknowledged with rationale. Devnet-6 smoke run (20k+ blocks, zero exception/invalid-block signals), EELS passing, extensive unit/regression/integration coverage, and flat-to-slightly-improved benchmarks. The PR is ready to merge.

@benaadams benaadams merged commit 481b6b1 into master May 8, 2026
970 of 976 checks passed
@benaadams benaadams deleted the bal-devnet-6 branch May 8, 2026 19:16
@benaadams benaadams restored the bal-devnet-6 branch May 8, 2026 19:16
Marchhill added a commit that referenced this pull request May 11, 2026
…hmarks

bal-devnet-6 (#11436) is now in master, so this brings everything from master
including the BAL devnet-6 PR plus subsequent master commits. Conflict
resolution:

  - Took ours for every BAL-touching file (decoders, manager, validator,
    BlockAccessListBased/TracedAccess world states, parallel-loop executor,
    cache pre-warmer, BAL tests). Our branch's ReadOnly*/Generated*/*AtIndex
    split diverges substantially from upstream's unified BlockAccessList, and
    upstream merging bal-devnet-6 into master pulled in the unified version.
  - Removed (again) BlockAccessListValidationIndex + tests, BlockAccessList,
    AccountChanges, SlotChanges, BlockAccessListItemCountTests, and
    BlockAccessListJournalTests: all reference the removed unified type.
  - Removed the now-broken Rlp.Encode(BlockAccessList) overload in Rlp.cs;
    callers use the generic Rlp.Encode<T> path for ReadOnly/Generated BALs.
  - Took theirs for TxReceiptConverter (upstream's boxing-free
    ForcedNumberConversion.Value refactor, already includes our EIP-7778/8037
    diagnostic fields) and ChainSpecBasedSpecProvider (comment-only addition).
  - Took ours for OpcodeBlockTracer (kept t_ prefix on the [ThreadStatic]
    field, our existing convention).
  - For .github/workflows/nethermind-tests-flat.yml took upstream's
    unconditional pre-build + 'dotnet build-server shutdown || true' approach
    (matches their CI peak-memory PR) while keeping our extra Cache NuGet
    packages step.
  - Updated EngineModuleTests.V6 ResultWrapper generic args from IEnumerable to
    IReadOnlyList to match upstream's API change.
barnabasbusa added a commit to ethpandaops/eth-client-docker-image-builder that referenced this pull request May 12, 2026
## Summary
- The `nethermindeth/nethermind#master master-bad-iszero` image build
has been failing because `nevermind/bad-iszero.patch` no longer applies
cleanly to upstream master ([failing
run](https://github.com/ethpandaops/eth-client-docker-image-builder/actions/runs/25737190830/job/75577551462)).
- Upstream Nethermind PR
[NethermindEth/nethermind#11436](NethermindEth/nethermind#11436)
(commit `481b6b17cc`) replaced the per-file `using Word =
Vector256<byte>;` aliases with a project-wide MSBuild `<Using ...
Alias=\"EvmWord\" />` in `src/Nethermind/Directory.Build.props`,
renaming all `Word` symbols to `EvmWord`. The underlying type
(`Vector256<byte>`) is unchanged, so `value.AsUInt64()` keeps working.
- This bumps the patch's context/signature from `Word Operation(Word
value)` to `EvmWord Operation(EvmWord value)`.

## Test plan
- [x] Dry-run `patch -p 1` against current upstream
`nethermindeth/nethermind` master — applies cleanly.
- [x] Applied patch and confirmed `OpIsZero.Operation` now reads with
`EvmWord` types and the bad-iszero hack body intact.
- [ ] Confirm the next scheduled `master-bad-iszero` build (linux-amd64
+ linux-arm64) succeeds end-to-end.
Marchhill added a commit that referenced this pull request May 13, 2026
Adopts master's parallel-execution architecture (PR #11436) for parent-state
reads while keeping our split BAL-type design:

  * Parallel workers now rent an IReadOnlyTxProcessingScope from a pooled
    IReadOnlyTxProcessingEnvFactory, scoped against the parent state root
    captured at PrepareForProcessing. BlockAccessListBasedWorldState falls
    through to that snapshot reader for any (address, slot) the suggested
    BAL doesn't carry at the current block-access index.

  * BAL completeness is preserved: reads for an account that isn't declared
    in the suggested BAL at all throw InvalidBlockLevelAccessListException
    with the same message format the sequential validator produces from
    ValidateBlockAccessList.

  * Parallel execution now requires stateProvider.IsInScope so a parent
    state root is always capturable; sequential path takes over otherwise.

Drops prestate-loading machinery in favour of the parent reader:

  * LoadPreStateToSuggestedBlockAccessList + per-account TaskCompletionSource
    gate (EnablePrestateGate / SignalPrestateLoaded / WaitForPrestate) are
    gone — workers no longer block on a per-account gate before reading
    prestate-dependent state.
  * ReadOnlyAccountChanges drops LoadPreStateBalance/Nonce/Code/Storage,
    GetSlotsForPreStateLoad, RecordWasChanged, ExistedBeforeBlock, and
    EmptyBeforeBlock; ReadOnlySlotChanges drops LoadPreStateChange.
  * Adds HasStateChanges, IsStorageRead, and TryGetLast{Balance,Nonce,Code}
    ChangeBefore convenience APIs the new world-state read paths need.
  * IndexedChanges keeps its prestate-slot storage and the wire-level
    PrestateIndex sentinel guard in IndexedChangeDecoder — both are dormant
    at runtime now but still defend against a malicious peer.

The slot-0 loader iteration in
BlockProcessor.ParallelBlockValidationTransactionsExecutor disappears (only
ApplyStateChanges remains in iteration 0); slot 1 keeps the pre-execution
StoreBeaconRoot / ApplyBlockhashStateChanges step and continues to
synchronize with IncrementalValidation via preExecutionDoneTcs.

Test updates:

  * BlockAccessListBasedWorldStateTests + the relevant TracedAccessWorldState
    test now wire up a parent reader (the inner state itself, scoped against
    genesis) and stop populating BAL prestate sentinels — covered values
    live in the parent state instead.
  * Removes AccountChangesPrestateTests and ReadOnlyAccountChangesTests
    entirely (every test exercised a deleted API).
  * Restores the parametrized
    PrepareForProcessing_keeps_parallel_bal_execution_for_validated_eip8037_blocks
    test and adds back the
    PrepareForProcessing_disables_parallel_bal_execution_when_state_provider_is_not_scoped
    test now that the IsInScope gate is in place.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants