From cdad65bca0445c4ff1e2cbc77daaa73b6a32b584 Mon Sep 17 00:00:00 2001
From: Marc Harvey-Hill <10379486+Marchhill@users.noreply.github.com>
Date: Wed, 1 Oct 2025 15:35:51 +0100
Subject: [PATCH 01/26] initial commit
---
.../Ethereum.Test.Base/BlockchainTest.cs | 1 +
.../Ethereum.Test.Base/BlockchainTestBase.cs | 152 +++++++-----
.../Ethereum.Test.Base/BlockchainTestJson.cs | 1 +
.../Ethereum.Test.Base/JsonToEthereumTest.cs | 232 +++++++++++-------
.../Ethereum.Test.Base/TestBlockHeaderJson.cs | 7 +
.../TestEngineNewPayloadsJson.cs | 45 ++++
.../BeaconBlockRootHandlerTests.cs | 2 -
.../ExecutionRequestsProcessorMock.cs | 1 -
.../Nethermind.Merge.Plugin/MergePlugin.cs | 2 +-
.../NoEngineRequestTracker.cs | 17 ++
.../StateProviderTests.cs | 2 -
.../BlockchainTestsRunner.cs | 13 +-
12 files changed, 326 insertions(+), 149 deletions(-)
create mode 100644 src/Nethermind/Ethereum.Test.Base/TestEngineNewPayloadsJson.cs
create mode 100644 src/Nethermind/Nethermind.Merge.Plugin/NoEngineRequestTracker.cs
diff --git a/src/Nethermind/Ethereum.Test.Base/BlockchainTest.cs b/src/Nethermind/Ethereum.Test.Base/BlockchainTest.cs
index 19f62afb8007..b4f78c9a0579 100644
--- a/src/Nethermind/Ethereum.Test.Base/BlockchainTest.cs
+++ b/src/Nethermind/Ethereum.Test.Base/BlockchainTest.cs
@@ -20,6 +20,7 @@ public class BlockchainTest : EthereumTest
public TestBlockJson[]? Blocks { get; set; }
public TestBlockHeaderJson? GenesisBlockHeader { get; set; }
+ public TestEngineNewPayloadsJson[]? EngineNewPayloads { get; set; }
public Dictionary
? Pre { get; set; }
public Dictionary? PostState { get; set; }
diff --git a/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs b/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs
index 55e59e9e10c0..129fef10d8c3 100644
--- a/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs
+++ b/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs
@@ -9,7 +9,6 @@
using System.Threading;
using System.Threading.Tasks;
using Autofac;
-using Nethermind.Api;
using Nethermind.Blockchain;
using Nethermind.Blockchain.Find;
using Nethermind.Config;
@@ -30,26 +29,25 @@
using Nethermind.Specs;
using Nethermind.Specs.Forks;
using Nethermind.Specs.Test;
-using Nethermind.State;
using Nethermind.Evm.State;
using Nethermind.Init.Modules;
using Nethermind.TxPool;
using NUnit.Framework;
+using Nethermind.Merge.Plugin.Data;
+using Nethermind.Merge.Plugin;
+using Nethermind.JsonRpc;
namespace Ethereum.Test.Base;
public abstract class BlockchainTestBase
{
- private static ILogger _logger;
- private static ILogManager _logManager = new TestLogManager(LogLevel.Warn);
- private static ISealValidator Sealer { get; }
+ private static readonly ILogger _logger;
+ private static readonly ILogManager _logManager = new TestLogManager(LogLevel.Warn);
private static DifficultyCalculatorWrapper DifficultyCalculator { get; }
static BlockchainTestBase()
{
DifficultyCalculator = new DifficultyCalculatorWrapper();
- Sealer = new EthashSealValidator(_logManager, DifficultyCalculator, new CryptoRandom(), new Ethash(_logManager), Timestamper.Default); // temporarily keep reusing the same one as otherwise it would recreate cache for each test
-
_logManager ??= LimboLogs.Instance;
_logger = _logManager.GetClassLogger();
}
@@ -129,6 +127,7 @@ protected async Task RunTest(BlockchainTest test, Stopwatch?
// configProvider.GetConfig().PreWarmStateOnBlockProcessing = false;
await using IContainer container = new ContainerBuilder()
.AddModule(new TestNethermindModule(configProvider))
+ .AddModule(new TestMergeModule(configProvider))
.AddSingleton(specProvider)
.AddSingleton(_logManager)
.AddSingleton(rewardCalculator)
@@ -141,9 +140,11 @@ protected async Task RunTest(BlockchainTest test, Stopwatch?
IBlockchainProcessor blockchainProcessor = mainBlockProcessingContext.BlockchainProcessor;
IBlockTree blockTree = container.Resolve();
IBlockValidator blockValidator = container.Resolve();
+ IEngineRpcModule engineRpcModule = container.Resolve();
blockchainProcessor.Start();
BlockHeader parentHeader;
+ (ExecutionPayload, string[]?, string[]?, string?)[] payloads;
// Genesis processing
using (stateProvider.BeginScope(null))
{
@@ -154,15 +155,18 @@ protected async Task RunTest(BlockchainTest test, Stopwatch?
test.GenesisRlp ??= Rlp.Encode(new Block(JsonToEthereumTest.Convert(test.GenesisBlockHeader)));
Block genesisBlock = Rlp.Decode(test.GenesisRlp.Bytes);
+ // Console.WriteLine(genesisBlock.ToString(Block.Format.Full));
Assert.That(genesisBlock.Header.Hash, Is.EqualTo(new Hash256(test.GenesisBlockHeader.Hash)));
+ payloads = [.. JsonToEthereumTest.Convert(test.EngineNewPayloads)];
+
ManualResetEvent genesisProcessed = new(false);
blockTree.NewHeadBlock += (_, args) =>
{
if (args.Block.Number == 0)
{
- Assert.That(stateProvider.HasStateForBlock(genesisBlock.Header), Is.EqualTo(true));
+ Assert.That(stateProvider.HasStateForBlock(genesisBlock.Header), Is.True);
genesisProcessed.Set();
}
};
@@ -170,11 +174,72 @@ protected async Task RunTest(BlockchainTest test, Stopwatch?
blockTree.SuggestBlock(genesisBlock);
genesisProcessed.WaitOne();
parentHeader = genesisBlock.Header;
+ }
+
+ if (test.Blocks is not null)
+ {
+ // blockchain test
+ parentHeader = SuggestBlocks(test, failOnInvalidRlp, blockValidator, blockTree, parentHeader);
+ }
+ else if (test.EngineNewPayloads is not null)
+ {
+ // blockchain test engine
+ foreach ((ExecutionPayload executionPayload, string[]? blobVersionedHashes, string[]? validationError, string? newPayloadVersion) in payloads)
+ {
+ ResultWrapper res;
+ switch (newPayloadVersion ?? "4")
+ {
+ case "1":
+ res = await engineRpcModule.engine_newPayloadV1(executionPayload);
+ break;
+ case "2":
+ res = await engineRpcModule.engine_newPayloadV2(executionPayload);
+ break;
+ case "3":
+ res = await engineRpcModule.engine_newPayloadV3((ExecutionPayloadV3)executionPayload, [], executionPayload.ParentBeaconBlockRoot);
+ break;
+ case "4":
+ byte[]?[] hashes = blobVersionedHashes is null ? null : [.. blobVersionedHashes.Select(x => Bytes.FromHexString(x))];
+ res = await engineRpcModule.engine_newPayloadV4((ExecutionPayloadV3)executionPayload, hashes, executionPayload.ParentBeaconBlockRoot, []);
+ break;
+ default:
+ Assert.Fail("Invalid blockchain engine test, version not recognised.");
+ break;
+ }
+ }
+ }
+ else
+ {
+ Assert.Fail("Invalid blockchain test, did not contain blocks or new payloads.");
+ }
+
+ await blockchainProcessor.StopAsync(true);
+ stopwatch?.Stop();
+
+ IBlockCachePreWarmer? preWarmer = container.Resolve().LifetimeScope.ResolveOptional();
- // Dispose genesis block's AccountChanges
- genesisBlock.DisposeAccountChanges();
+ // Caches are cleared async, which is a problem as read for the MainWorldState with prewarmer is not correct if its not cleared.
+ preWarmer?.ClearCaches();
+
+ Block? headBlock = blockTree.RetrieveHeadBlock();
+ List differences;
+ using (stateProvider.BeginScope(headBlock.Header))
+ {
+ differences = RunAssertions(test, blockTree.RetrieveHeadBlock(), stateProvider);
}
+ Assert.That(differences, Is.Empty, "differences");
+
+ return new EthereumTestResult
+ (
+ test.Name,
+ null,
+ differences.Count == 0
+ );
+ }
+
+ private static BlockHeader SuggestBlocks(BlockchainTest test, bool failOnInvalidRlp, IBlockValidator blockValidator, IBlockTree blockTree, BlockHeader parentHeader)
+ {
List<(Block Block, string ExpectedException)> correctRlp = DecodeRlps(test, failOnInvalidRlp);
for (int i = 0; i < correctRlp.Count; i++)
{
@@ -210,52 +275,26 @@ protected async Task RunTest(BlockchainTest test, Stopwatch?
{
Assert.Fail($"Unexpected exception during processing: {e}");
}
- finally
- {
- // Dispose AccountChanges to prevent memory leaks in tests
- correctRlp[i].Block.DisposeAccountChanges();
- }
parentHeader = correctRlp[i].Block.Header;
}
- await blockchainProcessor.StopAsync(true);
- stopwatch?.Stop();
-
- IBlockCachePreWarmer? preWarmer = container.Resolve().LifetimeScope.ResolveOptional();
- if (preWarmer is not null)
- {
- // Caches are cleared async, which is a problem as read for the MainWorldState with prewarmer is not correct if its not cleared.
- preWarmer.ClearCaches();
- }
-
- Block? headBlock = blockTree.RetrieveHeadBlock();
- List differences;
- using (stateProvider.BeginScope(headBlock.Header))
- {
- differences = RunAssertions(test, blockTree.RetrieveHeadBlock(), stateProvider);
- }
-
- Assert.That(differences.Count, Is.Zero, "differences");
-
- return new EthereumTestResult
- (
- test.Name,
- null,
- differences.Count == 0
- );
+ return parentHeader;
}
- private List<(Block Block, string ExpectedException)> DecodeRlps(BlockchainTest test, bool failOnInvalidRlp)
+ private static List<(Block Block, string ExpectedException)> DecodeRlps(BlockchainTest test, bool failOnInvalidRlp)
{
- List<(Block Block, string ExpectedException)> correctRlp = new();
+ List<(Block Block, string ExpectedException)> correctRlp = [];
for (int i = 0; i < test.Blocks.Length; i++)
{
TestBlockJson testBlockJson = test.Blocks[i];
try
{
- var rlpContext = Bytes.FromHexString(testBlockJson.Rlp).AsRlpStream();
+ RlpStream rlpContext = Bytes.FromHexString(testBlockJson.Rlp).AsRlpStream();
Block suggestedBlock = Rlp.Decode(rlpContext);
+ // Console.WriteLine("suggested block:");
+ // Console.WriteLine(suggestedBlock.BlockAccessList);
+ // Hash256 tmp = new(ValueKeccak.Compute(Rlp.Encode(suggestedBlock.BlockAccessList!.Value).Bytes).Bytes);
suggestedBlock.Header.SealEngineType =
test.SealEngineUsed ? SealEngineType.Ethash : SealEngineType.None;
@@ -296,17 +335,20 @@ protected async Task RunTest(BlockchainTest test, Stopwatch?
if (correctRlp.Count == 0)
{
- Assert.That(test.GenesisBlockHeader, Is.Not.Null);
- Assert.That(test.LastBlockHash, Is.EqualTo(new Hash256(test.GenesisBlockHeader.Hash)));
+ using (Assert.EnterMultipleScope())
+ {
+ Assert.That(test.GenesisBlockHeader, Is.Not.Null);
+ Assert.That(test.LastBlockHash, Is.EqualTo(new Hash256(test.GenesisBlockHeader.Hash)));
+ }
}
return correctRlp;
}
- private void InitializeTestState(BlockchainTest test, IWorldState stateProvider, ISpecProvider specProvider)
+ private static void InitializeTestState(BlockchainTest test, IWorldState stateProvider, ISpecProvider specProvider)
{
foreach (KeyValuePair accountState in
- ((IEnumerable>)test.Pre ?? Array.Empty>()))
+ (IEnumerable>)test.Pre ?? Array.Empty>())
{
foreach (KeyValuePair storageItem in accountState.Value.Storage)
{
@@ -324,18 +366,18 @@ private void InitializeTestState(BlockchainTest test, IWorldState stateProvider,
stateProvider.Reset();
}
- private List RunAssertions(BlockchainTest test, Block headBlock, IWorldState stateProvider)
+ private static List RunAssertions(BlockchainTest test, Block headBlock, IWorldState stateProvider)
{
if (test.PostStateRoot is not null)
{
- return test.PostStateRoot != stateProvider.StateRoot ? new List { "state root mismatch" } : Enumerable.Empty().ToList();
+ return test.PostStateRoot != stateProvider.StateRoot ? ["state root mismatch"] : [];
}
TestBlockHeaderJson testHeaderJson = (test.Blocks?
.Where(b => b.BlockHeader is not null)
.SingleOrDefault(b => new Hash256(b.BlockHeader.Hash) == headBlock.Hash)?.BlockHeader) ?? test.GenesisBlockHeader;
BlockHeader testHeader = JsonToEthereumTest.Convert(testHeaderJson);
- List differences = new();
+ List differences = [];
IEnumerable> deletedAccounts = test.Pre?
.Where(pre => !(test.PostState?.ContainsKey(pre.Key) ?? false)) ?? Array.Empty>();
@@ -359,8 +401,8 @@ private List RunAssertions(BlockchainTest test, Block headBlock, IWorldS
}
bool accountExists = stateProvider.AccountExists(acountAddress);
- UInt256? balance = accountExists ? stateProvider.GetBalance(acountAddress) : (UInt256?)null;
- UInt256? nonce = accountExists ? stateProvider.GetNonce(acountAddress) : (UInt256?)null;
+ UInt256? balance = accountExists ? stateProvider.GetBalance(acountAddress) : null;
+ UInt256? nonce = accountExists ? stateProvider.GetNonce(acountAddress) : null;
if (accountState.Balance != balance)
{
@@ -372,7 +414,7 @@ private List RunAssertions(BlockchainTest test, Block headBlock, IWorldS
differences.Add($"{acountAddress} nonce exp: {accountState.Nonce}, actual: {nonce}");
}
- byte[] code = accountExists ? stateProvider.GetCode(acountAddress) : new byte[0];
+ byte[] code = accountExists ? stateProvider.GetCode(acountAddress) : [];
if (!Bytes.AreEqual(accountState.Code, code))
{
differences.Add($"{acountAddress} code exp: {accountState.Code?.Length}, actual: {code?.Length}");
@@ -385,10 +427,10 @@ private List RunAssertions(BlockchainTest test, Block headBlock, IWorldS
differencesBefore = differences.Count;
- KeyValuePair[] clearedStorages = new KeyValuePair[0];
+ KeyValuePair[] clearedStorages = [];
if (test.Pre.ContainsKey(acountAddress))
{
- clearedStorages = test.Pre[acountAddress].Storage.Where(s => !accountState.Storage.ContainsKey(s.Key)).ToArray();
+ clearedStorages = [.. test.Pre[acountAddress].Storage.Where(s => !accountState.Storage.ContainsKey(s.Key))];
}
foreach (KeyValuePair clearedStorage in clearedStorages)
diff --git a/src/Nethermind/Ethereum.Test.Base/BlockchainTestJson.cs b/src/Nethermind/Ethereum.Test.Base/BlockchainTestJson.cs
index fdd03858fd8c..c344cd773da7 100644
--- a/src/Nethermind/Ethereum.Test.Base/BlockchainTestJson.cs
+++ b/src/Nethermind/Ethereum.Test.Base/BlockchainTestJson.cs
@@ -24,6 +24,7 @@ public class BlockchainTestJson
public TestBlockJson[]? Blocks { get; set; }
public TestBlockHeaderJson? GenesisBlockHeader { get; set; }
+ public TestEngineNewPayloadsJson[]? EngineNewPayloads { get; set; }
public Dictionary? Pre { get; set; }
public Dictionary? PostState { get; set; }
diff --git a/src/Nethermind/Ethereum.Test.Base/JsonToEthereumTest.cs b/src/Nethermind/Ethereum.Test.Base/JsonToEthereumTest.cs
index 9a09b17017c1..432156d5dcc2 100644
--- a/src/Nethermind/Ethereum.Test.Base/JsonToEthereumTest.cs
+++ b/src/Nethermind/Ethereum.Test.Base/JsonToEthereumTest.cs
@@ -5,6 +5,7 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
+using System.Text.Json;
using Nethermind.Config;
using Nethermind.Core;
using Nethermind.Core.Crypto;
@@ -14,6 +15,7 @@
using Nethermind.Crypto;
using Nethermind.Evm.EvmObjectFormat;
using Nethermind.Int256;
+using Nethermind.Merge.Plugin.Data;
using Nethermind.Serialization.Json;
using Nethermind.Serialization.Rlp;
using Nethermind.Specs;
@@ -56,36 +58,84 @@ public static BlockHeader Convert(TestBlockHeaderJson? headerJson)
(long)Bytes.FromHexString(headerJson.Number).ToUInt256(),
(long)Bytes.FromHexString(headerJson.GasLimit).ToUnsignedBigInteger(),
(ulong)Bytes.FromHexString(headerJson.Timestamp).ToUnsignedBigInteger(),
- Bytes.FromHexString(headerJson.ExtraData)
- );
-
- header.Bloom = new Bloom(Bytes.FromHexString(headerJson.Bloom));
- header.GasUsed = (long)Bytes.FromHexString(headerJson.GasUsed).ToUnsignedBigInteger();
- header.Hash = new Hash256(headerJson.Hash);
- header.MixHash = new Hash256(headerJson.MixHash);
- header.Nonce = (ulong)Bytes.FromHexString(headerJson.Nonce).ToUnsignedBigInteger();
- header.ReceiptsRoot = new Hash256(headerJson.ReceiptTrie);
- header.StateRoot = new Hash256(headerJson.StateRoot);
- header.TxRoot = new Hash256(headerJson.TransactionsTrie);
+ Bytes.FromHexString(headerJson.ExtraData),
+ headerJson.BlobGasUsed is null ? null : (ulong)Bytes.FromHexString(headerJson.BlobGasUsed).ToUnsignedBigInteger(),
+ headerJson.ExcessBlobGas is null ? null : (ulong)Bytes.FromHexString(headerJson.ExcessBlobGas).ToUnsignedBigInteger(),
+ headerJson.ParentBeaconBlockRoot is null ? null : new Hash256(headerJson.ParentBeaconBlockRoot),
+ headerJson.RequestsHash is null ? null : new Hash256(headerJson.RequestsHash)
+ )
+ {
+ Bloom = new Bloom(Bytes.FromHexString(headerJson.Bloom)),
+ GasUsed = (long)Bytes.FromHexString(headerJson.GasUsed).ToUnsignedBigInteger(),
+ Hash = new Hash256(headerJson.Hash),
+ MixHash = new Hash256(headerJson.MixHash),
+ Nonce = (ulong)Bytes.FromHexString(headerJson.Nonce).ToUnsignedBigInteger(),
+ ReceiptsRoot = new Hash256(headerJson.ReceiptTrie),
+ StateRoot = new Hash256(headerJson.StateRoot),
+ TxRoot = new Hash256(headerJson.TransactionsTrie),
+ WithdrawalsRoot = headerJson.WithdrawalsRoot is null ? null : new Hash256(headerJson.WithdrawalsRoot),
+ BlockAccessListHash = headerJson.BlockAccessListHash is null ? null : new Hash256(headerJson.BlockAccessListHash),
+ BaseFeePerGas = (ulong)Bytes.FromHexString(headerJson.BaseFeePerGas).ToUnsignedBigInteger()
+ };
return header;
}
+ public static IEnumerable<(ExecutionPayload, string[]?, string[]?, string?)> Convert(TestEngineNewPayloadsJson[]? executionPayloadsJson)
+ {
+ if (executionPayloadsJson is null)
+ {
+ throw new InvalidDataException("Execution payloads JSON was null when constructing test.");
+ }
+
+ foreach (TestEngineNewPayloadsJson engineNewPayload in executionPayloadsJson)
+ {
+ TestEngineNewPayloadsJson.ParamsExecutionPayload executionPayload = engineNewPayload.Params[0].Deserialize(EthereumJsonSerializer.JsonOptions);
+ string[]? blobVersionedHashes = engineNewPayload.Params.Length > 1 ? engineNewPayload.Params[1].Deserialize(EthereumJsonSerializer.JsonOptions) : null;
+ string? parentBeaconBlockRoot = engineNewPayload.Params.Length > 2 ? engineNewPayload.Params[2].Deserialize(EthereumJsonSerializer.JsonOptions) : null;
+ string[]? validationError = engineNewPayload.Params.Length > 3 ? engineNewPayload.Params[3].Deserialize(EthereumJsonSerializer.JsonOptions) : null;
+ yield return (new ExecutionPayloadV3()
+ {
+ BaseFeePerGas = (ulong)Bytes.FromHexString(executionPayload.BaseFeePerGas).ToUnsignedBigInteger(),
+ BlockHash = new(executionPayload.BlockHash),
+ BlockNumber = (long)Bytes.FromHexString(executionPayload.BlockNumber).ToUnsignedBigInteger(),
+ ExtraData = Bytes.FromHexString(executionPayload.ExtraData),
+ FeeRecipient = new(executionPayload.FeeRecipient),
+ GasLimit = (long)Bytes.FromHexString(executionPayload.GasLimit).ToUnsignedBigInteger(),
+ GasUsed = (long)Bytes.FromHexString(executionPayload.GasUsed).ToUnsignedBigInteger(),
+ LogsBloom = new(Bytes.FromHexString(executionPayload.LogsBloom)),
+ ParentHash = new(executionPayload.ParentHash),
+ PrevRandao = new(executionPayload.PrevRandao),
+ ReceiptsRoot = new(executionPayload.ReceiptsRoot),
+ StateRoot = new(executionPayload.StateRoot),
+ Timestamp = (ulong)Bytes.FromHexString(executionPayload.Timestamp).ToUnsignedBigInteger(),
+ BlockAccessList = executionPayload.BlockAccessList is null ? null : Bytes.FromHexString(executionPayload.BlockAccessList),
+ BlobGasUsed = executionPayload.BlobGasUsed is null ? null : (ulong)Bytes.FromHexString(executionPayload.BlobGasUsed).ToUnsignedBigInteger(),
+ ExcessBlobGas = executionPayload.ExcessBlobGas is null ? null : (ulong)Bytes.FromHexString(executionPayload.ExcessBlobGas).ToUnsignedBigInteger(),
+ ParentBeaconBlockRoot = parentBeaconBlockRoot is null ? null : new(parentBeaconBlockRoot),
+ Withdrawals = executionPayload.Withdrawals is null ? null : [.. executionPayload.Withdrawals.Select(x => Rlp.Decode(Bytes.FromHexString(x)))],
+ Transactions = [.. executionPayload.Transactions.Select(x => Bytes.FromHexString(x))],
+ ExecutionRequests = []
+ }, blobVersionedHashes, validationError, engineNewPayload.NewPayloadVersion);
+ }
+ }
+
public static Transaction Convert(PostStateJson postStateJson, TransactionJson transactionJson)
{
- Transaction transaction = new();
-
- transaction.Type = transactionJson.Type;
- transaction.Value = transactionJson.Value[postStateJson.Indexes.Value];
- transaction.GasLimit = transactionJson.GasLimit[postStateJson.Indexes.Gas];
- transaction.GasPrice = transactionJson.GasPrice ?? transactionJson.MaxPriorityFeePerGas ?? 0;
- transaction.DecodedMaxFeePerGas = transactionJson.MaxFeePerGas ?? 0;
- transaction.Nonce = transactionJson.Nonce;
- transaction.To = transactionJson.To;
- transaction.Data = transactionJson.Data[postStateJson.Indexes.Data];
- transaction.SenderAddress = new PrivateKey(transactionJson.SecretKey).Address;
- transaction.Signature = new Signature(1, 1, 27);
- transaction.BlobVersionedHashes = transactionJson.BlobVersionedHashes;
- transaction.MaxFeePerBlobGas = transactionJson.MaxFeePerBlobGas;
+ Transaction transaction = new()
+ {
+ Type = transactionJson.Type,
+ Value = transactionJson.Value[postStateJson.Indexes.Value],
+ GasLimit = transactionJson.GasLimit[postStateJson.Indexes.Gas],
+ GasPrice = transactionJson.GasPrice ?? transactionJson.MaxPriorityFeePerGas ?? 0,
+ DecodedMaxFeePerGas = transactionJson.MaxFeePerGas ?? 0,
+ Nonce = transactionJson.Nonce,
+ To = transactionJson.To,
+ Data = transactionJson.Data[postStateJson.Indexes.Data],
+ SenderAddress = new PrivateKey(transactionJson.SecretKey).Address,
+ Signature = new Signature(1, 1, 27),
+ BlobVersionedHashes = transactionJson.BlobVersionedHashes,
+ MaxFeePerBlobGas = transactionJson.MaxFeePerBlobGas
+ };
transaction.Hash = transaction.CalculateHash();
AccessList.Builder builder = new();
@@ -108,7 +158,7 @@ public static Transaction Convert(PostStateJson postStateJson, TransactionJson t
if (transactionJson.AuthorizationList is not null)
{
transaction.AuthorizationList =
- transactionJson.AuthorizationList
+ [.. transactionJson.AuthorizationList
.Select(i =>
{
if (i.Nonce > ulong.MaxValue)
@@ -148,7 +198,7 @@ public static Transaction Convert(PostStateJson postStateJson, TransactionJson t
(byte)i.V,
r,
s);
- }).ToArray();
+ })];
if (transaction.AuthorizationList.Any())
{
transaction.Type = TxType.SetCode;
@@ -172,14 +222,16 @@ public static void ProcessAccessList(AccessListItemJson[]? accessList, AccessLis
public static Transaction Convert(LegacyTransactionJson transactionJson)
{
- Transaction transaction = new();
- transaction.Value = transactionJson.Value;
- transaction.GasLimit = transactionJson.GasLimit;
- transaction.GasPrice = transactionJson.GasPrice;
- transaction.Nonce = transactionJson.Nonce;
- transaction.To = transactionJson.To;
- transaction.Data = transactionJson.Data;
- transaction.Signature = new Signature(transactionJson.R, transactionJson.S, transactionJson.V);
+ Transaction transaction = new()
+ {
+ Value = transactionJson.Value,
+ GasLimit = transactionJson.GasLimit,
+ GasPrice = transactionJson.GasPrice,
+ Nonce = transactionJson.Nonce,
+ To = transactionJson.To,
+ Data = transactionJson.Data,
+ Signature = new Signature(transactionJson.R, transactionJson.S, transactionJson.V)
+ };
transaction.Hash = transaction.CalculateHash();
return transaction;
}
@@ -191,41 +243,42 @@ public static IEnumerable Convert(string name, string category
return Enumerable.Repeat(new GeneralStateTest { Name = name, Category = category, LoadFailure = testJson.LoadFailure }, 1);
}
- List blockchainTests = new();
+ List blockchainTests = [];
foreach (KeyValuePair postStateBySpec in testJson.Post)
{
int iterationNumber = 0;
foreach (PostStateJson stateJson in postStateBySpec.Value)
{
- GeneralStateTest test = new();
- test.Name = Path.GetFileName(name) +
- $"_d{stateJson.Indexes.Data}g{stateJson.Indexes.Gas}v{stateJson.Indexes.Value}_";
+ GeneralStateTest test = new()
+ {
+ Name = Path.GetFileName(name) +
+ $"_d{stateJson.Indexes.Data}g{stateJson.Indexes.Gas}v{stateJson.Indexes.Value}_",
+ Category = category,
+ ForkName = postStateBySpec.Key,
+ Fork = SpecNameParser.Parse(postStateBySpec.Key),
+ PreviousHash = testJson.Env.PreviousHash,
+ CurrentCoinbase = testJson.Env.CurrentCoinbase,
+ CurrentDifficulty = testJson.Env.CurrentDifficulty,
+ CurrentGasLimit = testJson.Env.CurrentGasLimit,
+ CurrentNumber = testJson.Env.CurrentNumber,
+ CurrentTimestamp = testJson.Env.CurrentTimestamp,
+ CurrentBaseFee = testJson.Env.CurrentBaseFee,
+ CurrentRandom = testJson.Env.CurrentRandom,
+ CurrentBeaconRoot = testJson.Env.CurrentBeaconRoot,
+ CurrentWithdrawalsRoot = testJson.Env.CurrentWithdrawalsRoot,
+ CurrentExcessBlobGas = testJson.Env.CurrentExcessBlobGas,
+ ParentBlobGasUsed = testJson.Env.ParentBlobGasUsed,
+ ParentExcessBlobGas = testJson.Env.ParentExcessBlobGas,
+ PostReceiptsRoot = stateJson.Logs,
+ PostHash = stateJson.Hash,
+ Pre = testJson.Pre.ToDictionary(p => p.Key, p => p.Value),
+ Transaction = Convert(stateJson, testJson.Transaction)
+ };
+
if (testJson.Info?.Labels?.ContainsKey(iterationNumber.ToString()) ?? false)
{
test.Name += testJson.Info?.Labels?[iterationNumber.ToString()]?.Replace(":label ", string.Empty);
}
- test.Category = category;
-
- test.ForkName = postStateBySpec.Key;
- test.Fork = SpecNameParser.Parse(postStateBySpec.Key);
- test.PreviousHash = testJson.Env.PreviousHash;
- test.CurrentCoinbase = testJson.Env.CurrentCoinbase;
- test.CurrentDifficulty = testJson.Env.CurrentDifficulty;
- test.CurrentGasLimit = testJson.Env.CurrentGasLimit;
- test.CurrentNumber = testJson.Env.CurrentNumber;
- test.CurrentTimestamp = testJson.Env.CurrentTimestamp;
- test.CurrentBaseFee = testJson.Env.CurrentBaseFee;
- test.CurrentRandom = testJson.Env.CurrentRandom;
- test.CurrentBeaconRoot = testJson.Env.CurrentBeaconRoot;
- test.CurrentWithdrawalsRoot = testJson.Env.CurrentWithdrawalsRoot;
- test.CurrentExcessBlobGas = testJson.Env.CurrentExcessBlobGas;
- test.ParentBlobGasUsed = testJson.Env.ParentBlobGasUsed;
- test.ParentExcessBlobGas = testJson.Env.ParentExcessBlobGas;
- test.PostReceiptsRoot = stateJson.Logs;
- test.PostHash = stateJson.Hash;
- test.Pre = testJson.Pre.ToDictionary(p => p.Key, p => p.Value);
- test.Transaction = Convert(stateJson, testJson.Transaction);
-
blockchainTests.Add(test);
++iterationNumber;
}
@@ -241,17 +294,20 @@ public static BlockchainTest Convert(string name, string category, BlockchainTes
return new BlockchainTest { Name = name, Category = category, LoadFailure = testJson.LoadFailure };
}
- BlockchainTest test = new();
- test.Name = name;
- test.Category = category;
- test.Network = testJson.EthereumNetwork;
- test.NetworkAfterTransition = testJson.EthereumNetworkAfterTransition;
- test.TransitionForkActivation = testJson.TransitionForkActivation;
- test.LastBlockHash = new Hash256(testJson.LastBlockHash);
- test.GenesisRlp = testJson.GenesisRlp is null ? null : new Rlp(Bytes.FromHexString(testJson.GenesisRlp));
- test.GenesisBlockHeader = testJson.GenesisBlockHeader;
- test.Blocks = testJson.Blocks;
- test.Pre = testJson.Pre.ToDictionary(p => p.Key, p => p.Value);
+ BlockchainTest test = new()
+ {
+ Name = name,
+ Category = category,
+ Network = testJson.EthereumNetwork,
+ NetworkAfterTransition = testJson.EthereumNetworkAfterTransition,
+ TransitionForkActivation = testJson.TransitionForkActivation,
+ LastBlockHash = new Hash256(testJson.LastBlockHash),
+ GenesisRlp = testJson.GenesisRlp is null ? null : new Rlp(Bytes.FromHexString(testJson.GenesisRlp)),
+ GenesisBlockHeader = testJson.GenesisBlockHeader,
+ Blocks = testJson.Blocks,
+ EngineNewPayloads = testJson.EngineNewPayloads,
+ Pre = testJson.Pre.ToDictionary(p => p.Key, p => p.Value)
+ };
HalfBlockchainTestJson half = testJson as HalfBlockchainTestJson;
if (half is not null)
@@ -272,7 +328,7 @@ public static BlockchainTest Convert(string name, string category, BlockchainTes
public static IEnumerable ConvertToEofTests(string json)
{
Dictionary testsInFile = _serializer.Deserialize>(json);
- List tests = new();
+ List tests = [];
foreach (KeyValuePair namedTest in testsInFile)
{
(string name, string category) = GetNameAndCategory(namedTest.Key);
@@ -281,11 +337,13 @@ public static IEnumerable ConvertToEofTests(string json)
foreach (KeyValuePair pair in namedTest.Value.Vectors)
{
VectorTestJson vectorJson = pair.Value;
- VectorTest vector = new();
- vector.Code = Bytes.FromHexString(vectorJson.Code);
- vector.ContainerKind = ParseContainerKind(vectorJson.ContainerKind);
+ VectorTest vector = new()
+ {
+ Code = Bytes.FromHexString(vectorJson.Code),
+ ContainerKind = ParseContainerKind(vectorJson.ContainerKind)
+ };
- foreach (var result in vectorJson.Results)
+ foreach (KeyValuePair result in vectorJson.Results)
{
EofTest test = new()
{
@@ -293,10 +351,10 @@ public static IEnumerable ConvertToEofTests(string json)
Category = $"{category} [{result.Key}]",
Url = url,
Description = description,
- Spec = spec
+ Spec = spec,
+ Vector = vector,
+ Result = result.ToTestResult()
};
- test.Vector = vector;
- test.Result = result.ToTestResult();
tests.Add(test);
}
}
@@ -305,7 +363,7 @@ public static IEnumerable ConvertToEofTests(string json)
return tests;
static ValidationStrategy ParseContainerKind(string containerKind)
- => ("INITCODE".Equals(containerKind) ? ValidationStrategy.ValidateInitCodeMode : ValidationStrategy.ValidateRuntimeMode);
+ => "INITCODE".Equals(containerKind) ? ValidationStrategy.ValidateInitCodeMode : ValidationStrategy.ValidateRuntimeMode;
static void GetTestMetaData(KeyValuePair namedTest, out string? description, out string? url, out string? spec)
{
@@ -332,7 +390,7 @@ public static IEnumerable ConvertStateTest(string json)
Dictionary testsInFile =
_serializer.Deserialize>(json);
- List tests = new();
+ List tests = [];
foreach (KeyValuePair namedTest in testsInFile)
{
(string name, string category) = GetNameAndCategory(namedTest.Key);
@@ -349,17 +407,19 @@ public static IEnumerable ConvertToBlockchainTests(string json)
{
testsInFile = _serializer.Deserialize>(json);
}
- catch (Exception)
+ catch (Exception e)
{
- var half = _serializer.Deserialize>(json);
- testsInFile = new Dictionary();
+ Console.WriteLine(e);
+ Dictionary half =
+ _serializer.Deserialize>(json);
+ testsInFile = [];
foreach (KeyValuePair pair in half)
{
testsInFile[pair.Key] = pair.Value;
}
}
- List testsByName = new();
+ List testsByName = [];
foreach ((string testName, BlockchainTestJson testSpec) in testsInFile)
{
string[] transitionInfo = testSpec.Network.Split("At");
diff --git a/src/Nethermind/Ethereum.Test.Base/TestBlockHeaderJson.cs b/src/Nethermind/Ethereum.Test.Base/TestBlockHeaderJson.cs
index 3508dba38c66..39c11de9c42d 100644
--- a/src/Nethermind/Ethereum.Test.Base/TestBlockHeaderJson.cs
+++ b/src/Nethermind/Ethereum.Test.Base/TestBlockHeaderJson.cs
@@ -21,5 +21,12 @@ public class TestBlockHeaderJson
public string Timestamp { get; set; }
public string TransactionsTrie { get; set; }
public string UncleHash { get; set; }
+ public string? WithdrawalsRoot { get; set; }
+ public string? ParentBeaconBlockRoot { get; set; }
+ public string? RequestsHash { get; set; }
+ public string? BlockAccessListHash { get; set; }
+ public string? BlobGasUsed { get; set; }
+ public string? ExcessBlobGas { get; set; }
+ public string? BaseFeePerGas { get; set; }
}
}
diff --git a/src/Nethermind/Ethereum.Test.Base/TestEngineNewPayloadsJson.cs b/src/Nethermind/Ethereum.Test.Base/TestEngineNewPayloadsJson.cs
new file mode 100644
index 000000000000..a293b5175ac8
--- /dev/null
+++ b/src/Nethermind/Ethereum.Test.Base/TestEngineNewPayloadsJson.cs
@@ -0,0 +1,45 @@
+// SPDX-FileCopyrightText: 2025 Demerzel Solutions Limited
+// SPDX-License-Identifier: LGPL-3.0-only
+
+using System.Text.Json;
+
+namespace Ethereum.Test.Base
+{
+ public class TestEngineNewPayloadsJson
+ {
+ public JsonElement[] Params { get; set; }
+ // public EngineNewPayloadParams Params { get; set; }
+ public string? NewPayloadVersion { get; set; }
+ public string? ForkChoiceUpdatedVersion { get; set; }
+
+ // public class EngineNewPayloadParams
+ // {
+ // public ParamsExecutionPayload ExecutionPayload;
+ // public string[] BlobVersionedHashes;
+ // public string ParentBeaconBlockRoot;
+ // public string ValidationError;
+ // }
+
+ public class ParamsExecutionPayload
+ {
+ public string ParentHash { get; set; }
+ public string FeeRecipient { get; set; }
+ public string StateRoot { get; set; }
+ public string ReceiptsRoot { get; set; }
+ public string LogsBloom { get; set; }
+ public string BlockNumber { get; set; }
+ public string GasLimit { get; set; }
+ public string GasUsed { get; set; }
+ public string Timestamp { get; set; }
+ public string ExtraData { get; set; }
+ public string PrevRandao { get; set; }
+ public string BaseFeePerGas { get; set; }
+ public string BlobGasUsed { get; set; }
+ public string ExcessBlobGas { get; set; }
+ public string BlockHash { get; set; }
+ public string[] Transactions { get; set; }
+ public string[]? Withdrawals { get; set; }
+ public string? BlockAccessList { get; set; }
+ }
+ }
+}
diff --git a/src/Nethermind/Nethermind.Blockchain.Test/BeaconBlockRootHandlerTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/BeaconBlockRootHandlerTests.cs
index a82668f7d741..7288c0d85ac1 100644
--- a/src/Nethermind/Nethermind.Blockchain.Test/BeaconBlockRootHandlerTests.cs
+++ b/src/Nethermind/Nethermind.Blockchain.Test/BeaconBlockRootHandlerTests.cs
@@ -5,10 +5,8 @@
using Nethermind.Core;
using Nethermind.Core.Crypto;
using Nethermind.Core.Eip2930;
-using Nethermind.Core.Specs;
using Nethermind.Core.Test.Builders;
using Nethermind.Crypto;
-using Nethermind.Evm;
using Nethermind.Evm.Tracing;
using Nethermind.Evm.TransactionProcessing;
using Nethermind.Int256;
diff --git a/src/Nethermind/Nethermind.Merge.Plugin.Test/ExecutionRequestsProcessorMock.cs b/src/Nethermind/Nethermind.Merge.Plugin.Test/ExecutionRequestsProcessorMock.cs
index e1d8404c53da..8ad25a2ec4ef 100644
--- a/src/Nethermind/Nethermind.Merge.Plugin.Test/ExecutionRequestsProcessorMock.cs
+++ b/src/Nethermind/Nethermind.Merge.Plugin.Test/ExecutionRequestsProcessorMock.cs
@@ -8,7 +8,6 @@
using Nethermind.Core.ExecutionRequest;
using Nethermind.Core.Specs;
using Nethermind.Core.Test.Builders;
-using Nethermind.Evm;
using Nethermind.Evm.State;
namespace Nethermind.Merge.Plugin.Test;
diff --git a/src/Nethermind/Nethermind.Merge.Plugin/MergePlugin.cs b/src/Nethermind/Nethermind.Merge.Plugin/MergePlugin.cs
index 92d6a2961e0b..f5d933da50df 100644
--- a/src/Nethermind/Nethermind.Merge.Plugin/MergePlugin.cs
+++ b/src/Nethermind/Nethermind.Merge.Plugin/MergePlugin.cs
@@ -22,7 +22,6 @@
using Nethermind.Core;
using Nethermind.Core.Crypto;
using Nethermind.Core.Exceptions;
-using Nethermind.Core.Timers;
using Nethermind.Db;
using Nethermind.Facade.Proxy;
using Nethermind.HealthChecks;
@@ -329,6 +328,7 @@ protected override void Load(ContainerBuilder builder)
.AddSingleton()
.AddSingleton>, GetBlobsHandler>()
.AddSingleton?>, GetBlobsHandlerV2>()
+ .AddSingleton()
.AddSingleton()
.AddSingleton((ctx) =>
diff --git a/src/Nethermind/Nethermind.Merge.Plugin/NoEngineRequestTracker.cs b/src/Nethermind/Nethermind.Merge.Plugin/NoEngineRequestTracker.cs
new file mode 100644
index 000000000000..e0d1b606bd30
--- /dev/null
+++ b/src/Nethermind/Nethermind.Merge.Plugin/NoEngineRequestTracker.cs
@@ -0,0 +1,17 @@
+// SPDX-FileCopyrightText: 2025 Demerzel Solutions Limited
+// SPDX-License-Identifier: LGPL-3.0-only
+
+using System.Threading.Tasks;
+using Nethermind.Api;
+
+namespace Nethermind.Merge.Plugin;
+
+public class NoEngineRequestsTracker : IEngineRequestsTracker
+{
+ public void OnForkchoiceUpdatedCalled() { }
+
+ public void OnNewPayloadCalled() { }
+
+ public Task StartAsync()
+ => Task.CompletedTask;
+}
diff --git a/src/Nethermind/Nethermind.State.Test/StateProviderTests.cs b/src/Nethermind/Nethermind.State.Test/StateProviderTests.cs
index 243bb99cd4c6..27f361829033 100644
--- a/src/Nethermind/Nethermind.State.Test/StateProviderTests.cs
+++ b/src/Nethermind/Nethermind.State.Test/StateProviderTests.cs
@@ -10,13 +10,11 @@
using Nethermind.Specs;
using Nethermind.Specs.Forks;
using Nethermind.Core.Test.Builders;
-using Nethermind.Db;
using Nethermind.Int256;
using Nethermind.Blockchain.Tracing.ParityStyle;
using Nethermind.Logging;
using Nethermind.Evm.State;
using Nethermind.State;
-using Nethermind.Trie;
using NUnit.Framework;
namespace Nethermind.Store.Test;
diff --git a/src/Nethermind/Nethermind.Test.Runner/BlockchainTestsRunner.cs b/src/Nethermind/Nethermind.Test.Runner/BlockchainTestsRunner.cs
index 0856b9002fce..b9b3013d39f5 100644
--- a/src/Nethermind/Nethermind.Test.Runner/BlockchainTestsRunner.cs
+++ b/src/Nethermind/Nethermind.Test.Runner/BlockchainTestsRunner.cs
@@ -29,9 +29,18 @@ public BlockchainTestsRunner(ITestSourceLoader testsSource, string? filter, ulon
public async Task> RunTestsAsync()
{
List testResults = new();
- IEnumerable tests = _testsSource.LoadTests();
- foreach (BlockchainTest test in tests)
+ IEnumerable tests = _testsSource.LoadTests();
+ foreach (EthereumTest loadedTest in tests)
{
+ if (loadedTest as FailedToLoadTest is not null)
+ {
+ WriteRed(loadedTest.LoadFailure);
+ testResults.Add(new EthereumTestResult(loadedTest.Name, loadedTest.LoadFailure));
+ continue;
+ }
+
+ BlockchainTest test = loadedTest as BlockchainTest;
+
if (_filter is not null && !Regex.Match(test.Name, $"^({_filter})").Success)
continue;
Setup();
From 3c54497d0c62e27a51a68cc930336e0eaafa77c9 Mon Sep 17 00:00:00 2001
From: Marc Harvey-Hill <10379486+Marchhill@users.noreply.github.com>
Date: Wed, 1 Oct 2025 21:34:09 +0100
Subject: [PATCH 02/26] fix normal blockchain tests
---
src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs b/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs
index 129fef10d8c3..49eb21a5888c 100644
--- a/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs
+++ b/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs
@@ -144,7 +144,6 @@ protected async Task RunTest(BlockchainTest test, Stopwatch?
blockchainProcessor.Start();
BlockHeader parentHeader;
- (ExecutionPayload, string[]?, string[]?, string?)[] payloads;
// Genesis processing
using (stateProvider.BeginScope(null))
{
@@ -158,8 +157,6 @@ protected async Task RunTest(BlockchainTest test, Stopwatch?
// Console.WriteLine(genesisBlock.ToString(Block.Format.Full));
Assert.That(genesisBlock.Header.Hash, Is.EqualTo(new Hash256(test.GenesisBlockHeader.Hash)));
- payloads = [.. JsonToEthereumTest.Convert(test.EngineNewPayloads)];
-
ManualResetEvent genesisProcessed = new(false);
blockTree.NewHeadBlock += (_, args) =>
@@ -183,6 +180,8 @@ protected async Task RunTest(BlockchainTest test, Stopwatch?
}
else if (test.EngineNewPayloads is not null)
{
+ (ExecutionPayload, string[]?, string[]?, string?)[] payloads = [.. JsonToEthereumTest.Convert(test.EngineNewPayloads)];
+
// blockchain test engine
foreach ((ExecutionPayload executionPayload, string[]? blobVersionedHashes, string[]? validationError, string? newPayloadVersion) in payloads)
{
From c8afd68097c9ed8305131ce005b55f27790860e7 Mon Sep 17 00:00:00 2001
From: Marc Harvey-Hill <10379486+Marchhill@users.noreply.github.com>
Date: Thu, 2 Oct 2025 13:20:21 +0100
Subject: [PATCH 03/26] tidy
---
src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs | 4 ----
src/Nethermind/Ethereum.Test.Base/JsonToEthereumTest.cs | 3 +--
.../Ethereum.Test.Base/TestEngineNewPayloadsJson.cs | 9 ---------
3 files changed, 1 insertion(+), 15 deletions(-)
diff --git a/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs b/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs
index 49eb21a5888c..af18a524d66b 100644
--- a/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs
+++ b/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs
@@ -154,7 +154,6 @@ protected async Task RunTest(BlockchainTest test, Stopwatch?
test.GenesisRlp ??= Rlp.Encode(new Block(JsonToEthereumTest.Convert(test.GenesisBlockHeader)));
Block genesisBlock = Rlp.Decode(test.GenesisRlp.Bytes);
- // Console.WriteLine(genesisBlock.ToString(Block.Format.Full));
Assert.That(genesisBlock.Header.Hash, Is.EqualTo(new Hash256(test.GenesisBlockHeader.Hash)));
ManualResetEvent genesisProcessed = new(false);
@@ -291,9 +290,6 @@ private static BlockHeader SuggestBlocks(BlockchainTest test, bool failOnInvalid
{
RlpStream rlpContext = Bytes.FromHexString(testBlockJson.Rlp).AsRlpStream();
Block suggestedBlock = Rlp.Decode(rlpContext);
- // Console.WriteLine("suggested block:");
- // Console.WriteLine(suggestedBlock.BlockAccessList);
- // Hash256 tmp = new(ValueKeccak.Compute(Rlp.Encode(suggestedBlock.BlockAccessList!.Value).Bytes).Bytes);
suggestedBlock.Header.SealEngineType =
test.SealEngineUsed ? SealEngineType.Ethash : SealEngineType.None;
diff --git a/src/Nethermind/Ethereum.Test.Base/JsonToEthereumTest.cs b/src/Nethermind/Ethereum.Test.Base/JsonToEthereumTest.cs
index 432156d5dcc2..05be99df487f 100644
--- a/src/Nethermind/Ethereum.Test.Base/JsonToEthereumTest.cs
+++ b/src/Nethermind/Ethereum.Test.Base/JsonToEthereumTest.cs
@@ -407,9 +407,8 @@ public static IEnumerable ConvertToBlockchainTests(string json)
{
testsInFile = _serializer.Deserialize>(json);
}
- catch (Exception e)
+ catch (Exception)
{
- Console.WriteLine(e);
Dictionary half =
_serializer.Deserialize>(json);
testsInFile = [];
diff --git a/src/Nethermind/Ethereum.Test.Base/TestEngineNewPayloadsJson.cs b/src/Nethermind/Ethereum.Test.Base/TestEngineNewPayloadsJson.cs
index a293b5175ac8..b89dcd2869b2 100644
--- a/src/Nethermind/Ethereum.Test.Base/TestEngineNewPayloadsJson.cs
+++ b/src/Nethermind/Ethereum.Test.Base/TestEngineNewPayloadsJson.cs
@@ -8,18 +8,9 @@ namespace Ethereum.Test.Base
public class TestEngineNewPayloadsJson
{
public JsonElement[] Params { get; set; }
- // public EngineNewPayloadParams Params { get; set; }
public string? NewPayloadVersion { get; set; }
public string? ForkChoiceUpdatedVersion { get; set; }
- // public class EngineNewPayloadParams
- // {
- // public ParamsExecutionPayload ExecutionPayload;
- // public string[] BlobVersionedHashes;
- // public string ParentBeaconBlockRoot;
- // public string ValidationError;
- // }
-
public class ParamsExecutionPayload
{
public string ParentHash { get; set; }
From 309560a01cda265297784d18ba9c9b7d57702415 Mon Sep 17 00:00:00 2001
From: Marc Harvey-Hill <10379486+Marchhill@users.noreply.github.com>
Date: Thu, 2 Oct 2025 13:37:01 +0100
Subject: [PATCH 04/26] restore disposes
---
src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs b/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs
index af18a524d66b..2caafe54e558 100644
--- a/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs
+++ b/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs
@@ -219,6 +219,9 @@ protected async Task RunTest(BlockchainTest test, Stopwatch?
// Caches are cleared async, which is a problem as read for the MainWorldState with prewarmer is not correct if its not cleared.
preWarmer?.ClearCaches();
+ // Dispose genesis block's AccountChanges
+ genesisBlock.DisposeAccountChanges();
+
Block? headBlock = blockTree.RetrieveHeadBlock();
List differences;
using (stateProvider.BeginScope(headBlock.Header))
@@ -273,6 +276,11 @@ private static BlockHeader SuggestBlocks(BlockchainTest test, bool failOnInvalid
{
Assert.Fail($"Unexpected exception during processing: {e}");
}
+ finally
+ {
+ // Dispose AccountChanges to prevent memory leaks in tests
+ correctRlp[i].Block.DisposeAccountChanges();
+ }
parentHeader = correctRlp[i].Block.Header;
}
From 11e0cbfc98714c3533bd3d5141fb0f8d47aebb3d Mon Sep 17 00:00:00 2001
From: Marc Harvey-Hill <10379486+Marchhill@users.noreply.github.com>
Date: Thu, 2 Oct 2025 13:41:05 +0100
Subject: [PATCH 05/26] comment out BALs
---
src/Nethermind/Ethereum.Test.Base/JsonToEthereumTest.cs | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/Nethermind/Ethereum.Test.Base/JsonToEthereumTest.cs b/src/Nethermind/Ethereum.Test.Base/JsonToEthereumTest.cs
index 05be99df487f..1345c9cf96e6 100644
--- a/src/Nethermind/Ethereum.Test.Base/JsonToEthereumTest.cs
+++ b/src/Nethermind/Ethereum.Test.Base/JsonToEthereumTest.cs
@@ -74,7 +74,7 @@ public static BlockHeader Convert(TestBlockHeaderJson? headerJson)
StateRoot = new Hash256(headerJson.StateRoot),
TxRoot = new Hash256(headerJson.TransactionsTrie),
WithdrawalsRoot = headerJson.WithdrawalsRoot is null ? null : new Hash256(headerJson.WithdrawalsRoot),
- BlockAccessListHash = headerJson.BlockAccessListHash is null ? null : new Hash256(headerJson.BlockAccessListHash),
+ // BlockAccessListHash = headerJson.BlockAccessListHash is null ? null : new Hash256(headerJson.BlockAccessListHash),
BaseFeePerGas = (ulong)Bytes.FromHexString(headerJson.BaseFeePerGas).ToUnsignedBigInteger()
};
return header;
@@ -108,7 +108,7 @@ public static BlockHeader Convert(TestBlockHeaderJson? headerJson)
ReceiptsRoot = new(executionPayload.ReceiptsRoot),
StateRoot = new(executionPayload.StateRoot),
Timestamp = (ulong)Bytes.FromHexString(executionPayload.Timestamp).ToUnsignedBigInteger(),
- BlockAccessList = executionPayload.BlockAccessList is null ? null : Bytes.FromHexString(executionPayload.BlockAccessList),
+ // BlockAccessList = executionPayload.BlockAccessList is null ? null : Bytes.FromHexString(executionPayload.BlockAccessList),
BlobGasUsed = executionPayload.BlobGasUsed is null ? null : (ulong)Bytes.FromHexString(executionPayload.BlobGasUsed).ToUnsignedBigInteger(),
ExcessBlobGas = executionPayload.ExcessBlobGas is null ? null : (ulong)Bytes.FromHexString(executionPayload.ExcessBlobGas).ToUnsignedBigInteger(),
ParentBeaconBlockRoot = parentBeaconBlockRoot is null ? null : new(parentBeaconBlockRoot),
From ae3c660234b8a89c8f31d2e3a486d5ebf2b4cad7 Mon Sep 17 00:00:00 2001
From: Marc Harvey-Hill <10379486+Marchhill@users.noreply.github.com>
Date: Thu, 2 Oct 2025 13:47:02 +0100
Subject: [PATCH 06/26] fix var declaration
---
src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs b/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs
index 2caafe54e558..b12370be2bb6 100644
--- a/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs
+++ b/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs
@@ -143,6 +143,7 @@ protected async Task RunTest(BlockchainTest test, Stopwatch?
IEngineRpcModule engineRpcModule = container.Resolve();
blockchainProcessor.Start();
+ Block genesisBlock;
BlockHeader parentHeader;
// Genesis processing
using (stateProvider.BeginScope(null))
@@ -153,7 +154,7 @@ protected async Task RunTest(BlockchainTest test, Stopwatch?
test.GenesisRlp ??= Rlp.Encode(new Block(JsonToEthereumTest.Convert(test.GenesisBlockHeader)));
- Block genesisBlock = Rlp.Decode(test.GenesisRlp.Bytes);
+ genesisBlock = Rlp.Decode(test.GenesisRlp.Bytes);
Assert.That(genesisBlock.Header.Hash, Is.EqualTo(new Hash256(test.GenesisBlockHeader.Hash)));
ManualResetEvent genesisProcessed = new(false);
From 1c14e934ec298569201db2508c96d6052b052e3f Mon Sep 17 00:00:00 2001
From: Marc Harvey-Hill <10379486+Marchhill@users.noreply.github.com>
Date: Thu, 2 Oct 2025 14:23:35 +0100
Subject: [PATCH 07/26] don't set basefeepergas if null
---
src/Nethermind/Ethereum.Test.Base/JsonToEthereumTest.cs | 7 ++++++-
src/Nethermind/Ethereum.Test.Base/TestBlockHeaderJson.cs | 2 +-
2 files changed, 7 insertions(+), 2 deletions(-)
diff --git a/src/Nethermind/Ethereum.Test.Base/JsonToEthereumTest.cs b/src/Nethermind/Ethereum.Test.Base/JsonToEthereumTest.cs
index 1345c9cf96e6..5ab865e202f3 100644
--- a/src/Nethermind/Ethereum.Test.Base/JsonToEthereumTest.cs
+++ b/src/Nethermind/Ethereum.Test.Base/JsonToEthereumTest.cs
@@ -75,8 +75,13 @@ public static BlockHeader Convert(TestBlockHeaderJson? headerJson)
TxRoot = new Hash256(headerJson.TransactionsTrie),
WithdrawalsRoot = headerJson.WithdrawalsRoot is null ? null : new Hash256(headerJson.WithdrawalsRoot),
// BlockAccessListHash = headerJson.BlockAccessListHash is null ? null : new Hash256(headerJson.BlockAccessListHash),
- BaseFeePerGas = (ulong)Bytes.FromHexString(headerJson.BaseFeePerGas).ToUnsignedBigInteger()
};
+
+ if (headerJson.BaseFeePerGas is not null)
+ {
+ header.BaseFeePerGas = (ulong)Bytes.FromHexString(headerJson.BaseFeePerGas).ToUnsignedBigInteger();
+ }
+
return header;
}
diff --git a/src/Nethermind/Ethereum.Test.Base/TestBlockHeaderJson.cs b/src/Nethermind/Ethereum.Test.Base/TestBlockHeaderJson.cs
index 39c11de9c42d..c154f53e5743 100644
--- a/src/Nethermind/Ethereum.Test.Base/TestBlockHeaderJson.cs
+++ b/src/Nethermind/Ethereum.Test.Base/TestBlockHeaderJson.cs
@@ -21,12 +21,12 @@ public class TestBlockHeaderJson
public string Timestamp { get; set; }
public string TransactionsTrie { get; set; }
public string UncleHash { get; set; }
+ public string? BaseFeePerGas { get; set; }
public string? WithdrawalsRoot { get; set; }
public string? ParentBeaconBlockRoot { get; set; }
public string? RequestsHash { get; set; }
public string? BlockAccessListHash { get; set; }
public string? BlobGasUsed { get; set; }
public string? ExcessBlobGas { get; set; }
- public string? BaseFeePerGas { get; set; }
}
}
From 32f3e5340ccd603c1ed2d840d68bfcd6e8709b4d Mon Sep 17 00:00:00 2001
From: Marc Harvey-Hill <10379486+Marchhill@users.noreply.github.com>
Date: Thu, 9 Oct 2025 17:06:53 +0100
Subject: [PATCH 08/26] use network from genesis in blockchain test
---
.../Ethereum.Test.Base/BlockchainTestBase.cs | 8 +---
.../Ethereum.Test.Base/GeneralTestBase.cs | 44 +++++++++----------
.../Interfaces/EthereumTest.cs | 6 +--
3 files changed, 24 insertions(+), 34 deletions(-)
diff --git a/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs b/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs
index b12370be2bb6..2df80720367a 100644
--- a/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs
+++ b/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs
@@ -83,8 +83,7 @@ protected async Task RunTest(BlockchainTest test, Stopwatch?
test.Network = ChainUtils.ResolveSpec(test.Network, test.ChainId);
test.NetworkAfterTransition = ChainUtils.ResolveSpec(test.NetworkAfterTransition, test.ChainId);
- List<(ForkActivation Activation, IReleaseSpec Spec)> transitions =
- [((ForkActivation)0, test.GenesisSpec), ((ForkActivation)1, test.Network)]; // TODO: this thing took a lot of time to find after it was removed!, genesis block is always initialized with Frontier
+ List<(ForkActivation Activation, IReleaseSpec Spec)> transitions = [((ForkActivation)0, test.Network)];
if (test.NetworkAfterTransition is not null)
{
transitions.Add((test.TransitionForkActivation!.Value, test.NetworkAfterTransition));
@@ -92,11 +91,6 @@ protected async Task RunTest(BlockchainTest test, Stopwatch?
ISpecProvider specProvider = new CustomSpecProvider(test.ChainId, test.ChainId, transitions.ToArray());
- if (test.ChainId != GnosisSpecProvider.Instance.ChainId && specProvider.GenesisSpec != Frontier.Instance)
- {
- Assert.Fail("Expected genesis spec to be Frontier for blockchain tests");
- }
-
if (test.Network is Cancun || test.NetworkAfterTransition is Cancun)
{
await KzgPolynomialCommitments.InitializeAsync();
diff --git a/src/Nethermind/Ethereum.Test.Base/GeneralTestBase.cs b/src/Nethermind/Ethereum.Test.Base/GeneralTestBase.cs
index 998319565324..16e85265b851 100644
--- a/src/Nethermind/Ethereum.Test.Base/GeneralTestBase.cs
+++ b/src/Nethermind/Ethereum.Test.Base/GeneralTestBase.cs
@@ -44,7 +44,7 @@ static GeneralStateTestBase()
}
[SetUp]
- public void Setup()
+ public static void Setup()
{
}
@@ -68,15 +68,7 @@ protected EthereumTestResult RunTest(GeneralStateTest test, ITxTracer txTracer)
test.Fork = ChainUtils.ResolveSpec(test.Fork, test.ChainId);
- ISpecProvider specProvider =
- new CustomSpecProvider(test.ChainId, test.ChainId,
- ((ForkActivation)0, test.GenesisSpec), // TODO: this thing took a lot of time to find after it was removed!, genesis block is always initialized with Frontier
- ((ForkActivation)1, test.Fork));
-
- if (test.ChainId != GnosisSpecProvider.Instance.ChainId && specProvider.GenesisSpec != Frontier.Instance)
- {
- Assert.Fail("Expected genesis spec to be Frontier for blockchain tests");
- }
+ ISpecProvider specProvider = new CustomSpecProvider(test.ChainId, test.ChainId, ((ForkActivation)0, test.Fork));
IConfigProvider configProvider = new ConfigProvider();
using IContainer container = new ContainerBuilder()
@@ -101,17 +93,19 @@ protected EthereumTestResult RunTest(GeneralStateTest test, ITxTracer txTracer)
test.CurrentNumber,
test.CurrentGasLimit,
test.CurrentTimestamp,
- []);
- header.BaseFeePerGas = test.Fork.IsEip1559Enabled ? test.CurrentBaseFee ?? _defaultBaseFeeForStateTest : UInt256.Zero;
- header.StateRoot = test.PostHash;
+ [])
+ {
+ BaseFeePerGas = test.Fork.IsEip1559Enabled ? test.CurrentBaseFee ?? _defaultBaseFeeForStateTest : UInt256.Zero,
+ StateRoot = test.PostHash,
+ IsPostMerge = test.CurrentRandom is not null,
+ MixHash = test.CurrentRandom,
+ WithdrawalsRoot = test.CurrentWithdrawalsRoot,
+ ParentBeaconBlockRoot = test.CurrentBeaconRoot,
+ ExcessBlobGas = test.CurrentExcessBlobGas ?? (test.Fork is Cancun ? 0ul : null),
+ BlobGasUsed = BlobGasCalculator.CalculateBlobGas(test.Transaction),
+ RequestsHash = test.RequestsHash
+ };
header.Hash = header.CalculateHash();
- header.IsPostMerge = test.CurrentRandom is not null;
- header.MixHash = test.CurrentRandom;
- header.WithdrawalsRoot = test.CurrentWithdrawalsRoot;
- header.ParentBeaconBlockRoot = test.CurrentBeaconRoot;
- header.ExcessBlobGas = test.CurrentExcessBlobGas ?? (test.Fork is Cancun ? 0ul : null);
- header.BlobGasUsed = BlobGasCalculator.CalculateBlobGas(test.Transaction);
- header.RequestsHash = test.RequestsHash;
Stopwatch stopwatch = Stopwatch.StartNew();
IReleaseSpec? spec = specProvider.GetSpec((ForkActivation)test.CurrentNumber);
@@ -170,16 +164,18 @@ protected EthereumTestResult RunTest(GeneralStateTest test, ITxTracer txTracer)
}
List differences = RunAssertions(test, stateProvider);
- EthereumTestResult testResult = new(test.Name, test.ForkName, differences.Count == 0);
- testResult.TimeInMs = stopwatch.Elapsed.TotalMilliseconds;
- testResult.StateRoot = stateProvider.StateRoot;
+ EthereumTestResult testResult = new(test.Name, test.ForkName, differences.Count == 0)
+ {
+ TimeInMs = stopwatch.Elapsed.TotalMilliseconds,
+ StateRoot = stateProvider.StateRoot
+ };
if (differences.Count > 0)
{
_logger.Info($"\nDifferences from expected\n{string.Join("\n", differences)}");
}
- // Assert.Zero(differences.Count, "differences");
+ Assert.That(differences, Is.Empty, "differences");
return testResult;
}
diff --git a/src/Nethermind/Ethereum.Test.Base/Interfaces/EthereumTest.cs b/src/Nethermind/Ethereum.Test.Base/Interfaces/EthereumTest.cs
index d64cf0a6d6da..03e55c585a0e 100644
--- a/src/Nethermind/Ethereum.Test.Base/Interfaces/EthereumTest.cs
+++ b/src/Nethermind/Ethereum.Test.Base/Interfaces/EthereumTest.cs
@@ -9,8 +9,8 @@ public abstract class EthereumTest
public string? Name { get; set; }
public string? LoadFailure { get; set; }
public ulong ChainId { get; set; } = MainnetSpecProvider.Instance.ChainId;
- public IReleaseSpec GenesisSpec => ChainId == MainnetSpecProvider.Instance.ChainId
- ? MainnetSpecProvider.Instance.GenesisSpec
- : GnosisSpecProvider.Instance.GenesisSpec;
+ // public IReleaseSpec GenesisSpec => ChainId == MainnetSpecProvider.Instance.ChainId
+ // ? MainnetSpecProvider.Instance.GenesisSpec
+ // : GnosisSpecProvider.Instance.GenesisSpec;
}
}
From b8330ce6787cf9a54c08b150e2e30371753aedce Mon Sep 17 00:00:00 2001
From: Marc Harvey-Hill <10379486+Marchhill@users.noreply.github.com>
Date: Mon, 20 Oct 2025 17:06:55 +0100
Subject: [PATCH 09/26] update blockchain test base
---
.../Ethereum.Test.Base/BlockchainTestBase.cs | 299 ++++++++++--------
1 file changed, 173 insertions(+), 126 deletions(-)
diff --git a/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs b/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs
index 2df80720367a..67e0e0324121 100644
--- a/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs
+++ b/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs
@@ -30,6 +30,7 @@
using Nethermind.Specs.Forks;
using Nethermind.Specs.Test;
using Nethermind.Evm.State;
+using Nethermind.Evm.Tracing;
using Nethermind.Init.Modules;
using Nethermind.TxPool;
using NUnit.Framework;
@@ -42,7 +43,8 @@ namespace Ethereum.Test.Base;
public abstract class BlockchainTestBase
{
private static readonly ILogger _logger;
- private static readonly ILogManager _logManager = new TestLogManager(LogLevel.Warn);
+ private static readonly ILogManager _logManager = new TestLogManager();
+ // private static ISealValidator Sealer { get; }
private static DifficultyCalculatorWrapper DifficultyCalculator { get; }
static BlockchainTestBase()
@@ -73,9 +75,9 @@ public UInt256 Calculate(BlockHeader header, BlockHeader parent)
}
}
- protected async Task RunTest(BlockchainTest test, Stopwatch? stopwatch = null, bool failOnInvalidRlp = true)
+ protected async Task RunTest(BlockchainTest test, Stopwatch? stopwatch = null, bool failOnInvalidRlp = true, ITestBlockTracer? tracer = null)
{
- _logger.Info($"Running {test.Name}, Network: [{test.Network.Name}] at {DateTime.UtcNow:HH:mm:ss.ffffff}");
+ _logger.Info($"Running {test.Name}, Network: [{test.Network!.Name}] at {DateTime.UtcNow:HH:mm:ss.ffffff}");
if (test.NetworkAfterTransition is not null)
_logger.Info($"Network after transition: [{test.NetworkAfterTransition.Name}] at {test.TransitionForkActivation}");
Assert.That(test.LoadFailure, Is.Null, "test data loading failure");
@@ -120,7 +122,7 @@ protected async Task RunTest(BlockchainTest test, Stopwatch?
IConfigProvider configProvider = new ConfigProvider();
// configProvider.GetConfig().PreWarmStateOnBlockProcessing = false;
await using IContainer container = new ContainerBuilder()
- .AddModule(new TestNethermindModule(configProvider))
+ .AddModule(new TestNethermindModule(configProvider)) // check if two different modules must be fixed together
.AddModule(new TestMergeModule(configProvider))
.AddSingleton(specProvider)
.AddSingleton(_logManager)
@@ -137,101 +139,102 @@ protected async Task RunTest(BlockchainTest test, Stopwatch?
IEngineRpcModule engineRpcModule = container.Resolve();
blockchainProcessor.Start();
- Block genesisBlock;
- BlockHeader parentHeader;
- // Genesis processing
- using (stateProvider.BeginScope(null))
+ // Register tracer if provided for blocktest tracing
+ if (tracer is not null)
{
- InitializeTestState(test, stateProvider, specProvider);
+ blockchainProcessor.Tracers.Add(tracer);
+ }
- stopwatch?.Start();
+ try
+ {
+ BlockHeader parentHeader;
+ // Genesis processing
+ using (stateProvider.BeginScope(null))
+ {
+ InitializeTestState(test, stateProvider, specProvider);
- test.GenesisRlp ??= Rlp.Encode(new Block(JsonToEthereumTest.Convert(test.GenesisBlockHeader)));
+ stopwatch?.Start();
- genesisBlock = Rlp.Decode(test.GenesisRlp.Bytes);
- Assert.That(genesisBlock.Header.Hash, Is.EqualTo(new Hash256(test.GenesisBlockHeader.Hash)));
+ test.GenesisRlp ??= Rlp.Encode(new Block(JsonToEthereumTest.Convert(test.GenesisBlockHeader)));
- ManualResetEvent genesisProcessed = new(false);
+ Block genesisBlock = Rlp.Decode(test.GenesisRlp.Bytes);
+ // Console.WriteLine(genesisBlock.ToString(Block.Format.Full));
+ Assert.That(genesisBlock.Header.Hash, Is.EqualTo(new Hash256(test.GenesisBlockHeader.Hash)));
- blockTree.NewHeadBlock += (_, args) =>
- {
- if (args.Block.Number == 0)
+ ManualResetEvent genesisProcessed = new(false);
+
+ blockTree.NewHeadBlock += (_, args) =>
{
- Assert.That(stateProvider.HasStateForBlock(genesisBlock.Header), Is.True);
- genesisProcessed.Set();
- }
- };
+ if (args.Block.Number == 0)
+ {
+ Assert.That(stateProvider.HasStateForBlock(genesisBlock.Header), Is.True);
+ genesisProcessed.Set();
+ }
+ };
- blockTree.SuggestBlock(genesisBlock);
- genesisProcessed.WaitOne();
- parentHeader = genesisBlock.Header;
- }
+ blockTree.SuggestBlock(genesisBlock);
+ genesisProcessed.WaitOne();
+ parentHeader = genesisBlock.Header;
- if (test.Blocks is not null)
- {
- // blockchain test
- parentHeader = SuggestBlocks(test, failOnInvalidRlp, blockValidator, blockTree, parentHeader);
- }
- else if (test.EngineNewPayloads is not null)
- {
- (ExecutionPayload, string[]?, string[]?, string?)[] payloads = [.. JsonToEthereumTest.Convert(test.EngineNewPayloads)];
+ // Dispose genesis block's AccountChanges
+ genesisBlock.DisposeAccountChanges();
+ }
- // blockchain test engine
- foreach ((ExecutionPayload executionPayload, string[]? blobVersionedHashes, string[]? validationError, string? newPayloadVersion) in payloads)
+ if (test.Blocks is not null)
{
- ResultWrapper res;
- switch (newPayloadVersion ?? "4")
- {
- case "1":
- res = await engineRpcModule.engine_newPayloadV1(executionPayload);
- break;
- case "2":
- res = await engineRpcModule.engine_newPayloadV2(executionPayload);
- break;
- case "3":
- res = await engineRpcModule.engine_newPayloadV3((ExecutionPayloadV3)executionPayload, [], executionPayload.ParentBeaconBlockRoot);
- break;
- case "4":
- byte[]?[] hashes = blobVersionedHashes is null ? null : [.. blobVersionedHashes.Select(x => Bytes.FromHexString(x))];
- res = await engineRpcModule.engine_newPayloadV4((ExecutionPayloadV3)executionPayload, hashes, executionPayload.ParentBeaconBlockRoot, []);
- break;
- default:
- Assert.Fail("Invalid blockchain engine test, version not recognised.");
- break;
- }
+ // blockchain test
+ parentHeader = SuggestBlocks(test, failOnInvalidRlp, blockValidator, blockTree, parentHeader);
+ }
+ else if (test.EngineNewPayloads is not null)
+ {
+ RunNewPayloads(test.EngineNewPayloads, engineRpcModule);
+ }
+ else
+ {
+ Assert.Fail("Invalid blockchain test, did not contain blocks or new payloads.");
}
- }
- else
- {
- Assert.Fail("Invalid blockchain test, did not contain blocks or new payloads.");
- }
- await blockchainProcessor.StopAsync(true);
- stopwatch?.Stop();
+ // NOTE: Tracer removal must happen AFTER StopAsync to ensure all blocks are traced
+ // Blocks are queued asynchronously, so we need to wait for processing to complete
+ await blockchainProcessor.StopAsync(true);
+ stopwatch?.Stop();
- IBlockCachePreWarmer? preWarmer = container.Resolve().LifetimeScope.ResolveOptional();
+ IBlockCachePreWarmer? preWarmer = container.Resolve().LifetimeScope.ResolveOptional();
- // Caches are cleared async, which is a problem as read for the MainWorldState with prewarmer is not correct if its not cleared.
- preWarmer?.ClearCaches();
+ // Caches are cleared async, which is a problem as read for the MainWorldState with prewarmer is not correct if its not cleared.
+ preWarmer?.ClearCaches();
- // Dispose genesis block's AccountChanges
- genesisBlock.DisposeAccountChanges();
+ Block? headBlock = blockTree.RetrieveHeadBlock();
+ List differences;
+ using (stateProvider.BeginScope(headBlock.Header))
+ {
+ differences = RunAssertions(test, headBlock, stateProvider);
+ }
- Block? headBlock = blockTree.RetrieveHeadBlock();
- List differences;
- using (stateProvider.BeginScope(headBlock.Header))
- {
- differences = RunAssertions(test, blockTree.RetrieveHeadBlock(), stateProvider);
- }
+ bool testPassed = differences.Count == 0;
- Assert.That(differences, Is.Empty, "differences");
+ // Write test end marker if using streaming tracer (JSONL format)
+ // This must be done BEFORE removing tracer and BEFORE Assert to ensure marker is written even on failure
+ if (tracer is not null)
+ {
+ tracer.TestFinished(test.Name, testPassed, test.Network, stopwatch?.Elapsed, headBlock?.StateRoot);
+ blockchainProcessor.Tracers.Remove(tracer);
+ }
- return new EthereumTestResult
- (
- test.Name,
- null,
- differences.Count == 0
- );
+ Assert.That(differences, Is.Empty, "differences");
+
+ return new EthereumTestResult
+ (
+ test.Name,
+ null,
+ differences.Count == 0
+ );
+ }
+ catch (Exception)
+ {
+ await blockchainProcessor.StopAsync(true);
+ throw;
+ }
}
private static BlockHeader SuggestBlocks(BlockchainTest test, bool failOnInvalidRlp, IBlockValidator blockValidator, IBlockTree blockTree, BlockHeader parentHeader)
@@ -248,7 +251,7 @@ private static BlockHeader SuggestBlocks(BlockchainTest test, bool failOnInvalid
{
// TODO: mimic the actual behaviour where block goes through validating sync manager?
correctRlp[i].Block.Header.IsPostMerge = correctRlp[i].Block.Difficulty == 0;
- if (!test.SealEngineUsed || blockValidator.ValidateSuggestedBlock(correctRlp[i].Block, parentHeader, out var _error))
+ if (!test.SealEngineUsed || blockValidator.ValidateSuggestedBlock(correctRlp[i].Block, parentHeader, out _))
{
blockTree.SuggestBlock(correctRlp[i].Block);
}
@@ -279,19 +282,58 @@ private static BlockHeader SuggestBlocks(BlockchainTest test, bool failOnInvalid
parentHeader = correctRlp[i].Block.Header;
}
-
return parentHeader;
}
+ private async static void RunNewPayloads(TestEngineNewPayloadsJson[]? newPayloads, IEngineRpcModule engineRpcModule)
+ {
+ (ExecutionPayload, string[]?, string[]?, string?)[] payloads = [.. JsonToEthereumTest.Convert(newPayloads)];
+
+ // blockchain test engine
+ foreach ((ExecutionPayload executionPayload, string[]? blobVersionedHashes, string[]? validationError, string? newPayloadVersion) in payloads)
+ {
+ ResultWrapper res;
+ byte[]?[] hashes = blobVersionedHashes is null ? null : [.. blobVersionedHashes.Select(x => Bytes.FromHexString(x))];
+
+ switch (newPayloadVersion ?? "5")
+ {
+ case "1":
+ res = await engineRpcModule.engine_newPayloadV1(executionPayload);
+ break;
+ case "2":
+ res = await engineRpcModule.engine_newPayloadV2(executionPayload);
+ break;
+ case "3":
+ res = await engineRpcModule.engine_newPayloadV3((ExecutionPayloadV3)executionPayload, [], executionPayload.ParentBeaconBlockRoot);
+ break;
+ case "4":
+ res = await engineRpcModule.engine_newPayloadV4((ExecutionPayloadV3)executionPayload, hashes, executionPayload.ParentBeaconBlockRoot, []);
+ break;
+ // case "5":
+ // res = await engineRpcModule.engine_newPayloadV5((ExecutionPayloadV3)executionPayload, hashes, executionPayload.ParentBeaconBlockRoot, []);
+ // break;
+ default:
+ Assert.Fail("Invalid blockchain engine test, version not recognised.");
+ continue;
+ }
+
+ if (res.Result.ResultType == ResultType.Success)
+ {
+ ForkchoiceStateV1 fcuState = new(executionPayload.BlockHash, executionPayload.BlockHash, executionPayload.BlockHash);
+ await engineRpcModule.engine_forkchoiceUpdatedV3(fcuState);
+ }
+ }
+ }
+
private static List<(Block Block, string ExpectedException)> DecodeRlps(BlockchainTest test, bool failOnInvalidRlp)
{
- List<(Block Block, string ExpectedException)> correctRlp = [];
- for (int i = 0; i < test.Blocks.Length; i++)
+ List<(Block Block, string ExpectedException)> correctRlp = new();
+ for (int i = 0; i < test.Blocks!.Length; i++)
{
TestBlockJson testBlockJson = test.Blocks[i];
try
{
- RlpStream rlpContext = Bytes.FromHexString(testBlockJson.Rlp).AsRlpStream();
+ RlpStream rlpContext = Bytes.FromHexString(testBlockJson.Rlp!).AsRlpStream();
Block suggestedBlock = Rlp.Decode(rlpContext);
suggestedBlock.Header.SealEngineType =
test.SealEngineUsed ? SealEngineType.Ethash : SealEngineType.None;
@@ -302,7 +344,7 @@ private static BlockHeader SuggestBlocks(BlockchainTest test, bool failOnInvalid
for (int uncleIndex = 0; uncleIndex < suggestedBlock.Uncles.Length; uncleIndex++)
{
- Assert.That(suggestedBlock.Uncles[uncleIndex].Hash, Is.EqualTo(new Hash256(testBlockJson.UncleHeaders[uncleIndex].Hash)));
+ Assert.That(suggestedBlock.Uncles[uncleIndex].Hash, Is.EqualTo(new Hash256(testBlockJson.UncleHeaders![uncleIndex].Hash)));
}
correctRlp.Add((suggestedBlock, testBlockJson.ExpectedException));
@@ -368,13 +410,9 @@ private static List RunAssertions(BlockchainTest test, Block headBlock,
{
if (test.PostStateRoot is not null)
{
- return test.PostStateRoot != stateProvider.StateRoot ? ["state root mismatch"] : [];
+ return test.PostStateRoot != stateProvider.StateRoot ? ["state root mismatch"] : Enumerable.Empty().ToList();
}
- TestBlockHeaderJson testHeaderJson = (test.Blocks?
- .Where(b => b.BlockHeader is not null)
- .SingleOrDefault(b => new Hash256(b.BlockHeader.Hash) == headBlock.Hash)?.BlockHeader) ?? test.GenesisBlockHeader;
- BlockHeader testHeader = JsonToEthereumTest.Convert(testHeaderJson);
List differences = [];
IEnumerable> deletedAccounts = test.Pre?
@@ -388,7 +426,7 @@ private static List RunAssertions(BlockchainTest test, Block headBlock,
}
}
- foreach ((Address acountAddress, AccountState accountState) in test.PostState)
+ foreach ((Address accountAddress, AccountState accountState) in test.PostState!)
{
int differencesBefore = differences.Count;
@@ -398,87 +436,96 @@ private static List RunAssertions(BlockchainTest test, Block headBlock,
break;
}
- bool accountExists = stateProvider.AccountExists(acountAddress);
- UInt256? balance = accountExists ? stateProvider.GetBalance(acountAddress) : null;
- UInt256? nonce = accountExists ? stateProvider.GetNonce(acountAddress) : null;
+ bool accountExists = stateProvider.AccountExists(accountAddress);
+ UInt256? balance = accountExists ? stateProvider.GetBalance(accountAddress) : null;
+ UInt256? nonce = accountExists ? stateProvider.GetNonce(accountAddress) : null;
if (accountState.Balance != balance)
{
- differences.Add($"{acountAddress} balance exp: {accountState.Balance}, actual: {balance}, diff: {(balance > accountState.Balance ? balance - accountState.Balance : accountState.Balance - balance)}");
+ differences.Add($"{accountAddress} balance exp: {accountState.Balance}, actual: {balance}, diff: {(balance > accountState.Balance ? balance - accountState.Balance : accountState.Balance - balance)}");
}
if (accountState.Nonce != nonce)
{
- differences.Add($"{acountAddress} nonce exp: {accountState.Nonce}, actual: {nonce}");
+ differences.Add($"{accountAddress} nonce exp: {accountState.Nonce}, actual: {nonce}");
}
- byte[] code = accountExists ? stateProvider.GetCode(acountAddress) : [];
+ byte[] code = accountExists ? stateProvider.GetCode(accountAddress) : [];
if (!Bytes.AreEqual(accountState.Code, code))
{
- differences.Add($"{acountAddress} code exp: {accountState.Code?.Length}, actual: {code?.Length}");
+ differences.Add($"{accountAddress} code exp: {accountState.Code?.Length}, actual: {code?.Length}");
}
if (differences.Count != differencesBefore)
{
- _logger.Info($"ACCOUNT STATE ({acountAddress}) HAS DIFFERENCES");
+ _logger.Info($"ACCOUNT STATE ({accountAddress}) HAS DIFFERENCES");
}
differencesBefore = differences.Count;
KeyValuePair[] clearedStorages = [];
- if (test.Pre.ContainsKey(acountAddress))
+ if (test.Pre.ContainsKey(accountAddress))
{
- clearedStorages = [.. test.Pre[acountAddress].Storage.Where(s => !accountState.Storage.ContainsKey(s.Key))];
+ clearedStorages = [.. test.Pre[accountAddress].Storage.Where(s => !accountState.Storage.ContainsKey(s.Key))];
}
foreach (KeyValuePair clearedStorage in clearedStorages)
{
- ReadOnlySpan value = !stateProvider.AccountExists(acountAddress) ? Bytes.Empty : stateProvider.Get(new StorageCell(acountAddress, clearedStorage.Key));
+ ReadOnlySpan value = !stateProvider.AccountExists(accountAddress) ? Bytes.Empty : stateProvider.Get(new StorageCell(accountAddress, clearedStorage.Key));
if (!value.IsZero())
{
- differences.Add($"{acountAddress} storage[{clearedStorage.Key}] exp: 0x00, actual: {value.ToHexString(true)}");
+ differences.Add($"{accountAddress} storage[{clearedStorage.Key}] exp: 0x00, actual: {value.ToHexString(true)}");
}
}
foreach (KeyValuePair storageItem in accountState.Storage)
{
- ReadOnlySpan value = !stateProvider.AccountExists(acountAddress) ? Bytes.Empty : stateProvider.Get(new StorageCell(acountAddress, storageItem.Key));
+ ReadOnlySpan value = !stateProvider.AccountExists(accountAddress) ? Bytes.Empty : stateProvider.Get(new StorageCell(accountAddress, storageItem.Key));
if (!Bytes.AreEqual(storageItem.Value, value))
{
- differences.Add($"{acountAddress} storage[{storageItem.Key}] exp: {storageItem.Value.ToHexString(true)}, actual: {value.ToHexString(true)}");
+ differences.Add($"{accountAddress} storage[{storageItem.Key}] exp: {storageItem.Value.ToHexString(true)}, actual: {value.ToHexString(true)}");
}
}
if (differences.Count != differencesBefore)
{
- _logger.Info($"ACCOUNT STORAGE ({acountAddress}) HAS DIFFERENCES");
+ _logger.Info($"ACCOUNT STORAGE ({accountAddress}) HAS DIFFERENCES");
}
}
- BigInteger gasUsed = headBlock.Header.GasUsed;
- if ((testHeader?.GasUsed ?? 0) != gasUsed)
- {
- differences.Add($"GAS USED exp: {testHeader?.GasUsed ?? 0}, actual: {gasUsed}");
- }
+ TestBlockHeaderJson? testHeaderJson = test.Blocks?
+ .Where(b => b.BlockHeader is not null)
+ .SingleOrDefault(b => new Hash256(b.BlockHeader.Hash) == headBlock.Hash)?.BlockHeader;
- if (headBlock.Transactions.Any() && testHeader.Bloom.ToString() != headBlock.Header.Bloom.ToString())
+ if (testHeaderJson is not null)
{
- differences.Add($"BLOOM exp: {testHeader.Bloom}, actual: {headBlock.Header.Bloom}");
- }
+ BlockHeader testHeader = JsonToEthereumTest.Convert(testHeaderJson);
- if (testHeader.StateRoot != stateProvider.StateRoot)
- {
- differences.Add($"STATE ROOT exp: {testHeader.StateRoot}, actual: {stateProvider.StateRoot}");
- }
+ BigInteger gasUsed = headBlock.Header.GasUsed;
+ if ((testHeader?.GasUsed ?? 0) != gasUsed)
+ {
+ differences.Add($"GAS USED exp: {testHeader?.GasUsed ?? 0}, actual: {gasUsed}");
+ }
- if (testHeader.TxRoot != headBlock.Header.TxRoot)
- {
- differences.Add($"TRANSACTIONS ROOT exp: {testHeader.TxRoot}, actual: {headBlock.Header.TxRoot}");
- }
+ if (headBlock.Transactions.Length != 0 && testHeader.Bloom.ToString() != headBlock.Header.Bloom.ToString())
+ {
+ differences.Add($"BLOOM exp: {testHeader.Bloom}, actual: {headBlock.Header.Bloom}");
+ }
- if (testHeader.ReceiptsRoot != headBlock.Header.ReceiptsRoot)
- {
- differences.Add($"RECEIPT ROOT exp: {testHeader.ReceiptsRoot}, actual: {headBlock.Header.ReceiptsRoot}");
+ if (testHeader.StateRoot != stateProvider.StateRoot)
+ {
+ differences.Add($"STATE ROOT exp: {testHeader.StateRoot}, actual: {stateProvider.StateRoot}");
+ }
+
+ if (testHeader.TxRoot != headBlock.Header.TxRoot)
+ {
+ differences.Add($"TRANSACTIONS ROOT exp: {testHeader.TxRoot}, actual: {headBlock.Header.TxRoot}");
+ }
+
+ if (testHeader.ReceiptsRoot != headBlock.Header.ReceiptsRoot)
+ {
+ differences.Add($"RECEIPT ROOT exp: {testHeader.ReceiptsRoot}, actual: {headBlock.Header.ReceiptsRoot}");
+ }
}
if (test.LastBlockHash != headBlock.Hash)
From 40c168d1676c8ad79ab45eaf47c3173de7fad722 Mon Sep 17 00:00:00 2001
From: Marc Harvey-Hill <10379486+Marchhill@users.noreply.github.com>
Date: Mon, 20 Oct 2025 17:08:46 +0100
Subject: [PATCH 10/26] add tracer to blockchain tests runner
---
.../BlockchainTestsRunner.cs | 38 ++++++++++---------
1 file changed, 21 insertions(+), 17 deletions(-)
diff --git a/src/Nethermind/Nethermind.Test.Runner/BlockchainTestsRunner.cs b/src/Nethermind/Nethermind.Test.Runner/BlockchainTestsRunner.cs
index b9b3013d39f5..9f055bf779a7 100644
--- a/src/Nethermind/Nethermind.Test.Runner/BlockchainTestsRunner.cs
+++ b/src/Nethermind/Nethermind.Test.Runner/BlockchainTestsRunner.cs
@@ -3,28 +3,26 @@
using System;
using System.Collections.Generic;
-using System.IO;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Ethereum.Test.Base;
using Ethereum.Test.Base.Interfaces;
+using Nethermind.Blockchain.Tracing.GethStyle;
+using Nethermind.Evm.Tracing;
namespace Nethermind.Test.Runner;
-public class BlockchainTestsRunner : BlockchainTestBase, IBlockchainTestRunner
+public class BlockchainTestsRunner(
+ ITestSourceLoader testsSource,
+ string? filter,
+ ulong chainId,
+ bool trace = false,
+ bool traceMemory = false,
+ bool traceNoStack = false)
+ : BlockchainTestBase, IBlockchainTestRunner
{
- private readonly ConsoleColor _defaultColour;
- private readonly ITestSourceLoader _testsSource;
- private readonly string? _filter;
- private readonly ulong _chainId;
-
- public BlockchainTestsRunner(ITestSourceLoader testsSource, string? filter, ulong chainId)
- {
- _testsSource = testsSource ?? throw new ArgumentNullException(nameof(testsSource));
- _defaultColour = Console.ForegroundColor;
- _filter = filter;
- _chainId = chainId;
- }
+ private readonly ConsoleColor _defaultColour = Console.ForegroundColor;
+ private readonly ITestSourceLoader _testsSource = testsSource ?? throw new ArgumentNullException(nameof(testsSource));
public async Task> RunTestsAsync()
{
@@ -39,9 +37,14 @@ public async Task> RunTestsAsync()
continue;
}
+ // Create a streaming tracer once for all tests if tracing is enabled
+ using BlockchainTestStreamingTracer? tracer = trace
+ ? new BlockchainTestStreamingTracer(new() { EnableMemory = traceMemory, DisableStack = traceNoStack })
+ : null;
+
BlockchainTest test = loadedTest as BlockchainTest;
- if (_filter is not null && !Regex.Match(test.Name, $"^({_filter})").Success)
+ if (filter is not null && test.Name is not null && !Regex.Match(test.Name, $"^({filter})").Success)
continue;
Setup();
@@ -53,8 +56,9 @@ public async Task> RunTestsAsync()
}
else
{
- test.ChainId = _chainId;
- EthereumTestResult result = await RunTest(test);
+ test.ChainId = chainId;
+
+ EthereumTestResult result = await RunTest(test, tracer: tracer);
testResults.Add(result);
if (result.Pass)
WriteGreen("PASS");
From 6ed4f1f723bda899a810692f08b8c155876a3efe Mon Sep 17 00:00:00 2001
From: Marc Harvey-Hill <10379486+Marchhill@users.noreply.github.com>
Date: Mon, 20 Oct 2025 17:31:34 +0100
Subject: [PATCH 11/26] tidy
---
.../Ethereum.Test.Base/BlockchainTestBase.cs | 17 +++++------------
.../Ethereum.Test.Base/FileTestsSource.cs | 13 ++++---------
.../LoadBlockchainTestFileStrategy.cs | 1 -
3 files changed, 9 insertions(+), 22 deletions(-)
diff --git a/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs b/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs
index 72a34b70137a..6d4a1b20c8c9 100644
--- a/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs
+++ b/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs
@@ -155,7 +155,6 @@ protected async Task RunTest(BlockchainTest test, Stopwatch?
test.GenesisRlp ??= Rlp.Encode(new Block(JsonToEthereumTest.Convert(test.GenesisBlockHeader)));
Block genesisBlock = Rlp.Decode(test.GenesisRlp.Bytes);
- // Console.WriteLine(genesisBlock.ToString(Block.Format.Full));
Assert.That(genesisBlock.Header.Hash, Is.EqualTo(new Hash256(test.GenesisBlockHeader.Hash)));
ManualResetEvent genesisProcessed = new(false);
@@ -328,7 +327,7 @@ private async static void RunNewPayloads(TestEngineNewPayloadsJson[]? newPayload
private static List<(Block Block, string ExpectedException)> DecodeRlps(BlockchainTest test, bool failOnInvalidRlp)
{
- List<(Block Block, string ExpectedException)> correctRlp = new();
+ List<(Block Block, string ExpectedException)> correctRlp = [];
for (int i = 0; i < test.Blocks!.Length; i++)
{
TestBlockJson testBlockJson = test.Blocks[i];
@@ -354,16 +353,10 @@ private async static void RunNewPayloads(TestEngineNewPayloadsJson[]? newPayload
if (testBlockJson.ExpectedException is null)
{
string invalidRlpMessage = $"Invalid RLP ({i}) {e}";
- if (failOnInvalidRlp)
- {
- Assert.Fail(invalidRlpMessage);
- }
- else
- {
- // ForgedTests don't have ExpectedException and at the same time have invalid rlps
- // Don't fail here. If test executed incorrectly will fail at last check
- _logger.Warn(invalidRlpMessage);
- }
+ Assert.That(!failOnInvalidRlp, invalidRlpMessage);
+ // ForgedTests don't have ExpectedException and at the same time have invalid rlps
+ // Don't fail here. If test executed incorrectly will fail at last check
+ _logger.Warn(invalidRlpMessage);
}
else
{
diff --git a/src/Nethermind/Ethereum.Test.Base/FileTestsSource.cs b/src/Nethermind/Ethereum.Test.Base/FileTestsSource.cs
index 3e85b70087f4..45e0b041ae02 100644
--- a/src/Nethermind/Ethereum.Test.Base/FileTestsSource.cs
+++ b/src/Nethermind/Ethereum.Test.Base/FileTestsSource.cs
@@ -9,16 +9,10 @@
namespace Ethereum.Test.Base
{
- public class FileTestsSource
+ public class FileTestsSource(string fileName, string? wildcard = null)
{
- private readonly string _fileName;
- private readonly string? _wildcard;
-
- public FileTestsSource(string fileName, string? wildcard = null)
- {
- _fileName = fileName ?? throw new ArgumentNullException(nameof(fileName));
- _wildcard = wildcard;
- }
+ private readonly string _fileName = fileName ?? throw new ArgumentNullException(nameof(fileName));
+ private readonly string? _wildcard = wildcard;
public IEnumerable LoadTests(TestType testType)
{
@@ -34,6 +28,7 @@ public IEnumerable LoadTests(TestType testType)
return [];
}
+ Console.WriteLine("Loading test " + _fileName);
string json = File.ReadAllText(_fileName, Encoding.Default);
return testType switch
diff --git a/src/Nethermind/Ethereum.Test.Base/LoadBlockchainTestFileStrategy.cs b/src/Nethermind/Ethereum.Test.Base/LoadBlockchainTestFileStrategy.cs
index 6f7aad55a2c3..71c23519184d 100644
--- a/src/Nethermind/Ethereum.Test.Base/LoadBlockchainTestFileStrategy.cs
+++ b/src/Nethermind/Ethereum.Test.Base/LoadBlockchainTestFileStrategy.cs
@@ -1,7 +1,6 @@
// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited
// SPDX-License-Identifier: LGPL-3.0-only
-using System;
using System.Collections.Generic;
using Ethereum.Test.Base.Interfaces;
From a4eb1754c5bfca802376c8c7a64711300c9015b0 Mon Sep 17 00:00:00 2001
From: Marc Harvey-Hill <10379486+Marchhill@users.noreply.github.com>
Date: Wed, 29 Oct 2025 19:25:57 +0000
Subject: [PATCH 12/26] tidy
---
.../Ethereum.Blockchain.Pyspec.Test/BerlinBlockChainTests.cs | 4 +++-
.../Ethereum.Blockchain.Pyspec.Test/BerlinStateTests.cs | 4 +++-
.../ByzantiumBlockChainTests.cs | 4 +++-
.../Ethereum.Blockchain.Pyspec.Test/ByzantiumStateTests.cs | 4 +++-
.../Ethereum.Blockchain.Pyspec.Test/CancunBlockChainTests.cs | 1 -
.../Ethereum.Blockchain.Pyspec.Test/CancunStateTests.cs | 1 -
.../FrontierBlockChainTests.cs | 4 +++-
.../Ethereum.Blockchain.Pyspec.Test/FrontierStateTests.cs | 4 +++-
.../HomesteadBlockChainTests.cs | 4 +++-
.../Ethereum.Blockchain.Pyspec.Test/HomesteadStateTests.cs | 4 +++-
.../IstanbulBlockChainTests.cs | 4 +++-
.../Ethereum.Blockchain.Pyspec.Test/IstanbulStateTests.cs | 4 +++-
.../Ethereum.Blockchain.Pyspec.Test/OsakaBlockChainTests.cs | 1 -
.../Ethereum.Blockchain.Pyspec.Test/OsakaEofTests.cs | 1 -
.../Ethereum.Blockchain.Pyspec.Test/OsakaStateTests.cs | 1 -
.../ShanghaiBlockChainTests.cs | 1 -
.../Ethereum.Blockchain.Pyspec.Test/ShanghaiStateTests.cs | 4 +++-
src/Nethermind/Ethereum.Test.Base/GeneralTestBase.cs | 3 ---
18 files changed, 33 insertions(+), 20 deletions(-)
diff --git a/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/BerlinBlockChainTests.cs b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/BerlinBlockChainTests.cs
index 264bc859ca77..5e202049eaf8 100644
--- a/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/BerlinBlockChainTests.cs
+++ b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/BerlinBlockChainTests.cs
@@ -1,5 +1,7 @@
+// SPDX-FileCopyrightText: 2025 Demerzel Solutions Limited
+// SPDX-License-Identifier: LGPL-3.0-only
+
using System.Collections.Generic;
-using System.Linq;
using System.Threading.Tasks;
using Ethereum.Test.Base;
using NUnit.Framework;
diff --git a/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/BerlinStateTests.cs b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/BerlinStateTests.cs
index cdc20c50d11a..cc32ed244b0f 100644
--- a/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/BerlinStateTests.cs
+++ b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/BerlinStateTests.cs
@@ -1,5 +1,7 @@
+// SPDX-FileCopyrightText: 2025 Demerzel Solutions Limited
+// SPDX-License-Identifier: LGPL-3.0-only
+
using System.Collections.Generic;
-using System.Linq;
using Ethereum.Test.Base;
using FluentAssertions;
using NUnit.Framework;
diff --git a/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/ByzantiumBlockChainTests.cs b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/ByzantiumBlockChainTests.cs
index b6be913b4c5d..3583300d49c2 100644
--- a/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/ByzantiumBlockChainTests.cs
+++ b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/ByzantiumBlockChainTests.cs
@@ -1,5 +1,7 @@
+// SPDX-FileCopyrightText: 2025 Demerzel Solutions Limited
+// SPDX-License-Identifier: LGPL-3.0-only
+
using System.Collections.Generic;
-using System.Linq;
using System.Threading.Tasks;
using Ethereum.Test.Base;
using NUnit.Framework;
diff --git a/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/ByzantiumStateTests.cs b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/ByzantiumStateTests.cs
index a650f3c79666..7579dc2ed9fc 100644
--- a/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/ByzantiumStateTests.cs
+++ b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/ByzantiumStateTests.cs
@@ -1,5 +1,7 @@
+// SPDX-FileCopyrightText: 2025 Demerzel Solutions Limited
+// SPDX-License-Identifier: LGPL-3.0-only
+
using System.Collections.Generic;
-using System.Linq;
using Ethereum.Test.Base;
using FluentAssertions;
using NUnit.Framework;
diff --git a/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/CancunBlockChainTests.cs b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/CancunBlockChainTests.cs
index 62695ccc71fd..da29277f3419 100644
--- a/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/CancunBlockChainTests.cs
+++ b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/CancunBlockChainTests.cs
@@ -2,7 +2,6 @@
// SPDX-License-Identifier: LGPL-3.0-only
using System.Collections.Generic;
-using System.Linq;
using System.Threading.Tasks;
using Ethereum.Test.Base;
using FluentAssertions;
diff --git a/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/CancunStateTests.cs b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/CancunStateTests.cs
index f1f952b6adde..9a7d2402270d 100644
--- a/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/CancunStateTests.cs
+++ b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/CancunStateTests.cs
@@ -2,7 +2,6 @@
// SPDX-License-Identifier: LGPL-3.0-only
using System.Collections.Generic;
-using System.Linq;
using Ethereum.Test.Base;
using FluentAssertions;
using NUnit.Framework;
diff --git a/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/FrontierBlockChainTests.cs b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/FrontierBlockChainTests.cs
index fae15df4b213..0b3c9a4a6417 100644
--- a/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/FrontierBlockChainTests.cs
+++ b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/FrontierBlockChainTests.cs
@@ -1,5 +1,7 @@
+// SPDX-FileCopyrightText: 2025 Demerzel Solutions Limited
+// SPDX-License-Identifier: LGPL-3.0-only
+
using System.Collections.Generic;
-using System.Linq;
using System.Threading.Tasks;
using Ethereum.Test.Base;
using NUnit.Framework;
diff --git a/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/FrontierStateTests.cs b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/FrontierStateTests.cs
index 6011d779adf7..fbf265a22a8d 100644
--- a/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/FrontierStateTests.cs
+++ b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/FrontierStateTests.cs
@@ -1,5 +1,7 @@
+// SPDX-FileCopyrightText: 2025 Demerzel Solutions Limited
+// SPDX-License-Identifier: LGPL-3.0-only
+
using System.Collections.Generic;
-using System.Linq;
using Ethereum.Test.Base;
using FluentAssertions;
using NUnit.Framework;
diff --git a/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/HomesteadBlockChainTests.cs b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/HomesteadBlockChainTests.cs
index eba45011cbb3..fc6bc1c07b95 100644
--- a/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/HomesteadBlockChainTests.cs
+++ b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/HomesteadBlockChainTests.cs
@@ -1,5 +1,7 @@
+// SPDX-FileCopyrightText: 2025 Demerzel Solutions Limited
+// SPDX-License-Identifier: LGPL-3.0-only
+
using System.Collections.Generic;
-using System.Linq;
using System.Threading.Tasks;
using Ethereum.Test.Base;
using NUnit.Framework;
diff --git a/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/HomesteadStateTests.cs b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/HomesteadStateTests.cs
index 44ec8d4041f5..0fec88659d02 100644
--- a/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/HomesteadStateTests.cs
+++ b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/HomesteadStateTests.cs
@@ -1,5 +1,7 @@
+// SPDX-FileCopyrightText: 2025 Demerzel Solutions Limited
+// SPDX-License-Identifier: LGPL-3.0-only
+
using System.Collections.Generic;
-using System.Linq;
using Ethereum.Test.Base;
using FluentAssertions;
using NUnit.Framework;
diff --git a/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/IstanbulBlockChainTests.cs b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/IstanbulBlockChainTests.cs
index af62090dd9e9..4ad81bb85f3a 100644
--- a/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/IstanbulBlockChainTests.cs
+++ b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/IstanbulBlockChainTests.cs
@@ -1,5 +1,7 @@
+// SPDX-FileCopyrightText: 2025 Demerzel Solutions Limited
+// SPDX-License-Identifier: LGPL-3.0-only
+
using System.Collections.Generic;
-using System.Linq;
using System.Threading.Tasks;
using Ethereum.Test.Base;
using NUnit.Framework;
diff --git a/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/IstanbulStateTests.cs b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/IstanbulStateTests.cs
index a4daf560f351..fe0f84a61d36 100644
--- a/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/IstanbulStateTests.cs
+++ b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/IstanbulStateTests.cs
@@ -1,5 +1,7 @@
+// SPDX-FileCopyrightText: 2025 Demerzel Solutions Limited
+// SPDX-License-Identifier: LGPL-3.0-only
+
using System.Collections.Generic;
-using System.Linq;
using Ethereum.Test.Base;
using FluentAssertions;
using NUnit.Framework;
diff --git a/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/OsakaBlockChainTests.cs b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/OsakaBlockChainTests.cs
index 6e8cafbada58..99231fdd948d 100644
--- a/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/OsakaBlockChainTests.cs
+++ b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/OsakaBlockChainTests.cs
@@ -2,7 +2,6 @@
// SPDX-License-Identifier: LGPL-3.0-only
using System.Collections.Generic;
-using System.Linq;
using System.Threading.Tasks;
using Ethereum.Test.Base;
using NUnit.Framework;
diff --git a/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/OsakaEofTests.cs b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/OsakaEofTests.cs
index 28326dea3909..874f6a40f6bb 100644
--- a/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/OsakaEofTests.cs
+++ b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/OsakaEofTests.cs
@@ -2,7 +2,6 @@
// SPDX-License-Identifier: LGPL-3.0-only
using System.Collections.Generic;
-using System.Linq;
using Ethereum.Test.Base;
using NUnit.Framework;
diff --git a/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/OsakaStateTests.cs b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/OsakaStateTests.cs
index 097c9c8f658c..d9c6248b9404 100644
--- a/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/OsakaStateTests.cs
+++ b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/OsakaStateTests.cs
@@ -2,7 +2,6 @@
// SPDX-License-Identifier: LGPL-3.0-only
using System.Collections.Generic;
-using System.Linq;
using Ethereum.Test.Base;
using FluentAssertions;
using NUnit.Framework;
diff --git a/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/ShanghaiBlockChainTests.cs b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/ShanghaiBlockChainTests.cs
index 2d273d715659..2e85ba8918d9 100644
--- a/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/ShanghaiBlockChainTests.cs
+++ b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/ShanghaiBlockChainTests.cs
@@ -2,7 +2,6 @@
// SPDX-License-Identifier: LGPL-3.0-only
using System.Collections.Generic;
-using System.Linq;
using System.Threading.Tasks;
using Ethereum.Test.Base;
using NUnit.Framework;
diff --git a/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/ShanghaiStateTests.cs b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/ShanghaiStateTests.cs
index 5c75a9b80c63..b8e304a15167 100644
--- a/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/ShanghaiStateTests.cs
+++ b/src/Nethermind/Ethereum.Blockchain.Pyspec.Test/ShanghaiStateTests.cs
@@ -1,5 +1,7 @@
+// SPDX-FileCopyrightText: 2025 Demerzel Solutions Limited
+// SPDX-License-Identifier: LGPL-3.0-only
+
using System.Collections.Generic;
-using System.Linq;
using Ethereum.Test.Base;
using FluentAssertions;
using NUnit.Framework;
diff --git a/src/Nethermind/Ethereum.Test.Base/GeneralTestBase.cs b/src/Nethermind/Ethereum.Test.Base/GeneralTestBase.cs
index 16e85265b851..6e7ad62e6356 100644
--- a/src/Nethermind/Ethereum.Test.Base/GeneralTestBase.cs
+++ b/src/Nethermind/Ethereum.Test.Base/GeneralTestBase.cs
@@ -5,7 +5,6 @@
using System.Collections.Generic;
using System.Diagnostics;
using Autofac;
-using Nethermind.Api;
using NUnit.Framework;
using Nethermind.Config;
using Nethermind.Consensus.Processing;
@@ -23,10 +22,8 @@
using Nethermind.Evm.State;
using Nethermind.Evm.TransactionProcessing;
using Nethermind.Logging;
-using Nethermind.Specs;
using Nethermind.Specs.Forks;
using Nethermind.Specs.Test;
-using Nethermind.State;
namespace Ethereum.Test.Base
{
From a55521308a6d678875adc02ab7d4ac152b2a0326 Mon Sep 17 00:00:00 2001
From: Marc Harvey-Hill <10379486+Marchhill@users.noreply.github.com>
Date: Wed, 29 Oct 2025 21:26:41 +0000
Subject: [PATCH 13/26] add genesis processing timeout
---
src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs b/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs
index 6d4a1b20c8c9..b43e7be9fff7 100644
--- a/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs
+++ b/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs
@@ -169,7 +169,7 @@ protected async Task RunTest(BlockchainTest test, Stopwatch?
};
blockTree.SuggestBlock(genesisBlock);
- genesisProcessed.WaitOne();
+ genesisProcessed.WaitOne(10000);
parentHeader = genesisBlock.Header;
// Dispose genesis block's AccountChanges
From b5d37c888be8574d4f526b74fe2c7f27eb92c320 Mon Sep 17 00:00:00 2001
From: Marc Harvey-Hill <10379486+Marchhill@users.noreply.github.com>
Date: Thu, 30 Oct 2025 10:35:45 +0000
Subject: [PATCH 14/26] check for null head block
---
.../Ethereum.Test.Base/BlockchainTestBase.cs | 17 +++++++++--------
1 file changed, 9 insertions(+), 8 deletions(-)
diff --git a/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs b/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs
index b43e7be9fff7..e17569cfcbd8 100644
--- a/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs
+++ b/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs
@@ -169,7 +169,7 @@ protected async Task RunTest(BlockchainTest test, Stopwatch?
};
blockTree.SuggestBlock(genesisBlock);
- genesisProcessed.WaitOne(10000);
+ genesisProcessed.WaitOne(5000);
parentHeader = genesisBlock.Header;
// Dispose genesis block's AccountChanges
@@ -201,6 +201,13 @@ protected async Task RunTest(BlockchainTest test, Stopwatch?
preWarmer?.ClearCaches();
Block? headBlock = blockTree.RetrieveHeadBlock();
+
+ Assert.That(headBlock, Is.Not.Null);
+ if (headBlock is null)
+ {
+ return new EthereumTestResult(test.Name, null, false);
+ }
+
List differences;
using (stateProvider.BeginScope(headBlock.Header))
{
@@ -218,13 +225,7 @@ protected async Task RunTest(BlockchainTest test, Stopwatch?
}
Assert.That(differences, Is.Empty, "differences");
-
- return new EthereumTestResult
- (
- test.Name,
- null,
- differences.Count == 0
- );
+ return new EthereumTestResult(test.Name, null, differences.Count == 0);
}
catch (Exception)
{
From eba035c108789a7781fc3c7b01686ff337ffb3de Mon Sep 17 00:00:00 2001
From: Marc Harvey-Hill <10379486+Marchhill@users.noreply.github.com>
Date: Thu, 30 Oct 2025 10:57:31 +0000
Subject: [PATCH 15/26] try undo some changes
---
src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs | 6 +++++-
src/Nethermind/Ethereum.Test.Base/GeneralTestBase.cs | 6 +++++-
.../Ethereum.Test.Base/Interfaces/EthereumTest.cs | 6 +++---
3 files changed, 13 insertions(+), 5 deletions(-)
diff --git a/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs b/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs
index e17569cfcbd8..635bc6057ed5 100644
--- a/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs
+++ b/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs
@@ -42,11 +42,13 @@ public abstract class BlockchainTestBase
{
private static readonly ILogger _logger;
private static readonly ILogManager _logManager = new TestLogManager();
+ private static ISealValidator Sealer { get; }
private static DifficultyCalculatorWrapper DifficultyCalculator { get; }
static BlockchainTestBase()
{
DifficultyCalculator = new DifficultyCalculatorWrapper();
+ Sealer = new EthashSealValidator(_logManager, DifficultyCalculator, new CryptoRandom(), new Ethash(_logManager), Timestamper.Default); // temporarily keep reusing the same one as otherwise it would recreate cache for each test
_logManager ??= LimboLogs.Instance;
_logger = _logManager.GetClassLogger();
}
@@ -82,7 +84,9 @@ protected async Task RunTest(BlockchainTest test, Stopwatch?
test.Network = ChainUtils.ResolveSpec(test.Network, test.ChainId);
test.NetworkAfterTransition = ChainUtils.ResolveSpec(test.NetworkAfterTransition, test.ChainId);
- List<(ForkActivation Activation, IReleaseSpec Spec)> transitions = [((ForkActivation)0, test.Network)];
+ // List<(ForkActivation Activation, IReleaseSpec Spec)> transitions = [((ForkActivation)0, test.Network)];
+ List<(ForkActivation Activation, IReleaseSpec Spec)> transitions =
+ [((ForkActivation)0, test.GenesisSpec), ((ForkActivation)1, test.Network)]; // TODO: this thing took a lot of time to find after it was removed!, genesis block is always initialized with Frontier
if (test.NetworkAfterTransition is not null)
{
transitions.Add((test.TransitionForkActivation!.Value, test.NetworkAfterTransition));
diff --git a/src/Nethermind/Ethereum.Test.Base/GeneralTestBase.cs b/src/Nethermind/Ethereum.Test.Base/GeneralTestBase.cs
index 6e7ad62e6356..a98d9360e7fc 100644
--- a/src/Nethermind/Ethereum.Test.Base/GeneralTestBase.cs
+++ b/src/Nethermind/Ethereum.Test.Base/GeneralTestBase.cs
@@ -65,7 +65,11 @@ protected EthereumTestResult RunTest(GeneralStateTest test, ITxTracer txTracer)
test.Fork = ChainUtils.ResolveSpec(test.Fork, test.ChainId);
- ISpecProvider specProvider = new CustomSpecProvider(test.ChainId, test.ChainId, ((ForkActivation)0, test.Fork));
+ // ISpecProvider specProvider = new CustomSpecProvider(test.ChainId, test.ChainId, ((ForkActivation)0, test.Fork));
+ ISpecProvider specProvider =
+ new CustomSpecProvider(test.ChainId, test.ChainId,
+ ((ForkActivation)0, test.GenesisSpec), // TODO: this thing took a lot of time to find after it was removed!, genesis block is always initialized with Frontier
+ ((ForkActivation)1, test.Fork));
IConfigProvider configProvider = new ConfigProvider();
using IContainer container = new ContainerBuilder()
diff --git a/src/Nethermind/Ethereum.Test.Base/Interfaces/EthereumTest.cs b/src/Nethermind/Ethereum.Test.Base/Interfaces/EthereumTest.cs
index 03e55c585a0e..d64cf0a6d6da 100644
--- a/src/Nethermind/Ethereum.Test.Base/Interfaces/EthereumTest.cs
+++ b/src/Nethermind/Ethereum.Test.Base/Interfaces/EthereumTest.cs
@@ -9,8 +9,8 @@ public abstract class EthereumTest
public string? Name { get; set; }
public string? LoadFailure { get; set; }
public ulong ChainId { get; set; } = MainnetSpecProvider.Instance.ChainId;
- // public IReleaseSpec GenesisSpec => ChainId == MainnetSpecProvider.Instance.ChainId
- // ? MainnetSpecProvider.Instance.GenesisSpec
- // : GnosisSpecProvider.Instance.GenesisSpec;
+ public IReleaseSpec GenesisSpec => ChainId == MainnetSpecProvider.Instance.ChainId
+ ? MainnetSpecProvider.Instance.GenesisSpec
+ : GnosisSpecProvider.Instance.GenesisSpec;
}
}
From 802abc9ce0e337fdb0cf5708528fd5b553b9263a Mon Sep 17 00:00:00 2001
From: Marc Harvey-Hill <10379486+Marchhill@users.noreply.github.com>
Date: Thu, 30 Oct 2025 11:42:36 +0000
Subject: [PATCH 16/26] detect failure to process genesis
---
.../Ethereum.Test.Base/BlockchainTestBase.cs | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs b/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs
index 635bc6057ed5..99f20986a6b2 100644
--- a/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs
+++ b/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs
@@ -134,7 +134,7 @@ protected async Task RunTest(BlockchainTest test, Stopwatch?
IMainProcessingContext mainBlockProcessingContext = container.Resolve();
IWorldState stateProvider = mainBlockProcessingContext.WorldState;
- IBlockchainProcessor blockchainProcessor = mainBlockProcessingContext.BlockchainProcessor;
+ BlockchainProcessor blockchainProcessor = (BlockchainProcessor)mainBlockProcessingContext.BlockchainProcessor;
IBlockTree blockTree = container.Resolve();
IBlockValidator blockValidator = container.Resolve();
IEngineRpcModule engineRpcModule = container.Resolve();
@@ -172,6 +172,15 @@ protected async Task RunTest(BlockchainTest test, Stopwatch?
}
};
+ blockchainProcessor.BlockRemoved += (_, args) =>
+ {
+ if (args.BlockHash == genesisBlock.Header.Hash)
+ {
+ Assert.Fail($"Failed to process genesis block: {args.Exception}");
+ genesisProcessed.Set();
+ }
+ };
+
blockTree.SuggestBlock(genesisBlock);
genesisProcessed.WaitOne(5000);
parentHeader = genesisBlock.Header;
From bfbcfbba99681ade131ad131133ebdaf63b70401 Mon Sep 17 00:00:00 2001
From: Marc Harvey-Hill <10379486+Marchhill@users.noreply.github.com>
Date: Thu, 30 Oct 2025 11:50:43 +0000
Subject: [PATCH 17/26] check removal is error
---
src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs b/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs
index 99f20986a6b2..b86b90832f32 100644
--- a/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs
+++ b/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs
@@ -174,7 +174,7 @@ protected async Task RunTest(BlockchainTest test, Stopwatch?
blockchainProcessor.BlockRemoved += (_, args) =>
{
- if (args.BlockHash == genesisBlock.Header.Hash)
+ if (args.ProcessingResult != ProcessingResult.Success && args.BlockHash == genesisBlock.Header.Hash)
{
Assert.Fail($"Failed to process genesis block: {args.Exception}");
genesisProcessed.Set();
From c1f5bc3111c22925f566a271e4af3dbabfcde2f6 Mon Sep 17 00:00:00 2001
From: Marc Harvey-Hill <10379486+Marchhill@users.noreply.github.com>
Date: Thu, 30 Oct 2025 11:59:04 +0000
Subject: [PATCH 18/26] add back checks for genesis spec
---
.../Ethereum.Test.Base/BlockchainTestBase.cs | 10 +++++++++-
src/Nethermind/Ethereum.Test.Base/GeneralTestBase.cs | 9 +++++++--
2 files changed, 16 insertions(+), 3 deletions(-)
diff --git a/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs b/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs
index b86b90832f32..4d7b5ac07a07 100644
--- a/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs
+++ b/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs
@@ -26,6 +26,7 @@
using Nethermind.Int256;
using Nethermind.Logging;
using Nethermind.Serialization.Rlp;
+using Nethermind.Specs;
using Nethermind.Specs.Forks;
using Nethermind.Specs.Test;
using Nethermind.Evm.State;
@@ -84,9 +85,13 @@ protected async Task RunTest(BlockchainTest test, Stopwatch?
test.Network = ChainUtils.ResolveSpec(test.Network, test.ChainId);
test.NetworkAfterTransition = ChainUtils.ResolveSpec(test.NetworkAfterTransition, test.ChainId);
- // List<(ForkActivation Activation, IReleaseSpec Spec)> transitions = [((ForkActivation)0, test.Network)];
+ bool isEngineTest = test.Blocks is null && test.EngineNewPayloads is not null;
+
List<(ForkActivation Activation, IReleaseSpec Spec)> transitions =
+ isEngineTest ?
+ [((ForkActivation)0, test.Network)] :
[((ForkActivation)0, test.GenesisSpec), ((ForkActivation)1, test.Network)]; // TODO: this thing took a lot of time to find after it was removed!, genesis block is always initialized with Frontier
+
if (test.NetworkAfterTransition is not null)
{
transitions.Add((test.TransitionForkActivation!.Value, test.NetworkAfterTransition));
@@ -94,6 +99,8 @@ protected async Task RunTest(BlockchainTest test, Stopwatch?
ISpecProvider specProvider = new CustomSpecProvider(test.ChainId, test.ChainId, transitions.ToArray());
+ Assert.That(!isEngineTest && (test.ChainId == GnosisSpecProvider.Instance.ChainId || specProvider.GenesisSpec == Frontier.Instance), "Expected genesis spec to be Frontier for blockchain tests");
+
if (test.Network is Cancun || test.NetworkAfterTransition is Cancun)
{
await KzgPolynomialCommitments.InitializeAsync();
@@ -196,6 +203,7 @@ protected async Task RunTest(BlockchainTest test, Stopwatch?
}
else if (test.EngineNewPayloads is not null)
{
+ // engine test
RunNewPayloads(test.EngineNewPayloads, engineRpcModule);
}
else
diff --git a/src/Nethermind/Ethereum.Test.Base/GeneralTestBase.cs b/src/Nethermind/Ethereum.Test.Base/GeneralTestBase.cs
index a98d9360e7fc..f0167769b2fa 100644
--- a/src/Nethermind/Ethereum.Test.Base/GeneralTestBase.cs
+++ b/src/Nethermind/Ethereum.Test.Base/GeneralTestBase.cs
@@ -22,6 +22,7 @@
using Nethermind.Evm.State;
using Nethermind.Evm.TransactionProcessing;
using Nethermind.Logging;
+using Nethermind.Specs;
using Nethermind.Specs.Forks;
using Nethermind.Specs.Test;
@@ -41,7 +42,7 @@ static GeneralStateTestBase()
}
[SetUp]
- public static void Setup()
+ public void Setup()
{
}
@@ -65,12 +66,16 @@ protected EthereumTestResult RunTest(GeneralStateTest test, ITxTracer txTracer)
test.Fork = ChainUtils.ResolveSpec(test.Fork, test.ChainId);
- // ISpecProvider specProvider = new CustomSpecProvider(test.ChainId, test.ChainId, ((ForkActivation)0, test.Fork));
ISpecProvider specProvider =
new CustomSpecProvider(test.ChainId, test.ChainId,
((ForkActivation)0, test.GenesisSpec), // TODO: this thing took a lot of time to find after it was removed!, genesis block is always initialized with Frontier
((ForkActivation)1, test.Fork));
+ if (test.ChainId != GnosisSpecProvider.Instance.ChainId && specProvider.GenesisSpec != Frontier.Instance)
+ {
+ Assert.Fail("Expected genesis spec to be Frontier for blockchain tests");
+ }
+
IConfigProvider configProvider = new ConfigProvider();
using IContainer container = new ContainerBuilder()
.AddModule(new TestNethermindModule(configProvider))
From a213860f69a4ed5df68a3edc0b678415fabead90 Mon Sep 17 00:00:00 2001
From: Marc Harvey-Hill <10379486+Marchhill@users.noreply.github.com>
Date: Thu, 30 Oct 2025 12:02:35 +0000
Subject: [PATCH 19/26] only add noenginerequeststracker in tests
---
.../Nethermind.Core.Test/Modules/TestMergeModule.cs | 4 +++-
src/Nethermind/Nethermind.Merge.Plugin/MergePlugin.cs | 1 -
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/src/Nethermind/Nethermind.Core.Test/Modules/TestMergeModule.cs b/src/Nethermind/Nethermind.Core.Test/Modules/TestMergeModule.cs
index 18347180f0fa..2a930771c265 100644
--- a/src/Nethermind/Nethermind.Core.Test/Modules/TestMergeModule.cs
+++ b/src/Nethermind/Nethermind.Core.Test/Modules/TestMergeModule.cs
@@ -11,7 +11,6 @@
using Nethermind.Consensus.Rewards;
using Nethermind.Merge.Plugin;
using Nethermind.Merge.Plugin.BlockProduction;
-using Nethermind.Merge.Plugin.InvalidChainTracker;
using Nethermind.TxPool;
namespace Nethermind.Core.Test.Modules;
@@ -43,6 +42,9 @@ protected override void Load(ContainerBuilder builder)
.AddDecorator()
.AddScoped()
.AddDecorator()
+
+ // Engine rpc
+ .AddSingleton()
;
if (txPoolConfig.BlobsSupport.SupportsReorgs())
diff --git a/src/Nethermind/Nethermind.Merge.Plugin/MergePlugin.cs b/src/Nethermind/Nethermind.Merge.Plugin/MergePlugin.cs
index f5d933da50df..5a350188359c 100644
--- a/src/Nethermind/Nethermind.Merge.Plugin/MergePlugin.cs
+++ b/src/Nethermind/Nethermind.Merge.Plugin/MergePlugin.cs
@@ -328,7 +328,6 @@ protected override void Load(ContainerBuilder builder)
.AddSingleton()
.AddSingleton>, GetBlobsHandler>()
.AddSingleton?>, GetBlobsHandlerV2>()
- .AddSingleton()
.AddSingleton()
.AddSingleton((ctx) =>
From 176cf575586e898851ddfefb352928b7a335ac19 Mon Sep 17 00:00:00 2001
From: Marc Harvey-Hill <10379486+Marchhill@users.noreply.github.com>
Date: Thu, 30 Oct 2025 12:15:54 +0000
Subject: [PATCH 20/26] comment sealed block check
---
src/Nethermind/Nethermind.Trie/Pruning/TrieStore.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/Nethermind/Nethermind.Trie/Pruning/TrieStore.cs b/src/Nethermind/Nethermind.Trie/Pruning/TrieStore.cs
index c203a906dce6..2279e6438249 100644
--- a/src/Nethermind/Nethermind.Trie/Pruning/TrieStore.cs
+++ b/src/Nethermind/Nethermind.Trie/Pruning/TrieStore.cs
@@ -935,7 +935,7 @@ private void VerifyNewCommitSet(long blockNumber)
{
if (_lastCommitSet is not null)
{
- Debug.Assert(_lastCommitSet.IsSealed, "Not sealed when beginning new block");
+ // Debug.Assert(_lastCommitSet.IsSealed, "Not sealed when beginning new block");
if (_lastCommitSet.BlockNumber != blockNumber - 1 && blockNumber != 0 && _lastCommitSet.BlockNumber != 0)
{
From 5d4cd477bf53ba0b10fed603ceb82886fe71ca77 Mon Sep 17 00:00:00 2001
From: Marc Harvey-Hill <10379486+Marchhill@users.noreply.github.com>
Date: Thu, 30 Oct 2025 12:38:54 +0000
Subject: [PATCH 21/26] try remove timeout
---
src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs | 2 +-
src/Nethermind/Nethermind.Trie/Pruning/TrieStore.cs | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs b/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs
index 4d7b5ac07a07..3a023070193e 100644
--- a/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs
+++ b/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs
@@ -189,7 +189,7 @@ protected async Task RunTest(BlockchainTest test, Stopwatch?
};
blockTree.SuggestBlock(genesisBlock);
- genesisProcessed.WaitOne(5000);
+ genesisProcessed.WaitOne();
parentHeader = genesisBlock.Header;
// Dispose genesis block's AccountChanges
diff --git a/src/Nethermind/Nethermind.Trie/Pruning/TrieStore.cs b/src/Nethermind/Nethermind.Trie/Pruning/TrieStore.cs
index 2279e6438249..c203a906dce6 100644
--- a/src/Nethermind/Nethermind.Trie/Pruning/TrieStore.cs
+++ b/src/Nethermind/Nethermind.Trie/Pruning/TrieStore.cs
@@ -935,7 +935,7 @@ private void VerifyNewCommitSet(long blockNumber)
{
if (_lastCommitSet is not null)
{
- // Debug.Assert(_lastCommitSet.IsSealed, "Not sealed when beginning new block");
+ Debug.Assert(_lastCommitSet.IsSealed, "Not sealed when beginning new block");
if (_lastCommitSet.BlockNumber != blockNumber - 1 && blockNumber != 0 && _lastCommitSet.BlockNumber != 0)
{
From 954c1329a515f4aeb06e1bdaabec3c5fa6b98406 Mon Sep 17 00:00:00 2001
From: Marc Harvey-Hill <10379486+Marchhill@users.noreply.github.com>
Date: Thu, 30 Oct 2025 12:47:35 +0000
Subject: [PATCH 22/26] only configure merge for engine tests
---
.../Ethereum.Test.Base/BlockchainTestBase.cs | 17 +++++++++++------
1 file changed, 11 insertions(+), 6 deletions(-)
diff --git a/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs b/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs
index 3a023070193e..cade76f24165 100644
--- a/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs
+++ b/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs
@@ -129,22 +129,26 @@ protected async Task RunTest(BlockchainTest test, Stopwatch?
IConfigProvider configProvider = new ConfigProvider();
// configProvider.GetConfig().PreWarmStateOnBlockProcessing = false;
- await using IContainer container = new ContainerBuilder()
+ ContainerBuilder containerBuilder = new ContainerBuilder()
.AddModule(new TestNethermindModule(configProvider))
.AddModule(new TestMergeModule(configProvider))
.AddSingleton(specProvider)
.AddSingleton(_logManager)
.AddSingleton(rewardCalculator)
- .AddSingleton(DifficultyCalculator)
- .AddSingleton(NullTxPool.Instance)
- .Build();
+ .AddSingleton(DifficultyCalculator);
+
+ if (isEngineTest)
+ {
+ containerBuilder.AddModule(new TestMergeModule(configProvider));
+ }
+
+ await using IContainer container = containerBuilder.Build();
IMainProcessingContext mainBlockProcessingContext = container.Resolve();
IWorldState stateProvider = mainBlockProcessingContext.WorldState;
BlockchainProcessor blockchainProcessor = (BlockchainProcessor)mainBlockProcessingContext.BlockchainProcessor;
IBlockTree blockTree = container.Resolve();
IBlockValidator blockValidator = container.Resolve();
- IEngineRpcModule engineRpcModule = container.Resolve();
blockchainProcessor.Start();
// Register tracer if provided for blocktest tracing
@@ -204,6 +208,7 @@ protected async Task RunTest(BlockchainTest test, Stopwatch?
else if (test.EngineNewPayloads is not null)
{
// engine test
+ IEngineRpcModule engineRpcModule = container.Resolve();
RunNewPayloads(test.EngineNewPayloads, engineRpcModule);
}
else
@@ -246,7 +251,7 @@ protected async Task RunTest(BlockchainTest test, Stopwatch?
}
Assert.That(differences, Is.Empty, "differences");
- return new EthereumTestResult(test.Name, null, differences.Count == 0);
+ return new EthereumTestResult(test.Name, null, testPassed);
}
catch (Exception)
{
From c1ef3537a47d948d6affd57d000e2bee52295eab Mon Sep 17 00:00:00 2001
From: Marc Harvey-Hill <10379486+Marchhill@users.noreply.github.com>
Date: Thu, 30 Oct 2025 12:49:15 +0000
Subject: [PATCH 23/26] fix merge module init
---
src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs b/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs
index cade76f24165..20ec4f56082e 100644
--- a/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs
+++ b/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs
@@ -131,12 +131,11 @@ protected async Task RunTest(BlockchainTest test, Stopwatch?
// configProvider.GetConfig().PreWarmStateOnBlockProcessing = false;
ContainerBuilder containerBuilder = new ContainerBuilder()
.AddModule(new TestNethermindModule(configProvider))
- .AddModule(new TestMergeModule(configProvider))
.AddSingleton(specProvider)
.AddSingleton(_logManager)
.AddSingleton(rewardCalculator)
.AddSingleton(DifficultyCalculator);
-
+
if (isEngineTest)
{
containerBuilder.AddModule(new TestMergeModule(configProvider));
From 063f70d9245ed6ae7988f261b09ffb00968c348e Mon Sep 17 00:00:00 2001
From: Marc Harvey-Hill <10379486+Marchhill@users.noreply.github.com>
Date: Thu, 30 Oct 2025 12:54:51 +0000
Subject: [PATCH 24/26] add back timeout and remove sealer
---
src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs b/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs
index 20ec4f56082e..53fb9866be2a 100644
--- a/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs
+++ b/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs
@@ -31,7 +31,6 @@
using Nethermind.Specs.Test;
using Nethermind.Evm.State;
using Nethermind.Init.Modules;
-using Nethermind.TxPool;
using NUnit.Framework;
using Nethermind.Merge.Plugin.Data;
using Nethermind.Merge.Plugin;
@@ -43,13 +42,12 @@ public abstract class BlockchainTestBase
{
private static readonly ILogger _logger;
private static readonly ILogManager _logManager = new TestLogManager();
- private static ISealValidator Sealer { get; }
private static DifficultyCalculatorWrapper DifficultyCalculator { get; }
+ private const int _genesisProcessingTimeoutMs = 5000;
static BlockchainTestBase()
{
DifficultyCalculator = new DifficultyCalculatorWrapper();
- Sealer = new EthashSealValidator(_logManager, DifficultyCalculator, new CryptoRandom(), new Ethash(_logManager), Timestamper.Default); // temporarily keep reusing the same one as otherwise it would recreate cache for each test
_logManager ??= LimboLogs.Instance;
_logger = _logManager.GetClassLogger();
}
@@ -192,7 +190,7 @@ protected async Task RunTest(BlockchainTest test, Stopwatch?
};
blockTree.SuggestBlock(genesisBlock);
- genesisProcessed.WaitOne();
+ genesisProcessed.WaitOne(_genesisProcessingTimeoutMs);
parentHeader = genesisBlock.Header;
// Dispose genesis block's AccountChanges
From 1c6ae5180ff7b8549fa945996952eef955e8abc6 Mon Sep 17 00:00:00 2001
From: Marc Harvey-Hill <10379486+Marchhill@users.noreply.github.com>
Date: Fri, 31 Oct 2025 12:56:58 +0000
Subject: [PATCH 25/26] await new payloads
---
src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs b/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs
index 53fb9866be2a..baeeec596c05 100644
--- a/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs
+++ b/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs
@@ -97,7 +97,7 @@ protected async Task RunTest(BlockchainTest test, Stopwatch?
ISpecProvider specProvider = new CustomSpecProvider(test.ChainId, test.ChainId, transitions.ToArray());
- Assert.That(!isEngineTest && (test.ChainId == GnosisSpecProvider.Instance.ChainId || specProvider.GenesisSpec == Frontier.Instance), "Expected genesis spec to be Frontier for blockchain tests");
+ Assert.That(isEngineTest || test.ChainId == GnosisSpecProvider.Instance.ChainId || specProvider.GenesisSpec == Frontier.Instance, "Expected genesis spec to be Frontier for blockchain tests");
if (test.Network is Cancun || test.NetworkAfterTransition is Cancun)
{
@@ -206,7 +206,7 @@ protected async Task RunTest(BlockchainTest test, Stopwatch?
{
// engine test
IEngineRpcModule engineRpcModule = container.Resolve();
- RunNewPayloads(test.EngineNewPayloads, engineRpcModule);
+ await RunNewPayloads(test.EngineNewPayloads, engineRpcModule);
}
else
{
@@ -309,7 +309,7 @@ private static BlockHeader SuggestBlocks(BlockchainTest test, bool failOnInvalid
return parentHeader;
}
- private async static void RunNewPayloads(TestEngineNewPayloadsJson[]? newPayloads, IEngineRpcModule engineRpcModule)
+ private async static Task RunNewPayloads(TestEngineNewPayloadsJson[]? newPayloads, IEngineRpcModule engineRpcModule)
{
(ExecutionPayload, string[]?, string[]?, string?)[] payloads = [.. JsonToEthereumTest.Convert(newPayloads)];
@@ -319,7 +319,7 @@ private async static void RunNewPayloads(TestEngineNewPayloadsJson[]? newPayload
ResultWrapper res;
byte[]?[] hashes = blobVersionedHashes is null ? null : [.. blobVersionedHashes.Select(x => Bytes.FromHexString(x))];
- switch (newPayloadVersion ?? "5")
+ switch (newPayloadVersion ?? "4")
{
case "1":
res = await engineRpcModule.engine_newPayloadV1(executionPayload);
From 684d01413e3494ac94434da7d41da2afda09a1ad Mon Sep 17 00:00:00 2001
From: Marc Harvey-Hill <10379486+Marchhill@users.noreply.github.com>
Date: Fri, 31 Oct 2025 13:28:08 +0000
Subject: [PATCH 26/26] use reflection for engine rpc method calling
---
.../Ethereum.Test.Base/BlockchainTestBase.cs | 43 ++++++++-----------
.../Ethereum.Test.Base/JsonToEthereumTest.cs | 4 +-
2 files changed, 20 insertions(+), 27 deletions(-)
diff --git a/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs b/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs
index baeeec596c05..ee72db8fead6 100644
--- a/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs
+++ b/src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs
@@ -35,6 +35,7 @@
using Nethermind.Merge.Plugin.Data;
using Nethermind.Merge.Plugin;
using Nethermind.JsonRpc;
+using System.Reflection;
namespace Ethereum.Test.Base;
@@ -311,40 +312,32 @@ private static BlockHeader SuggestBlocks(BlockchainTest test, bool failOnInvalid
private async static Task RunNewPayloads(TestEngineNewPayloadsJson[]? newPayloads, IEngineRpcModule engineRpcModule)
{
- (ExecutionPayload, string[]?, string[]?, string?)[] payloads = [.. JsonToEthereumTest.Convert(newPayloads)];
+ (ExecutionPayloadV3, string[]?, string[]?, int, int)[] payloads = [.. JsonToEthereumTest.Convert(newPayloads)];
// blockchain test engine
- foreach ((ExecutionPayload executionPayload, string[]? blobVersionedHashes, string[]? validationError, string? newPayloadVersion) in payloads)
+ foreach ((ExecutionPayload executionPayload, string[]? blobVersionedHashes, string[]? validationError, int newPayloadVersion, int fcuVersion) in payloads)
{
ResultWrapper res;
- byte[]?[] hashes = blobVersionedHashes is null ? null : [.. blobVersionedHashes.Select(x => Bytes.FromHexString(x))];
-
- switch (newPayloadVersion ?? "4")
- {
- case "1":
- res = await engineRpcModule.engine_newPayloadV1(executionPayload);
- break;
- case "2":
- res = await engineRpcModule.engine_newPayloadV2(executionPayload);
- break;
- case "3":
- res = await engineRpcModule.engine_newPayloadV3((ExecutionPayloadV3)executionPayload, [], executionPayload.ParentBeaconBlockRoot);
- break;
- case "4":
- res = await engineRpcModule.engine_newPayloadV4((ExecutionPayloadV3)executionPayload, hashes, executionPayload.ParentBeaconBlockRoot, []);
- break;
- // case "5":
- // res = await engineRpcModule.engine_newPayloadV5((ExecutionPayloadV3)executionPayload, hashes, executionPayload.ParentBeaconBlockRoot, []);
- // break;
- default:
- Assert.Fail("Invalid blockchain engine test, version not recognised.");
- continue;
+ byte[]?[] hashes = blobVersionedHashes is null ? [] : [.. blobVersionedHashes.Select(x => Bytes.FromHexString(x))];
+
+ MethodInfo newPayloadMethod = engineRpcModule.GetType().GetMethod($"engine_newPayloadV{newPayloadVersion}");
+ List