Skip to content

Commit

Permalink
Evm tool/t8n/init project (#7685)
Browse files Browse the repository at this point in the history
Co-authored-by: lukasz.rozmej <lukasz.rozmej@gmail.com>
  • Loading branch information
yerke26 and LukaszRozmej authored Oct 30, 2024
1 parent cedb007 commit 9e12334
Show file tree
Hide file tree
Showing 15 changed files with 210 additions and 46 deletions.
27 changes: 3 additions & 24 deletions src/Nethermind/Ethereum.Test.Base/GeneralTestBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,11 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using Nethermind.Blockchain;
using Nethermind.Consensus.Ethash;
using Nethermind.Consensus.Validators;
using Nethermind.Core;
using Nethermind.Core.Crypto;
using Nethermind.Core.Extensions;
using Nethermind.Core.Specs;
using Nethermind.Core.Test.Builders;
using Nethermind.Crypto;
using Nethermind.Db;
using Nethermind.Int256;
Expand Down Expand Up @@ -89,7 +86,7 @@ protected EthereumTestResult RunTest(GeneralStateTest test, ITxTracer txTracer)
codeInfoRepository,
_logManager);

InitializeTestState(test, stateProvider, specProvider);
InitializeTestState(test.Pre, stateProvider, specProvider);

BlockHeader header = new(
test.PreviousHash,
Expand Down Expand Up @@ -135,8 +132,6 @@ protected EthereumTestResult RunTest(GeneralStateTest test, ITxTracer txTracer)
header.ExcessBlobGas = BlobGasCalculator.CalculateExcessBlobGas(parent, spec);
}

Block block = Build.A.Block.WithTransactions(test.Transaction).WithHeader(header).TestObject;

ValidationResult txIsValid = _txValidator.IsWellFormed(test.Transaction, spec);

if (txIsValid)
Expand Down Expand Up @@ -172,9 +167,9 @@ protected EthereumTestResult RunTest(GeneralStateTest test, ITxTracer txTracer)
return testResult;
}

