Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature t8n gnosis #7319

Merged
merged 9 commits into from
Oct 16, 2024
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 54 additions & 20 deletions src/Nethermind/Ethereum.Test.Base/GeneralTestBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
using NUnit.Framework;
using System.Threading.Tasks;
using Ethereum.Test.Base.T8NUtils;
using Microsoft.IdentityModel.Tokens;
using Nethermind.Consensus.BeaconBlockRoot;
using Nethermind.Consensus.Rewards;
using Nethermind.Consensus.Withdrawals;
Expand All @@ -41,7 +40,7 @@ public abstract class GeneralStateTestBase
private static ILogger _logger = new(new ConsoleAsyncLogger(LogLevel.Info));
private static ILogManager _logManager = LimboLogs.Instance;
private static readonly UInt256 _defaultBaseFeeForStateTest = 0xA;
private readonly TxValidator _txValidator = new(MainnetSpecProvider.Instance.ChainId);
private TxValidator? _txValidator;
private readonly BeaconBlockRootHandler _beaconBlockRootHandler = new();

[SetUp]
Expand All @@ -58,27 +57,43 @@ protected static void Setup(ILogManager logManager)
_logger = _logManager.GetClassLogger();
}

protected EthereumTestResult RunTest(GeneralStateTest test)
protected EthereumTestResult RunTest(GeneralStateTest test, bool isGnosis = false)
{
return RunTest(test, NullTxTracer.Instance);
return RunTest(test, NullTxTracer.Instance, isGnosis);
}

