Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
78 commits
Select commit Hold shift + click to select a range
0c62196
feat(engine): introduce REST based + SSZ serialized `new-payload-with…
Dyslex7c May 15, 2026
45710c8
register handler in DI
Dyslex7c May 15, 2026
f5631ea
fix test and formatting
Dyslex7c May 15, 2026
c4028c5
address deep review comments
Dyslex7c May 15, 2026
1e31a1f
add JSON-RPC method
Dyslex7c May 15, 2026
6671f99
fix taiko tests
Dyslex7c May 15, 2026
1d382f4
address review comments
Dyslex7c May 16, 2026
5ded051
address review comments
Dyslex7c May 17, 2026
8d10573
fix taiko tests and build
Dyslex7c May 17, 2026
2997bad
remove double block execution
Dyslex7c May 20, 2026
56551a1
merge with upstream
Dyslex7c May 20, 2026
bf1ccb1
fix CI build error
Dyslex7c May 20, 2026
792a296
address prev review comments
Dyslex7c May 20, 2026
13a70ee
address claude review comments
Dyslex7c May 20, 2026
6ec0663
address claude review
Dyslex7c May 21, 2026
5e43a8f
bug fixes
Dyslex7c May 21, 2026
77b72af
fix(witness): forward default IWorldState members to inner
LukaszRozmej May 22, 2026
384fd60
revert CodeInfoRepository code-lookup order swap
LukaszRozmej May 22, 2026
c9af935
restore SSZ MaxBodySize to spec value (16 MiB)
LukaszRozmej May 22, 2026
6e2b729
make NewPayloadWithWitnessV1Result IDisposable to return pool buffers
LukaszRozmej May 22, 2026
488d613
handle witness-capture cancellation on duplicate ArmCapture
LukaszRozmej May 22, 2026
53ff5e6
remove unused PayloadStatus.InvalidBlockHash
LukaszRozmej May 22, 2026
d7bb6a2
introduce WitnessCaptureSession to remove witness arm/disarm flags
LukaszRozmej May 22, 2026
4558ff1
inject Lazy<IEngineRpcModule> into NewPayloadWithWitnessHandler
LukaszRozmej May 22, 2026
13696e6
use Configure helper for newPayloadWithWitness; trim SSZ Union comment
LukaszRozmej May 22, 2026
8556efa
revert cosmetic refactor in EngineRpcModule
LukaszRozmej May 22, 2026
bbb6876
parameterize three Handler_calls_DisarmCapture tests
LukaszRozmej May 22, 2026
d2946c5
factor witness state-node proof collection into shared helper
LukaszRozmej May 22, 2026
b691335
share body-read/metrics/error path between versioned and witness SSZ …
LukaszRozmej May 22, 2026
56cc9f1
tighten SSZ codec/handler edges
LukaszRozmej May 22, 2026
43892c0
remove now-unused Nethermind.State.Proofs using in WitnessGeneratingW…
LukaszRozmej May 22, 2026
f81dac2
fix Arm() double-arm semantics and IDE0028 lint
LukaszRozmej May 22, 2026
90edb7d
disarm capture if BranchProcessor did not run for VALID payload
LukaszRozmej May 22, 2026
a2d6273
drop redundant inner using of Witness in SSZ writer
LukaszRozmej May 22, 2026
56ed6be
address deep-review fixes for newPayloadWithWitness
LukaszRozmej May 22, 2026
ffb03e3
disarm capture on engine_newPayloadV5 exception; flip Disarm order
LukaszRozmej May 22, 2026
e290bd6
snapshot proxy tracking dicts to drop ! non-null assertions
LukaszRozmej May 22, 2026
7018bbf
update Disarm comment after recorders moved to snapshot model
LukaszRozmej May 22, 2026
6148859
trim verbose comments across witness/SSZ surface
LukaszRozmej May 22, 2026
3f598dd
parameterize SSZ codec witness-union and middleware error-response tests
LukaszRozmej May 22, 2026
2035776
address review nits — uint32 offsets, namespace match
LukaszRozmej May 22, 2026
b7592f0
fold witness registry into proxy; drop registry param from BranchProc…
LukaszRozmej May 22, 2026
9b68f6a
inject witness handler directly into SszMiddleware; logger one-liners…
LukaszRozmej May 22, 2026
624fe3a
move witness arm/drain out of BranchProcessor; collapse IWitnessCaptu…
LukaszRozmej May 22, 2026
1c81852
remove unused usings flagged by IDE0005 in CI
LukaszRozmej May 22, 2026
45979e8
Collapse witness Arm/Drain into per-call recorder
LukaszRozmej May 22, 2026
891debf
remove unused Nethermind.Logging using flagged by IDE0005 in CI
LukaszRozmej May 22, 2026
b67b746
drop unused Nethermind.State using from witness proxy
LukaszRozmej May 22, 2026
73c86cc
wip: integrate new EEST tests
Dyslex7c May 23, 2026
c0a7e14
fix pyspec zkevm tests
Dyslex7c May 25, 2026
4eaa290
fix ci build error
Dyslex7c May 25, 2026
3295932
fix ci build error ethereum tests
Dyslex7c May 25, 2026
678540b
fixing failing zkevm tests checkpoint
Dyslex7c May 26, 2026
581ffcd
fix zkevm failing tests
Dyslex7c May 26, 2026
31c7d04
update known failing tests
Dyslex7c May 27, 2026
a3ec13e
use known-failing-hive-tests.txt
Dyslex7c May 27, 2026
2aad6ea
Merge remote-tracking branch 'origin/master' into new-payload-with-wi…
LukaszRozmej May 27, 2026
ecebc49
Merge remote-tracking branch 'origin/master' into new-payload-with-wi…
LukaszRozmej May 27, 2026
c13e577
Merge remote-tracking branch 'origin/master' into new-payload-with-wi…
LukaszRozmej May 27, 2026
bb6f8d8
fix zkevm tests after merge
Dyslex7c May 27, 2026
80e9198
use `_innerWorldState.RecordBytecodeAccess directly`
Dyslex7c May 28, 2026
ec15292
use `WitnessCapturingTrieStore`
Dyslex7c May 28, 2026
861b3b8
Merge remote-tracking branch 'origin/master' into pr-11623
LukaszRozmej Jun 2, 2026
b9fae05
fix(merge): forward IWorldState.HintBal in WitnessCapturingWorldState…
LukaszRozmej Jun 2, 2026
dbe9a8f
Merge branch 'master' into new-payload-with-witness-ssz
hudem1 Jun 9, 2026
48ce9c4
chore: Remove stale amsterdam tests folder
hudem1 Jun 9, 2026
ee86148
chore: Remove partial pyspec zkevm tests support
hudem1 Jun 9, 2026
51b7e31
chore: Remove partial witness recording fixes
hudem1 Jun 9, 2026
d93e81f
chore: Create WitnessCapturingTrieStore directly where needed
hudem1 Jun 9, 2026
35b8d8f
fix: Wire capturing trie store + capturing header finder + no-cache C…
hudem1 Jun 12, 2026
02c5ec0
fix: Use WitnessExecutionPredicate for BAL
hudem1 Jun 15, 2026
fe7a6a7
fix: Record trie nodes on flat db via ITrieNodeReadObserver
hudem1 Jun 15, 2026
7c94a7d
Merge branch 'master' into new-payload-with-witness-ssz
hudem1 Jun 15, 2026
20d6be0
fix: Remove double container configuration in tests
hudem1 Jun 15, 2026
2673738
fix: Register only a distinct instance of each block validation and m…
hudem1 Jun 15, 2026
ae9e585
fix: Format
hudem1 Jun 15, 2026
65073e0
temporary: logs for debugging tests on CI
hudem1 Jun 15, 2026
040db57
Revert "temporary: logs for debugging tests on CI"
hudem1 Jun 17, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
using Nethermind.Int256;
using Nethermind.Logging;
using Nethermind.State;
using Nethermind.Consensus.Stateless;

namespace Nethermind.Consensus.Processing;

Expand Down Expand Up @@ -86,7 +87,7 @@ static ParallelTxProcessorWithWorldStateManager()
private readonly ILogManager _logManager;
private readonly ObjectPool<IReadOnlyTxProcessorSource>? _parentReaderEnvPool;
private int _processorCount;
private readonly bool _witnessMode;
private readonly Func<bool>? _isWitnessExecution;

public ParallelTxProcessorWithWorldStateManager(
IBlockhashProvider blockHashProvider,
Expand All @@ -96,13 +97,13 @@ public ParallelTxProcessorWithWorldStateManager(
PrewarmerEnvFactory? prewarmerEnvFactory,
PreBlockCaches? preBlockCaches,
IReadOnlyTxProcessingEnvFactory? readOnlyTxProcessingEnvFactory,
bool witnessMode)
Func<bool>? isWitnessExecution)
{
_blockHashProvider = blockHashProvider;
_specProvider = specProvider;
_stateProvider = stateProvider;
_logManager = logManager;
_witnessMode = witnessMode;
_isWitnessExecution = isWitnessExecution;
_parentReaderEnvPool = CreateParentReaderEnvPool(prewarmerEnvFactory, preBlockCaches, readOnlyTxProcessingEnvFactory);
for (int i = 0; i < ProcessorPoolSize; i++)
{
Expand Down Expand Up @@ -226,7 +227,7 @@ private int ClampBalIndex(uint balIndex)
=> (int)uint.Min(balIndex, (uint)_lastBalIndex);

private TxProcessorWithWorldState NewProcessor()
=> new(true, _blockHashProvider, _specProvider, _stateProvider, _logManager, _witnessMode);
=> new(true, _blockHashProvider, _specProvider, _stateProvider, _logManager, _isWitnessExecution);

private TxProcessorWithWorldState RentProcessor()
{
Expand Down Expand Up @@ -333,9 +334,9 @@ public SequentialTxProcessorWithWorldStateManager(
ISpecProvider specProvider,
IWorldState stateProvider,
ILogManager logManager,
bool witnessMode)
Func<bool>? isWitnessExecution)
{
_txProcessorWithWorldState = new(false, blockHashProvider, specProvider, stateProvider, logManager, witnessMode);
_txProcessorWithWorldState = new(false, blockHashProvider, specProvider, stateProvider, logManager, isWitnessExecution);
_txProcessorWithWorldState.WorldState.SetGeneratingBlockAccessList(new());
}

Expand Down Expand Up @@ -377,7 +378,7 @@ public TxProcessorWithWorldState(
ISpecProvider specProvider,
IWorldState stateProvider,
ILogManager logManager,
bool witnessMode)
Func<bool>? isWitnessExecution)
{

VirtualMachine virtualMachine = new(blockHashProvider, specProvider, logManager);
Expand All @@ -388,12 +389,14 @@ public TxProcessorWithWorldState(
worldState = _balWorldState;
}
WorldState = new TracedAccessWorldState(worldState, parallel);
// Witness mode must record every code access, so it uses the non-caching CodeInfoRepository.
// EthereumCodeInfoRepository wraps a CacheCodeInfoRepository whose process-wide static code
// cache serves hits without reading through the (traced) WorldState, so cached code accesses
// would be missing from the generated witness.
ICodeInfoRepository codeInfoRepository = witnessMode
? new CodeInfoRepository(WorldState, new EthereumPrecompileProvider())
// On witness-capable managers, route code lookups through CodeInfoRepositoryProxy: while a
// witness is being executed (predicate true) it uses the non-caching CodeInfoRepository so
// every code access flows through the (traced) WorldState; otherwise it uses the cached repo.
// The process-wide static code cache would otherwise serve hits without reading through the
// WorldState, dropping those accesses from the witness. Non-witness managers use the cached
// repo directly with no per-call indirection.
ICodeInfoRepository codeInfoRepository = isWitnessExecution is not null
? new CodeInfoRepositoryProxy(new EthereumCodeInfoRepository(WorldState), WorldState, new EthereumPrecompileProvider(), isWitnessExecution)
: new EthereumCodeInfoRepository(WorldState);
TxProcessor = new(BlobBaseFeeCalculator.Instance, specProvider, WorldState, virtualMachine, codeInfoRepository, logManager, parallel);
TxProcessorAdapter = new(TxProcessor);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,17 +47,17 @@ public partial class BlockAccessListManager(
PrewarmerEnvFactory? prewarmerEnvFactory = null,
PreBlockCaches? preBlockCaches = null,
IReadOnlyTxProcessingEnvFactory? readOnlyTxProcessingEnvFactory = null,
bool witnessMode = false)
Func<bool>? isWitnessExecution = null)
: IBlockAccessListManager, IDisposable
{
private readonly ILogger _logger = logManager.GetClassLogger<BlockAccessListManager>();
private BlockExecutionContext? _blockExecutionContext;
private ITxProcessorWithWorldStateManager? _txProcessorWithWorldStateManager;
private Task? _balWarmupTask;
private readonly Lazy<ParallelTxProcessorWithWorldStateManager> _parallelTxProcessorWithWorldStateManager =
new(() => new(blockHashProvider, specProvider, stateProvider, logManager, prewarmerEnvFactory, preBlockCaches, readOnlyTxProcessingEnvFactory, witnessMode));
new(() => new(blockHashProvider, specProvider, stateProvider, logManager, prewarmerEnvFactory, preBlockCaches, readOnlyTxProcessingEnvFactory, isWitnessExecution));
private readonly Lazy<SequentialTxProcessorWithWorldStateManager> _sequentialTxProcessorWithWorldStateManager =
new(() => new(blockHashProvider, specProvider, stateProvider, logManager, witnessMode));
new(() => new(blockHashProvider, specProvider, stateProvider, logManager, isWitnessExecution));
private const int GasValidationChunkSize = 8;
private long? _gasRemaining;
private bool _isBuilding;
Expand Down Expand Up @@ -124,11 +124,17 @@ public void PrepareForProcessing(Block suggestedBlock, IReleaseSpec spec, Proces

// Parallel execution needs the decoded BAL body (RLP fixtures only carry the hash)
// and an active state scope (so we can capture the parent state root for workers).
//
// Witness execution forces sequential: parallel workers read pre-state through pooled
// parent-reader snapshots that bypass the capturing world-state proxy, so their accesses
// would be missing from the witness. Evaluated per block via the predicate so regular
// blocks on EIP-7928 chains keep parallel execution.
ParallelExecutionEnabled = Enabled
&& blocksConfig.ParallelExecution
&& !_isBuilding
&& suggestedBlock.BlockAccessList is not null
&& stateProvider.IsInScope;
&& stateProvider.IsInScope
&& isWitnessExecution?.Invoke() is not true;

// BAL-driven read warming: mirrors BlockCachePreWarmer.IsBalReadWarmingEnabled so
// HintBal honours the same opt-in config as the prewarmer path.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// SPDX-FileCopyrightText: 2026 Demerzel Solutions Limited
// SPDX-License-Identifier: LGPL-3.0-only

using System;
using System.Diagnostics.CodeAnalysis;
using Nethermind.Core;
using Nethermind.Core.Specs;
using Nethermind.Evm;
using Nethermind.Evm.CodeAnalysis;
using Nethermind.Evm.State;

namespace Nethermind.Consensus.Stateless;

/// <summary>
/// Thin <see cref="ICodeInfoRepository"/> decorator that routes every call to a non-caching
/// <see cref="CodeInfoRepository"/> it owns when <paramref name="useNonCaching"/> returns <c>true</c>,
/// and to the wrapped cached repository otherwise. The predicate is evaluated per call so the choice
/// tracks the live witness-execution state rather than being fixed at construction.
/// </summary>
/// <remarks>
/// Witness execution requires every bytecode/code-hash lookup to flow through <see cref="IWorldState"/>
/// (so a recording world state observes it, or so stateless execution stays isolated to the witness);
/// the process-wide static code cache used by the inner repository would short-circuit those reads.
/// The non-caching repository is built inside this decorator (rather than resolved from DI) so no other
/// DI consumer can pick it up and accidentally bypass the cache for non-witness blocks.
/// </remarks>
public sealed class CodeInfoRepositoryProxy(
ICodeInfoRepository inner,
IWorldState worldState,
IPrecompileProvider precompileProvider,
Func<bool> useNonCaching) : ICodeInfoRepository
{
private readonly ICodeInfoRepository _inner = inner;
private readonly CodeInfoRepository _nonCached = new(worldState, precompileProvider);

private ICodeInfoRepository Current => useNonCaching() ? _nonCached : _inner;

public CodeInfo GetCachedCodeInfo(Address codeSource, bool followDelegation, IReleaseSpec vmSpec, out Address? delegationAddress)
=> Current.GetCachedCodeInfo(codeSource, followDelegation, vmSpec, out delegationAddress);

public void InsertCode(ReadOnlyMemory<byte> code, Address codeOwner, IReleaseSpec spec)
=> Current.InsertCode(code, codeOwner, spec);

public void SetDelegation(Address codeSource, Address authority, IReleaseSpec spec)
=> Current.SetDelegation(codeSource, authority, spec);

public bool TryGetDelegation(Address address, IReleaseSpec spec, [NotNullWhen(true)] out Address? delegatedAddress)
=> Current.TryGetDelegation(address, spec, out delegatedAddress);
}
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,9 @@ private BlockProcessor GetProcessor()
ParallelExecutionBatchRead = false
},
new WithdrawalProcessorFactory(logManager),
witnessMode: true
// Stateless execution must resolve code only from the witness-backed state, never the
// shared cache — so it always runs in witness mode (non-caching code reads).
isWitnessExecution: static () => true
);
BlockProcessor.ParallelBlockValidationTransactionsExecutor txExecutor = new(
new BlockProcessor.BlockValidationTransactionsExecutor(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// SPDX-FileCopyrightText: 2026 Demerzel Solutions Limited
// SPDX-License-Identifier: LGPL-3.0-only

using System.Threading;

namespace Nethermind.Consensus.Stateless;

/// <summary>
/// Per-main-processing-scope arming point for witness capture. Holds nullable pointers to the
/// recorders that are active during a single <c>ProcessOne</c> call; the decorators
/// (<see cref="WitnessCapturingWorldStateProxy"/>, <see cref="WitnessCapturingTrieStore"/>,
/// <see cref="WitnessCapturingHeaderFinder"/>) consult these pointers on every call and forward
/// straight through to the inner component when null.
/// </summary>
/// <remarks>
/// <para>
/// Single arm/disarm point in <see cref="WitnessCapturingBlockProcessor"/> replaces the previous
/// per-decorator <c>TryActivate</c>/<c>Deactivate</c> ceremony: all three decorators become dumb
/// passthroughs that share one source of truth here.
/// </para>
/// <para>
/// Thread-safety: <see cref="TryArm"/> uses CAS on the world-state pointer so concurrent armers
/// see at most one winner; <see cref="Disarm"/> clears in reverse so any consumer that still sees
/// <see cref="WorldStateRecorder"/> set also sees the other recorders set. The main processing
/// pipeline drives blocks serially so contention is theoretical, but the volatile reads remain
/// safe under any caller.
/// </para>
/// </remarks>
public sealed class WitnessCaptureSession
{
private WitnessGeneratingWorldState? _worldStateRecorder;
private WitnessHeaderRecorder? _headerRecorder;
private WitnessTrieStoreRecorder? _trieRecorder;

public WitnessGeneratingWorldState? WorldStateRecorder => Volatile.Read(ref _worldStateRecorder);
public WitnessHeaderRecorder? HeaderRecorder => Volatile.Read(ref _headerRecorder);
public WitnessTrieStoreRecorder? TrieRecorder => Volatile.Read(ref _trieRecorder);

public bool IsActive => WorldStateRecorder is not null;

/// <summary>
/// Atomically installs the three recorders for a single capture pass. Returns <c>false</c>
/// when a capture is already in progress on this session.
/// </summary>
/// <remarks>
/// The world-state recorder is the primary slot — the CAS on it gates the operation; the other
/// two are written under the post-CAS happens-before, so any reader that observes the
/// world-state recorder also observes the header and trie recorders.
/// </remarks>
public bool TryArm(
WitnessGeneratingWorldState worldStateRecorder,
WitnessHeaderRecorder headerRecorder,
WitnessTrieStoreRecorder trieRecorder)
{
Volatile.Write(ref _trieRecorder, trieRecorder);
Volatile.Write(ref _headerRecorder, headerRecorder);
return Interlocked.CompareExchange(ref _worldStateRecorder, worldStateRecorder, null) is null;
}

public void Disarm()
{
Volatile.Write(ref _worldStateRecorder, null);
Volatile.Write(ref _headerRecorder, null);
Volatile.Write(ref _trieRecorder, null);
}
}
Loading
Loading