private static void InitializeTestState(GeneralStateTest test, WorldState stateProvider, ISpecProvider specProvider)
private static void InitializeTestState(Dictionary<Address, AccountState> preState, WorldState stateProvider, ISpecProvider specProvider)
{
foreach (KeyValuePair<Address, AccountState> accountState in test.Pre)
foreach (KeyValuePair<Address, AccountState> accountState in preState)
{
foreach (KeyValuePair<UInt256, byte[]> storageItem in accountState.Value.Storage)
{
Expand All @@ -192,22 +187,6 @@ private static void InitializeTestState(GeneralStateTest test, WorldState stateP
stateProvider.Reset();
}

private bool IsValidBlock(Block block, ISpecProvider specProvider)
{
IBlockTree blockTree = Build.A.BlockTree()
.WithSpecProvider(specProvider)
.WithoutSettingHead
.TestObject;

var difficultyCalculator = new EthashDifficultyCalculator(specProvider);
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);

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

private List<string> RunAssertions(GeneralStateTest test, IWorldState stateProvider)
{
List<string> differences = [];
Expand Down
5 changes: 3 additions & 2 deletions src/Nethermind/Ethereum.Test.Base/JsonToEthereumTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ public static IReleaseSpec ParseSpec(string network)
network = network.Replace("EIP150", "TangerineWhistle");
network = network.Replace("EIP158", "SpuriousDragon");
network = network.Replace("DAO", "Dao");
network = network.Replace("Merged", "GrayGlacier");
network = network.Replace("Merge", "GrayGlacier");
network = network.Replace("Merged", "Paris");
network = network.Replace("Merge", "Paris");
network = network.Replace("London+3540+3670", "Shanghai");
network = network.Replace("GrayGlacier+3540+3670", "Shanghai");
network = network.Replace("GrayGlacier+3860", "Shanghai");
Expand Down Expand Up @@ -55,6 +55,7 @@ public static IReleaseSpec ParseSpec(string network)
"Istanbul" => Istanbul.Instance,
"Berlin" => Berlin.Instance,
"London" => London.Instance,
"ArrowGlacier" => ArrowGlacier.Instance,
"GrayGlacier" => GrayGlacier.Instance,
"Shanghai" => Shanghai.Instance,
"Cancun" => Cancun.Instance,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

[assembly: InternalsVisibleTo("Ethereum.Test.Base")]
[assembly: InternalsVisibleTo("Ethereum.Difficulty.Test")]
[assembly: InternalsVisibleTo("Evm")]

namespace Nethermind.Consensus.Ethash
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -251,12 +251,12 @@ public TransactionBuilder<T> Signed(IEthereumEcdsa ecdsa, PrivateKey privateKey,
return this;
}

public TransactionBuilder<T> Signed(PrivateKey? privateKey = null)
public TransactionBuilder<T> Signed(PrivateKey? privateKey = null, bool isEip155Enabled = true)
{
privateKey ??= TestItem.IgnoredPrivateKey;
EthereumEcdsa ecdsa = new(TestObjectInternal.ChainId ?? TestBlockchainIds.ChainId);

return Signed(ecdsa, privateKey, isEip155Enabled: true);
return Signed(ecdsa, privateKey, isEip155Enabled);
}

// TODO: auto create ecdsa here
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -298,13 +298,13 @@ public void Storage_is_cleared_and_restored_when_moving_between_call_levels()
}; */

Assert.That(trace.Entries[0].Storage.Count, Is.EqualTo(0), "BEGIN 1");
Assert.That(trace.Entries[13].Storage.Count, Is.EqualTo(2), "CALL FROM 1");
Assert.That(trace.Entries[13].Storage.Count, Is.EqualTo(0), "CALL FROM 1");
Assert.That(trace.Entries[14].Storage.Count, Is.EqualTo(0), "BEGIN 2");
Assert.That(trace.Entries[26].Storage.Count, Is.EqualTo(1), "CREATE FROM 2");
Assert.That(trace.Entries[26].Storage.Count, Is.EqualTo(0), "CREATE FROM 2");
Assert.That(trace.Entries[27].Storage.Count, Is.EqualTo(0), "BEGIN 3");
Assert.That(trace.Entries[32].Storage.Count, Is.EqualTo(0), "END 3");
Assert.That(trace.Entries[33].Storage.Count, Is.EqualTo(1), "END 2");
Assert.That(trace.Entries[34].Storage.Count, Is.EqualTo(2), "END 1");
Assert.That(trace.Entries[33].Storage.Count, Is.EqualTo(0), "END 2");
Assert.That(trace.Entries[34].Storage.Count, Is.EqualTo(0), "END 1");
}

[Test]
Expand Down
4 changes: 2 additions & 2 deletions src/Nethermind/Nethermind.Evm.Test/VirtualMachineTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public void Trace()
Assert.That(entry.GasCost, Is.EqualTo(GasCostOf.VeryLow), nameof(entry.GasCost));
Assert.That(entry.Memory.Count, Is.EqualTo(0), nameof(entry.Memory));
Assert.That(entry.Stack.Count, Is.EqualTo(1), nameof(entry.Stack));
Assert.That(trace.Entries[4].Storage.Count, Is.EqualTo(1), nameof(entry.Storage));
Assert.That(trace.Entries[4].Storage.Count, Is.EqualTo(0), nameof(entry.Storage));
Assert.That(entry.ProgramCounter, Is.EqualTo(2), nameof(entry.ProgramCounter));
Assert.That(entry.Opcode, Is.EqualTo("PUSH1"), nameof(entry.Opcode));
}
Expand Down Expand Up @@ -135,7 +135,7 @@ public void Trace_each_tx_separate()
Assert.That(entry.GasCost, Is.EqualTo(GasCostOf.VeryLow), nameof(entry.GasCost));
Assert.That(entry.Memory.Count, Is.EqualTo(0), nameof(entry.Memory));
Assert.That(entry.Stack.Count, Is.EqualTo(1), nameof(entry.Stack));
Assert.That(trace.Entries[4].Storage.Count, Is.EqualTo(1), nameof(entry.Storage));
Assert.That(trace.Entries[4].Storage.Count, Is.EqualTo(0), nameof(entry.Storage));
Assert.That(entry.ProgramCounter, Is.EqualTo(2), nameof(entry.ProgramCounter));
Assert.That(entry.Opcode, Is.EqualTo("PUSH1"), nameof(entry.Opcode));
}
Expand Down
22 changes: 11 additions & 11 deletions src/Nethermind/Nethermind.Evm/VirtualMachine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2679,19 +2679,19 @@ private EvmExceptionType InstructionSStore<TTracingInstructions, TTracingRefunds
if (!newSameAsCurrent)
{
_state.Set(in storageCell, newIsZero ? BytesZero : bytes.ToArray());
}