protected EthereumTestResult RunTest(GeneralStateTest test, ITxTracer txTracer)
protected EthereumTestResult RunTest(GeneralStateTest test, ITxTracer txTracer, bool isGnosis = false)
{
TestContext.Write($"Running {test.Name} at {DateTime.UtcNow:HH:mm:ss.ffffff}");
Assert.IsNull(test.LoadFailure, "test data loading failure");

_txValidator = new TxValidator(test.StateChainId);

IDb stateDb = new MemDb();
IDb codeDb = new MemDb();

ISpecProvider specProvider = new CustomSpecProvider(
((ForkActivation)0, Frontier.Instance), // 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));
ISpecProvider specProvider;
if (isGnosis)
{
specProvider = new CustomSpecProvider(
((ForkActivation)0,
GnosisSpecProvider.Instance
.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));
}
else
{
specProvider = new CustomSpecProvider(
((ForkActivation)0,
Frontier
.Instance), // 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 (specProvider.GenesisSpec != Frontier.Instance)
{
Assert.Fail("Expected genesis spec to be Frontier for blockchain tests");
}

IReleaseSpec? spec = specProvider.GetSpec((ForkActivation)test.CurrentNumber);

BlockHeader header = test.GetBlockHeader();
Expand All @@ -88,6 +103,7 @@ protected EthereumTestResult RunTest(GeneralStateTest test, ITxTracer txTracer)
{
test.CurrentBaseFee = header.BaseFeePerGas = CalculateBaseFeePerGas(test, parentHeader);
}

if (parentHeader != null)
{
header.ExcessBlobGas = BlobGasCalculator.CalculateExcessBlobGas(parentHeader, spec);
Expand Down Expand Up @@ -152,11 +168,14 @@ protected EthereumTestResult RunTest(GeneralStateTest test, ITxTracer txTracer)
compositeBlockTracer.Add(storageTxTracer);
if (test.IsTraceEnabled)
{
GethLikeBlockFileTracer gethLikeBlockFileTracer = new(block, test.GethTraceOptions, new FileSystem());
GethLikeBlockFileTracer gethLikeBlockFileTracer =
new(block, test.GethTraceOptions, new FileSystem());
compositeBlockTracer.Add(gethLikeBlockFileTracer);
}

blockReceiptsTracer.SetOtherTracer(compositeBlockTracer);
}

blockReceiptsTracer.StartNewBlockTrace(block);

if (!test.IsStateTest && test.ParentBeaconBlockRoot != null)
Expand All @@ -169,12 +188,14 @@ protected EthereumTestResult RunTest(GeneralStateTest test, ITxTracer txTracer)

foreach (var tx in test.Transactions)
{
bool isValid = _txValidator.IsWellFormed(tx, spec, out string error) && IsValidBlock(block, specProvider);
bool isValid = _txValidator.IsWellFormed(tx, spec, out string error) &&
IsValidBlock(block, specProvider);
if (isValid)
{
blockReceiptsTracer.StartNewTxTrace(tx);
TransactionResult transactionResult = transactionProcessor
.Execute(tx, new BlockExecutionContext(header), test.IsT8NTest ? blockReceiptsTracer : txTracer);
.Execute(tx, new BlockExecutionContext(header),
test.IsT8NTest ? blockReceiptsTracer : txTracer);
blockReceiptsTracer.EndTxTrace();

if (!test.IsT8NTest) continue;
Expand All @@ -189,16 +210,21 @@ protected EthereumTestResult RunTest(GeneralStateTest test, ITxTracer txTracer)
}
else if (transactionResult.Error != null)
{
transactionExecutionReport.RejectedTransactionReceipts.Add(new RejectedTx(txIndex, GethErrorMappings.GetErrorMapping(transactionResult.Error, tx.SenderAddress.ToString(true), tx.Nonce, stateProvider.GetNonce(tx.SenderAddress))));
transactionExecutionReport.RejectedTransactionReceipts.Add(new RejectedTx(txIndex,
GethErrorMappings.GetErrorMapping(transactionResult.Error, tx.SenderAddress.ToString(true),
tx.Nonce, stateProvider.GetNonce(tx.SenderAddress))));
stateProvider.Reset();
}

txIndex++;
}
else if (error != null)
{
transactionExecutionReport.RejectedTransactionReceipts.Add(new RejectedTx(txIndex, GethErrorMappings.GetErrorMapping(error)));
transactionExecutionReport.RejectedTransactionReceipts.Add(new RejectedTx(txIndex,
GethErrorMappings.GetErrorMapping(error)));
}
}

blockReceiptsTracer.EndBlockTrace();

stopwatch.Stop();
Expand All @@ -223,18 +249,21 @@ protected EthereumTestResult RunTest(GeneralStateTest test, ITxTracer txTracer)

if (test.IsT8NTest)
{
testResult.T8NResult = T8NResult.ConstructT8NResult(stateProvider, block, test, storageTxTracer, blockReceiptsTracer, specProvider, header, transactionExecutionReport);
testResult.T8NResult = T8NResult.ConstructT8NResult(stateProvider, block, test, storageTxTracer,
blockReceiptsTracer, specProvider, header, transactionExecutionReport);
}

return testResult;
}

private static IBlockhashProvider GetBlockHashProvider(GeneralStateTest test, BlockHeader header, BlockHeader? parent)
private static IBlockhashProvider GetBlockHashProvider(GeneralStateTest test, BlockHeader header,
BlockHeader? parent)
{
if (!test.IsT8NTest)
{
return new TestBlockhashProvider();
}

var t8NBlockHashProvider = new T8NBlockHashProvider();

if (header.Hash != null) t8NBlockHashProvider.Insert(header.Hash, header.Number);
Expand All @@ -243,6 +272,7 @@ private static IBlockhashProvider GetBlockHashProvider(GeneralStateTest test, Bl
{
t8NBlockHashProvider.Insert(blockHash.Value, long.Parse(blockHash.Key));
}

return t8NBlockHashProvider;
}

Expand All @@ -252,7 +282,8 @@ private static UInt256 CalculateBaseFeePerGas(GeneralStateTest test, BlockHeader
return test.IsT8NTest ? BaseFeeCalculator.Calculate(parentHeader, test.Fork) : _defaultBaseFeeForStateTest;
}

private static void InitializeTestPreState(Dictionary<Address, AccountState> pre, WorldState stateProvider, ISpecProvider specProvider)
private static void InitializeTestPreState(Dictionary<Address, AccountState> pre, WorldState stateProvider,
ISpecProvider specProvider)
{
foreach (KeyValuePair<Address, AccountState> accountState in pre)
{
Expand Down Expand Up @@ -285,15 +316,18 @@ private bool IsValidBlock(Block block, ISpecProvider specProvider)
.TestObject;

var difficultyCalculator = new EthashDifficultyCalculator(specProvider);
var sealer = new EthashSealValidator(_logManager, difficultyCalculator, new CryptoRandom(), new Ethash(_logManager), Timestamper.Default);
var sealer = new EthashSealValidator(_logManager, difficultyCalculator, new CryptoRandom(),
new Ethash(_logManager), Timestamper.Default);
IHeaderValidator headerValidator = new HeaderValidator(blockTree, sealer, specProvider, _logManager);
IUnclesValidator unclesValidator = new UnclesValidator(blockTree, headerValidator, _logManager);
IBlockValidator blockValidator = new BlockValidator(_txValidator, headerValidator, unclesValidator, specProvider, _logManager);
IBlockValidator blockValidator = new BlockValidator(_txValidator, headerValidator, unclesValidator,
specProvider, _logManager);

return blockValidator.ValidateOrphanedBlock(block, out _);
}

private static void CalculateReward(string? stateReward, bool isStateTest, Block block, WorldState stateProvider, IReleaseSpec spec)
private static void CalculateReward(string? stateReward, bool isStateTest, Block block,
WorldState stateProvider, IReleaseSpec spec)
{
if (stateReward == null || isStateTest) return;

Expand Down
1 change: 1 addition & 0 deletions tools/Evm.Test/T8NTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,7 @@ private void Execute(InputParams inputParams, OutputParams outputParams, int exp
1,
inputParams.StateFork,
inputParams.StateReward,
false,
TraceOptions.Default
);

Expand Down
2 changes: 2 additions & 0 deletions tools/evm/Evm.sln
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,6 @@ Global
{AAA9AF72-46AE-4535-9698-610C9E94AE06}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AAA9AF72-46AE-4535-9698-610C9E94AE06}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
EndGlobalSection
EndGlobal
3 changes: 3 additions & 0 deletions tools/evm/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ static void ConfigureT8NCommand(ref RootCommand rootCmd)
var traceOpt = new Option<bool>("--trace", description: "Configures the use of the JSON opcode tracer. This tracer emits traces to files as trace-<txIndex>-<txHash>.jsonl", getDefaultValue: () => false);
var traceNoStackOpt = new Option<bool>("--trace.noStack", description: "Trace no stack", getDefaultValue: () => false);
var traceReturnDataOpt = new Option<bool>("--trace.returnData", description: "Trace return data", getDefaultValue: () => false);
var isGnosisTests = new Option<bool>("--run.gnosis", description: "If set to true, will run under Gnosis spec", getDefaultValue: () => false);

Choose a reason for hiding this comment

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

Just an idea for an improvement: instead of using a new --run.gnosis option maybe we can reuse --state.chainId and choose ISpecProvider based on chain / networkid? With such a way we will not need to add a new flag every time we have to add a new network to t8n.

Copy link
Contributor

Choose a reason for hiding this comment

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

Good idea, removed --run.gnosis flag


var cmd = new Command("t8n", "EVM State Transition command")
{
Expand All @@ -53,6 +54,7 @@ static void ConfigureT8NCommand(ref RootCommand rootCmd)
traceMemoryOpt,
traceNoStackOpt,
traceReturnDataOpt,
isGnosisTests
};

cmd.AddAlias("transition");
Expand Down Expand Up @@ -86,6 +88,7 @@ await Task.Run(() =>
context.ParseResult.GetValueForOption(stateChainIdOpt),
context.ParseResult.GetValueForOption(stateForkOpt),
context.ParseResult.GetValueForOption(stateRewardOpt),
context.ParseResult.GetValueForOption(isGnosisTests),
traceOpts
);
Environment.ExitCode = output.ExitCode;
Expand Down
12 changes: 9 additions & 3 deletions tools/evm/T8NTool/InputProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using Nethermind.Evm.Tracing.GethStyle;
using Nethermind.Serialization.Json;
using Nethermind.Serialization.Rlp;
using Nethermind.Specs;
using Nethermind.Specs.Forks;
using Nethermind.Specs.Test;

Expand All @@ -23,14 +24,16 @@ public static GeneralStateTest ConvertToGeneralStateTest(string inputAlloc,
string stateFork,
string? stateReward,
ulong stateChainId,
bool isGnosis,
TraceOptions traceOptions)
{
GethTraceOptions gethTraceOptions = new GethTraceOptions
{
EnableMemory = traceOptions.Memory,
DisableStack = traceOptions.NoStack
};
Dictionary<Address, AccountState> allocJson = EthereumJsonSerializer.Deserialize<Dictionary<Address, AccountState>>(File.ReadAllText(inputAlloc));
Dictionary<Address, AccountState> allocJson =
EthereumJsonSerializer.Deserialize<Dictionary<Address, AccountState>>(File.ReadAllText(inputAlloc));
EnvInfo envInfo = EthereumJsonSerializer.Deserialize<EnvInfo>(File.ReadAllText(inputEnv));

Transaction[] transactions;
Expand Down Expand Up @@ -61,25 +64,28 @@ public static GeneralStateTest ConvertToGeneralStateTest(string inputAlloc,
throw new T8NException(e, ExitCodes.ErrorConfig);
}

ISpecProvider specProvider = new CustomSpecProvider(((ForkActivation)0, Frontier.Instance), ((ForkActivation)1, spec));
ISpecProvider specProvider = isGnosis ? GnosisSpecProvider.Instance
: new CustomSpecProvider(((ForkActivation)0, Frontier.Instance), ((ForkActivation)1, spec));

if (spec is Paris)
{
specProvider.UpdateMergeTransitionInfo(envInfo.CurrentNumber, 0);
}

envInfo.ApplyChecks(specProvider, spec);

GeneralStateTest generalStateTest = new();
generalStateTest.IsT8NTest = true;
generalStateTest.Fork = spec;
generalStateTest.Pre = allocJson;
generalStateTest.Transactions = transactions;
generalStateTest.StateChainId = isGnosis ? GnosisSpecProvider.Instance.ChainId : MainnetSpecProvider.Instance.ChainId;

generalStateTest.CurrentCoinbase = envInfo.CurrentCoinbase;
generalStateTest.CurrentGasLimit = envInfo.CurrentGasLimit;
generalStateTest.CurrentTimestamp = envInfo.CurrentTimestamp;
generalStateTest.CurrentNumber = envInfo.CurrentNumber;
generalStateTest.Withdrawals = envInfo.Withdrawals;
generalStateTest.Withdrawals = envInfo.Withdrawals;
generalStateTest.CurrentRandom = envInfo.GetCurrentRandomHash256();
generalStateTest.ParentTimestamp = envInfo.ParentTimestamp;
generalStateTest.ParentDifficulty = envInfo.ParentDifficulty;
Expand Down
16 changes: 13 additions & 3 deletions tools/evm/T8NTool/T8NTool.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using Ethereum.Test.Base.T8NUtils;
using Evm.JsonTypes;
using Nethermind.Serialization.Json;
using Nethermind.Specs;

namespace Evm.T8NTool;

Expand All @@ -28,12 +29,18 @@ public T8NOutput Execute(
ulong stateChainId,
string stateFork,
string? stateReward,
bool isGnosis,
TraceOptions traceOptions)
{
T8NOutput t8NOutput = new();
try
{
var t8NExecutionResult = Execute(inputAlloc, inputEnv, inputTxs, stateFork, stateReward, stateChainId, traceOptions);
if (isGnosis)
{
stateChainId = GnosisSpecProvider.Instance.ChainId;
}
var t8NExecutionResult = Execute(inputAlloc, inputEnv, inputTxs, stateFork, stateReward, stateChainId,
isGnosis, traceOptions);

if (outputAlloc == "stdout") t8NOutput.Alloc = t8NExecutionResult.Alloc;
else if (outputAlloc != null) WriteToFile(outputAlloc, outputBasedir, t8NExecutionResult.Alloc);
Expand Down Expand Up @@ -72,6 +79,7 @@ public T8NOutput Execute(
Console.WriteLine(t8NOutput.ErrorMessage);
}
}

return t8NOutput;
}

Expand All @@ -82,11 +90,13 @@ private T8NExecutionResult Execute(
string stateFork,
string? stateReward,
ulong stateChainId,
bool isGnosis,
TraceOptions traceOptions)
{
var generalStateTest = InputProcessor.ConvertToGeneralStateTest(inputAlloc, inputEnv, inputTxs, stateFork, stateReward, stateChainId, traceOptions);
var generalStateTest = InputProcessor.ConvertToGeneralStateTest(inputAlloc, inputEnv, inputTxs, stateFork,
stateReward, stateChainId, isGnosis, traceOptions);

var res = RunTest(generalStateTest);
var res = RunTest(generalStateTest, isGnosis);

PostState postState = new PostState();
postState.StateRoot = res.StateRoot;
Expand Down