if (typeof(TTracingInstructions) == typeof(IsTracing))
{
ReadOnlySpan<byte> valueToStore = newIsZero ? BytesZero.AsSpan() : bytes;
byte[] storageBytes = new byte[32]; // do not stackalloc here
storageCell.Index.ToBigEndian(storageBytes);
_txTracer.ReportStorageChange(storageBytes, valueToStore);
}
if (typeof(TTracingInstructions) == typeof(IsTracing))
{
ReadOnlySpan<byte> valueToStore = newIsZero ? BytesZero.AsSpan() : bytes;
byte[] storageBytes = new byte[32]; // do not stackalloc here
storageCell.Index.ToBigEndian(storageBytes);
_txTracer.ReportStorageChange(storageBytes, valueToStore);
}

if (typeof(TTracingStorage) == typeof(IsTracing))
{
_txTracer.SetOperationStorage(storageCell.Address, result, bytes, currentValue);
if (typeof(TTracingStorage) == typeof(IsTracing))
{
_txTracer.SetOperationStorage(storageCell.Address, result, bytes, currentValue);
}
}

return EvmExceptionType.None;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ public OverridableReleaseSpec(IReleaseSpec spec)
{
_spec = spec;
IsEip3607Enabled = _spec.IsEip3607Enabled;
BlockReward = _spec.BlockReward;
}

public string Name => "OverridableReleaseSpec";
Expand All @@ -31,7 +32,7 @@ public OverridableReleaseSpec(IReleaseSpec spec)

public long GasLimitBoundDivisor => _spec.GasLimitBoundDivisor;

public UInt256 BlockReward => _spec.BlockReward;
public UInt256 BlockReward { get; set; }

public long DifficultyBombDelay => _spec.DifficultyBombDelay;

Expand Down
16 changes: 16 additions & 0 deletions tools/Evm/Evm.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@

Microsoft Visual Studio Solution File, Format Version 12.00
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Evm", "Evm\Evm.csproj", "{9D450C5A-C4B3-457A-8398-4690DFF4C47C}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{9D450C5A-C4B3-457A-8398-4690DFF4C47C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9D450C5A-C4B3-457A-8398-4690DFF4C47C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9D450C5A-C4B3-457A-8398-4690DFF4C47C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9D450C5A-C4B3-457A-8398-4690DFF4C47C}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal
14 changes: 14 additions & 0 deletions tools/Evm/Evm/Evm.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="System.CommandLine" Version="2.0.0-beta4.22272.1" />
</ItemGroup>

</Project>
16 changes: 16 additions & 0 deletions tools/Evm/Evm/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using System.CommandLine;
using Evm.t8n;

namespace Evm;

public static class Program
{
public static async Task Main(string[] args)
{
var rootCmd = new RootCommand { Name = "Evm" };

T8NCommand.Configure(ref rootCmd);

await rootCmd.InvokeAsync(args);
}
}
22 changes: 22 additions & 0 deletions tools/Evm/Evm/t8n/T8NCommand.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited
// SPDX-License-Identifier: LGPL-3.0-only

using System.CommandLine;

namespace Evm.t8n;

public static class T8NCommand
{
public static void Configure(ref RootCommand rootCmd)
{
Command cmd = T8NCommandOptions.CreateCommand();
rootCmd.Add(cmd);

cmd.SetHandler(
context =>
{
var arguments = T8NCommandArguments.FromParseResult(context.ParseResult);
T8NExecutor.Execute(arguments);
});
}
}
52 changes: 52 additions & 0 deletions tools/Evm/Evm/t8n/T8NCommandArguments.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited
// SPDX-License-Identifier: LGPL-3.0-only

using System.CommandLine.Parsing;

namespace Evm.t8n;

public class T8NCommandArguments
{
public string? InputAlloc { get; set; }
public string? InputEnv { get; set; }
public string? InputTxs { get; set; }

public string? OutputAlloc { get; set; }
public string? OutputResult { get; set; }
public string? OutputBody { get; set; }
public string? OutputBaseDir { get; set; }

public ulong? StateChainId { get; set; }
public string? StateFork { get; set; }
public string? StateReward { get; set; }

public bool? Trace { get; set; }
public bool? TraceMemory { get; set; }
public bool? TraceNoStack { get; set; }
public bool? TraceReturnData { get; set; }

public static T8NCommandArguments FromParseResult(ParseResult parseResult)
{
return new T8NCommandArguments
{
InputAlloc = parseResult.GetValueForOption(T8NCommandOptions.InputAllocOpt),
InputEnv = parseResult.GetValueForOption(T8NCommandOptions.InputEnvOpt),
InputTxs = parseResult.GetValueForOption(T8NCommandOptions.InputTxsOpt),

OutputAlloc = parseResult.GetValueForOption(T8NCommandOptions.OutputAllocOpt),
OutputResult = parseResult.GetValueForOption(T8NCommandOptions.OutputResultOpt),
OutputBody = parseResult.GetValueForOption(T8NCommandOptions.OutputBodyOpt),
OutputBaseDir = parseResult.GetValueForOption(T8NCommandOptions.OutputBaseDirOpt),

StateChainId = parseResult.GetValueForOption(T8NCommandOptions.StateChainIdOpt),
StateFork = parseResult.GetValueForOption(T8NCommandOptions.StateForkOpt),
StateReward = parseResult.GetValueForOption(T8NCommandOptions.StateRewardOpt),

Trace = parseResult.GetValueForOption(T8NCommandOptions.TraceOpt),
TraceMemory = parseResult.GetValueForOption(T8NCommandOptions.TraceMemoryOpt),
TraceNoStack = parseResult.GetValueForOption(T8NCommandOptions.TraceNoStackOpt),
TraceReturnData = parseResult.GetValueForOption(T8NCommandOptions.TraceReturnDataOpt)
};
}

}
50 changes: 50 additions & 0 deletions tools/Evm/Evm/t8n/T8NCommandOptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited
// SPDX-License-Identifier: LGPL-3.0-only

namespace Evm.t8n;

using System.CommandLine;

public static class T8NCommandOptions
{
public static Option<string> InputAllocOpt { get; } = new Option<string>("--input.alloc", description: "Input allocations", getDefaultValue: () => "alloc.json");
public static Option<string> InputEnvOpt { get; } = new Option<string>("--input.env", description: "Input environment", getDefaultValue: () => "env.json");
public static Option<string> InputTxsOpt { get; } = new Option<string>("--input.txs", description: "Input transactions", getDefaultValue: () => "txs.json");

public static Option<string> OutputAllocOpt { get; } = new Option<string>("--output.alloc", description: "Output allocations", getDefaultValue: () => "alloc.json");
public static Option<string> OutputResultOpt { get; } = new Option<string>("--output.result", description: "Output result", getDefaultValue: () => "result.json");
public static Option<string> OutputBodyOpt { get; } = new Option<string>("--output.body", description: "Output body");
public static Option<string> OutputBaseDirOpt { get; } = new Option<string>("--output.basedir", description: "Output base directory");

public static Option<ulong> StateChainIdOpt { get; } = new Option<ulong>("--state.chainid", description: "State chain id", getDefaultValue: () => 1);
public static Option<string> StateForkOpt { get; } = new Option<string>("--state.fork", description: "State fork", getDefaultValue: () => "GrayGlacier");
public static Option<string> StateRewardOpt { get; } = new Option<string>("--state.reward", description: "State reward");

public static Option<bool> TraceOpt { get; } = new Option<bool>("--trace", description: "Configures the use of the JSON opcode tracer. This tracer emits traces to files as trace-<txIndex>-<txHash>.json", getDefaultValue: () => false);
public static Option<bool> TraceMemoryOpt { get; } = new Option<bool>("--trace.memory", description: "Trace memory", getDefaultValue: () => false);
public static Option<bool> TraceNoStackOpt { get; } = new Option<bool>("--trace.nostack", description: "Trace no stack", getDefaultValue: () => false);
public static Option<bool> TraceReturnDataOpt { get; } = new Option<bool>("--trace.returndata", description: "Trace return data", getDefaultValue: () => false);

public static Command CreateCommand()
{
var cmd = new Command("t8n", "EVM State Transition command")
{
InputAllocOpt,
InputEnvOpt,
InputTxsOpt,
OutputAllocOpt,
OutputBaseDirOpt,
OutputBodyOpt,
OutputResultOpt,
StateChainIdOpt,
StateForkOpt,
StateRewardOpt,
TraceOpt,
TraceMemoryOpt,
TraceNoStackOpt,
TraceReturnDataOpt,
};
cmd.AddAlias("transition");
return cmd;
}
}
12 changes: 12 additions & 0 deletions tools/Evm/Evm/t8n/T8NExecutor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited
// SPDX-License-Identifier: LGPL-3.0-only

namespace Evm.t8n;

public static class T8NExecutor
{
public static void Execute(T8NCommandArguments arguments)
{

}
}

0 comments on commit 9e12334

Please sign in to comment.