diff --git a/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.BlockValidationTransactionsExecutor.cs b/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.BlockValidationTransactionsExecutor.cs index d487cda83fa..6d2299ef920 100644 --- a/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.BlockValidationTransactionsExecutor.cs +++ b/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.BlockValidationTransactionsExecutor.cs @@ -18,28 +18,22 @@ namespace Nethermind.Consensus.Processing { public partial class BlockProcessor { - public class BlockValidationTransactionsExecutor : IBlockProcessor.IBlockTransactionsExecutor + public class BlockValidationTransactionsExecutor( + ITransactionProcessorAdapter transactionProcessor, + IWorldState stateProvider) + : IBlockProcessor.IBlockTransactionsExecutor { - private readonly ITransactionProcessorAdapter _transactionProcessor; - private readonly IWorldState _stateProvider; - public BlockValidationTransactionsExecutor(ITransactionProcessor transactionProcessor, IWorldState stateProvider) : this(new ExecuteTransactionProcessorAdapter(transactionProcessor), stateProvider) { } - public BlockValidationTransactionsExecutor(ITransactionProcessorAdapter transactionProcessor, IWorldState stateProvider) - { - _transactionProcessor = transactionProcessor; - _stateProvider = stateProvider; - } - public event EventHandler? TransactionProcessed; public TxReceipt[] ProcessTransactions(Block block, ProcessingOptions processingOptions, BlockReceiptsTracer receiptsTracer, IReleaseSpec spec) { Metrics.ResetBlockStats(); - BlockExecutionContext blkCtx = new(block.Header); + BlockExecutionContext blkCtx = CreateBlockExecutionContext(block); for (int i = 0; i < block.Transactions.Length; i++) { block.TransactionProcessed = i; @@ -49,9 +43,11 @@ public TxReceipt[] ProcessTransactions(Block block, ProcessingOptions processing return receiptsTracer.TxReceipts.ToArray(); } + protected virtual BlockExecutionContext CreateBlockExecutionContext(Block block) => new(block.Header); + protected virtual void ProcessTransaction(in BlockExecutionContext blkCtx, Transaction currentTx, int index, BlockReceiptsTracer receiptsTracer, ProcessingOptions processingOptions) { - TransactionResult result = _transactionProcessor.ProcessTransaction(in blkCtx, currentTx, receiptsTracer, processingOptions, _stateProvider); + TransactionResult result = transactionProcessor.ProcessTransaction(in blkCtx, currentTx, receiptsTracer, processingOptions, stateProvider); if (!result) ThrowInvalidBlockException(result, blkCtx.Header, currentTx, index); TransactionProcessed?.Invoke(this, new TxProcessedEventArgs(index, currentTx, receiptsTracer.TxReceipts[index])); } diff --git a/src/Nethermind/Nethermind.Core/Crypto/Hash256.cs b/src/Nethermind/Nethermind.Core/Crypto/Hash256.cs index bd26dd918e1..0f223c05197 100644 --- a/src/Nethermind/Nethermind.Core/Crypto/Hash256.cs +++ b/src/Nethermind/Nethermind.Core/Crypto/Hash256.cs @@ -142,6 +142,7 @@ public readonly struct Hash256AsKey(Hash256 key) : IEquatable public sealed class Hash256 : IEquatable, IComparable { public const int Size = 32; + public static readonly Hash256 Zero = new("0x0000000000000000000000000000000000000000000000000000000000000000"); public const int MemorySize = MemorySizes.SmallObjectOverhead - diff --git a/src/Nethermind/Nethermind.Evm.Test/EvmPooledMemoryTests.cs b/src/Nethermind/Nethermind.Evm.Test/EvmPooledMemoryTests.cs index bfa853192b5..69e75399a8f 100644 --- a/src/Nethermind/Nethermind.Evm.Test/EvmPooledMemoryTests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/EvmPooledMemoryTests.cs @@ -121,9 +121,9 @@ public void GetTrace_memory_should_not_bleed_between_txs() 0x5b, 0x36, 0x59, 0x3a, 0x34, 0x60, 0x5b, 0x59, 0x05, 0x30, 0xf4, 0x3a, 0x56}; - var a = run(second).ToString(); - run(first); - var b = run(second).ToString(); + var a = Run(second).ToString(); + Run(first); + var b = Run(second).ToString(); Assert.That(b, Is.EqualTo(a)); } @@ -134,7 +134,7 @@ public void GetTrace_memory_should_not_overflow() var input = new byte[] { 0x5b, 0x59, 0x60, 0x20, 0x59, 0x81, 0x91, 0x52, 0x44, 0x36, 0x5a, 0x3b, 0x59, 0xf4, 0x5b, 0x31, 0x56, 0x08}; - run(input); + Run(input); } private static readonly PrivateKey PrivateKeyD = new("0000000000000000000000000000000000000000000000000000001000000000"); @@ -144,7 +144,7 @@ public void GetTrace_memory_should_not_overflow() private static readonly Address coinbase = new Address("0x4444588443C3a91288c5002483449Aba1054192b"); // for testing purposes, particular chain id does not matter. Maybe make random id so it captures the idea that signature should would irrespective of chain private static readonly EthereumEcdsa ethereumEcdsa = new(BlockchainIds.GenericNonRealNetwork); - private static string run(byte[] input) + private static string Run(byte[] input) { long blocknr = 12965000; long gas = 34218; diff --git a/src/Nethermind/Nethermind.Evm/BlockExecutionContext.cs b/src/Nethermind/Nethermind.Evm/BlockExecutionContext.cs index 759dc5ee04f..a4ed924c6c4 100644 --- a/src/Nethermind/Nethermind.Evm/BlockExecutionContext.cs +++ b/src/Nethermind/Nethermind.Evm/BlockExecutionContext.cs @@ -25,9 +25,11 @@ public BlockExecutionContext(BlockHeader blockHeader) } } - public static implicit operator BlockExecutionContext(BlockHeader header) + public BlockExecutionContext(BlockHeader blockHeader, UInt256 forceBlobBaseFee) { - return new BlockExecutionContext(header); + Header = blockHeader; + BlobBaseFee = forceBlobBaseFee; } + public static implicit operator BlockExecutionContext(BlockHeader header) => new(header); } diff --git a/src/Nethermind/Nethermind.Evm/TransactionProcessing/TransactionProcessor.cs b/src/Nethermind/Nethermind.Evm/TransactionProcessing/TransactionProcessor.cs index f742375d825..f01be3bfdeb 100644 --- a/src/Nethermind/Nethermind.Evm/TransactionProcessing/TransactionProcessor.cs +++ b/src/Nethermind/Nethermind.Evm/TransactionProcessing/TransactionProcessor.cs @@ -432,6 +432,8 @@ protected ExecutionEnvironment BuildExecutionEnvironment( ); } + protected virtual bool ShouldValidate(ExecutionOptions opts) => !opts.HasFlag(ExecutionOptions.NoValidation); + protected void ExecuteEvmCall( Transaction tx, BlockHeader header, @@ -444,7 +446,7 @@ protected void ExecuteEvmCall( out long spentGas, out byte statusCode) { - bool validate = !opts.HasFlag(ExecutionOptions.NoValidation); + bool validate = ShouldValidate(opts); substate = null; spentGas = tx.GasLimit; diff --git a/src/Nethermind/Nethermind.Facade/BlockchainBridge.cs b/src/Nethermind/Nethermind.Facade/BlockchainBridge.cs index 1686604fcaa..b95f0646548 100644 --- a/src/Nethermind/Nethermind.Facade/BlockchainBridge.cs +++ b/src/Nethermind/Nethermind.Facade/BlockchainBridge.cs @@ -169,7 +169,7 @@ public SimulateOutput Simulate(BlockHeader header, SimulatePayload Calls { get; set; } = new(); - public UInt256 BlobBaseFee { get; set; } } diff --git a/src/Nethermind/Nethermind.Facade/Simulate/SimulateBlockTracer.cs b/src/Nethermind/Nethermind.Facade/Simulate/SimulateBlockTracer.cs index c6ab396eedc..e8f656465a2 100644 --- a/src/Nethermind/Nethermind.Facade/Simulate/SimulateBlockTracer.cs +++ b/src/Nethermind/Nethermind.Facade/Simulate/SimulateBlockTracer.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Linq; using Nethermind.Core; +using Nethermind.Core.Crypto; using Nethermind.Core.Specs; using Nethermind.Evm; using Nethermind.Evm.Tracing; @@ -46,14 +47,6 @@ public override void EndBlockTrace() { Calls = _txTracers.Select(t => t.TraceResult).ToList(), }; - if (_currentBlock.Header.ExcessBlobGas is not null) - { - if (!BlobGasCalculator.TryCalculateBlobGasPricePerUnit(_currentBlock.Header.ExcessBlobGas.Value, - out UInt256 blobGasPricePerUnit)) - { - result.BlobBaseFee = blobGasPricePerUnit; - } - } Results.Add(result); } diff --git a/src/Nethermind/Nethermind.Facade/Simulate/SimulateBridgeHelper.cs b/src/Nethermind/Nethermind.Facade/Simulate/SimulateBridgeHelper.cs index 4993b53ec6e..59c97ea3c5c 100644 --- a/src/Nethermind/Nethermind.Facade/Simulate/SimulateBridgeHelper.cs +++ b/src/Nethermind/Nethermind.Facade/Simulate/SimulateBridgeHelper.cs @@ -1,11 +1,6 @@ // SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only -using System; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Runtime.InteropServices; using Nethermind.Blockchain; using Nethermind.Config; using Nethermind.Consensus.Processing; @@ -14,11 +9,17 @@ using Nethermind.Core.Crypto; using Nethermind.Core.Specs; using Nethermind.Crypto; +using Nethermind.Evm; using Nethermind.Evm.Tracing; -using Nethermind.Evm.TransactionProcessing; using Nethermind.Facade.Proxy.Models.Simulate; using Nethermind.Int256; using Nethermind.State; +using Nethermind.State.Proofs; +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Runtime.InteropServices; using Transaction = Nethermind.Core.Transaction; namespace Nethermind.Facade.Simulate; @@ -58,14 +59,16 @@ private void PrepareState(BlockHeader blockHeader, public bool TrySimulate( BlockHeader parent, SimulatePayload payload, + SimulateBlockTracer simulateOutputTracer, IBlockTracer tracer, [NotNullWhen(false)] out string? error) => - TrySimulate(parent, payload, tracer, simulateProcessingEnvFactory.Create(payload.Validation), out error); + TrySimulate(parent, payload, simulateOutputTracer, tracer, simulateProcessingEnvFactory.Create(payload.Validation), out error); private bool TrySimulate( BlockHeader parent, SimulatePayload payload, + SimulateBlockTracer simulateOutputTracer, IBlockTracer tracer, SimulateReadOnlyBlocksProcessingEnv env, [NotNullWhen(false)] out string? error) @@ -83,40 +86,31 @@ private bool TrySimulate( foreach (BlockStateCall blockCall in payload.BlockStateCalls) { nonceCache.Clear(); + BlockHeader callHeader = GetCallHeader(blockCall, parent, payload.Validation, spec); //currentSpec is still parent spec spec = env.SpecProvider.GetSpec(callHeader); PrepareState(callHeader, parent, blockCall, env.WorldState, env.CodeInfoRepository, spec); - - if (blockCall.BlockOverrides is { BaseFeePerGas: not null }) - { - callHeader.BaseFeePerGas = blockCall.BlockOverrides.BaseFeePerGas.Value; - } - else if (!payload.Validation) - { - callHeader.BaseFeePerGas = 0; - } + Transaction[] transactions = CreateTransactions(payload, blockCall, callHeader, stateProvider, nonceCache); + callHeader.TxRoot = TxTrie.CalculateRoot(transactions); callHeader.Hash = callHeader.CalculateHash(); - Transaction[] transactions = CreateTransactions(payload, blockCall, callHeader, stateProvider, nonceCache); if (!TryGetBlock(payload, env, callHeader, transactions, out Block currentBlock, out error)) { return false; } - ProcessingOptions processingFlags = SimulateProcessingOptions; - - if (!payload.Validation) - { - processingFlags |= ProcessingOptions.NoValidation; - } + ProcessingOptions processingFlags = payload.Validation + ? SimulateProcessingOptions + : SimulateProcessingOptions | ProcessingOptions.NoValidation; suggestedBlocks[0] = currentBlock; - IBlockProcessor processor = env.GetProcessor(payload.Validation); - Block processedBlock = - processor.Process(stateProvider.StateRoot, suggestedBlocks, processingFlags, tracer)[0]; + IBlockProcessor processor = env.GetProcessor(payload.Validation, spec.IsEip4844Enabled ? blockCall.BlockOverrides?.BlobBaseFee : null); + Block processedBlock = processor.Process(stateProvider.StateRoot, suggestedBlocks, processingFlags, tracer)[0]; FinalizeStateAndBlock(stateProvider, processedBlock, spec, currentBlock, blockTree); + CheckMisssingAndSetTracedDefaults(simulateOutputTracer, processedBlock); + parent = processedBlock.Header; } } @@ -125,6 +119,18 @@ private bool TrySimulate( return true; } + private static void CheckMisssingAndSetTracedDefaults(SimulateBlockTracer simulateOutputTracer, Block processedBlock) + { + SimulateBlockResult current = simulateOutputTracer.Results.Last(); + current.StateRoot = processedBlock.StateRoot ?? Hash256.Zero; + current.ParentBeaconBlockRoot = processedBlock.ParentBeaconBlockRoot ?? Hash256.Zero; + current.TransactionsRoot = processedBlock.Header.TxRoot; + current.WithdrawalsRoot = processedBlock.WithdrawalsRoot ?? Keccak.EmptyTreeHash; + current.ExcessBlobGas = processedBlock.ExcessBlobGas ?? 0; + current.Withdrawals = processedBlock.Withdrawals ?? []; + current.Author = null; + } + private static void FinalizeStateAndBlock(IWorldState stateProvider, Block processedBlock, IReleaseSpec currentSpec, Block currentBlock, IBlockTree blockTree) { stateProvider.StateRoot = processedBlock.StateRoot!; @@ -223,7 +229,6 @@ private Transaction CreateTransaction(TransactionWithSourceDetails transactionDe { Transaction? transaction = transactionDetails.Transaction; transaction.SenderAddress ??= Address.Zero; - transaction.To ??= Address.Zero; transaction.Data ??= Memory.Empty; if (!transactionDetails.HadNonceInRequest) @@ -261,13 +266,15 @@ private Transaction CreateTransaction(TransactionWithSourceDetails transactionDe } transaction.Hash ??= transaction.CalculateHash(); + callHeader.BlobGasUsed += BlobGasCalculator.CalculateBlobGas(transaction); return transaction; } - private BlockHeader GetCallHeader(BlockStateCall block, BlockHeader parent, bool payloadValidation, IReleaseSpec parentSpec) => - block.BlockOverrides is not null - ? block.BlockOverrides.GetBlockHeader(parent, blocksConfig, parentSpec) + private BlockHeader GetCallHeader(BlockStateCall block, BlockHeader parent, bool payloadValidation, IReleaseSpec spec) + { + BlockHeader result = block.BlockOverrides is not null + ? block.BlockOverrides.GetBlockHeader(parent, blocksConfig, spec) : new BlockHeader( parent.Hash!, Keccak.OfAnEmptySequenceRlp, @@ -278,8 +285,18 @@ block.BlockOverrides is not null parent.Timestamp + 1, Array.Empty()) { - BaseFeePerGas = !payloadValidation ? 0 : BaseFeeCalculator.Calculate(parent, parentSpec), MixHash = parent.MixHash, - IsPostMerge = parent.Difficulty == 0 + IsPostMerge = parent.Difficulty == 0, }; + result.Timestamp = parent.Timestamp + 1; + result.BaseFeePerGas = block.BlockOverrides is { BaseFeePerGas: not null } + ? block.BlockOverrides.BaseFeePerGas.Value + : !payloadValidation + ? 0 + : BaseFeeCalculator.Calculate(parent, spec); + + result.ExcessBlobGas = spec.IsEip4844Enabled ? BlobGasCalculator.CalculateExcessBlobGas(parent, spec) : (ulong?)0; + + return result; + } } diff --git a/src/Nethermind/Nethermind.Facade/Simulate/SimulateReadOnlyBlocksProcessingEnv.cs b/src/Nethermind/Nethermind.Facade/Simulate/SimulateReadOnlyBlocksProcessingEnv.cs index ba6e190c4e2..3f70c14789f 100644 --- a/src/Nethermind/Nethermind.Facade/Simulate/SimulateReadOnlyBlocksProcessingEnv.cs +++ b/src/Nethermind/Nethermind.Facade/Simulate/SimulateReadOnlyBlocksProcessingEnv.cs @@ -15,26 +15,30 @@ using Nethermind.Evm; using Nethermind.Evm.Tracing; using Nethermind.Evm.TransactionProcessing; +using Nethermind.Int256; using Nethermind.Logging; using Nethermind.State; using static Nethermind.Consensus.Processing.BlockProcessor; namespace Nethermind.Facade.Simulate; -public class SimulateBlockValidationTransactionsExecutor : BlockValidationTransactionsExecutor +public class SimulateBlockValidationTransactionsExecutor( + ITransactionProcessor transactionProcessor, + IWorldState stateProvider, + bool validate, + UInt256? blobBaseFeeOverride) + : BlockValidationTransactionsExecutor(transactionProcessor, stateProvider) { - public SimulateBlockValidationTransactionsExecutor(ITransactionProcessor transactionProcessor, IWorldState stateProvider) : base(transactionProcessor, stateProvider) - { - } + protected override BlockExecutionContext CreateBlockExecutionContext(Block block) => + blobBaseFeeOverride is not null ? new BlockExecutionContext(block.Header, blobBaseFeeOverride.Value) : base.CreateBlockExecutionContext(block); - public SimulateBlockValidationTransactionsExecutor(ITransactionProcessorAdapter transactionProcessor, IWorldState stateProvider) : base(transactionProcessor, stateProvider) + protected override void ProcessTransaction(in BlockExecutionContext blkCtx, Transaction currentTx, int index, BlockReceiptsTracer receiptsTracer, ProcessingOptions processingOptions) { - } + if (!validate) + { + processingOptions |= ProcessingOptions.ForceProcessing | ProcessingOptions.DoNotVerifyNonce | ProcessingOptions.NoValidation; + } - protected override void ProcessTransaction(in BlockExecutionContext blkCtx, Transaction currentTx, int index, - BlockReceiptsTracer receiptsTracer, ProcessingOptions processingOptions) - { - processingOptions |= ProcessingOptions.ForceProcessing | ProcessingOptions.DoNotVerifyNonce | ProcessingOptions.NoValidation; base.ProcessTransaction(in blkCtx, currentTx, index, receiptsTracer, processingOptions); } } @@ -102,13 +106,11 @@ private SimulateBlockValidatorProxy CreateValidator() return new SimulateBlockValidatorProxy(blockValidator); } - public IBlockProcessor GetProcessor(bool validate) => + public IBlockProcessor GetProcessor(bool validate, UInt256? blobBaseFeeOverride) => new BlockProcessor(SpecProvider, _blockValidator, NoBlockRewards.Instance, - validate - ? new BlockValidationTransactionsExecutor(_transactionProcessor, StateProvider) - : new SimulateBlockValidationTransactionsExecutor(_transactionProcessor, StateProvider), + new SimulateBlockValidationTransactionsExecutor(_transactionProcessor, StateProvider, validate, blobBaseFeeOverride), StateProvider, NullReceiptStorage.Instance, new BlockhashStore(SpecProvider, StateProvider), diff --git a/src/Nethermind/Nethermind.Facade/Simulate/SimulateTransactionProcessor.cs b/src/Nethermind/Nethermind.Facade/Simulate/SimulateTransactionProcessor.cs index 79499458247..9b6ebb52192 100644 --- a/src/Nethermind/Nethermind.Facade/Simulate/SimulateTransactionProcessor.cs +++ b/src/Nethermind/Nethermind.Facade/Simulate/SimulateTransactionProcessor.cs @@ -6,6 +6,7 @@ using Nethermind.Evm; using Nethermind.Evm.Tracing; using Nethermind.Evm.TransactionProcessing; +using Nethermind.Int256; using Nethermind.Logging; using Nethermind.State; @@ -20,6 +21,8 @@ public class SimulateTransactionProcessor( bool validate) : TransactionProcessor(specProvider, worldState, virtualMachine, codeInfoRepository, logManager), ITransactionProcessor { + protected override bool ShouldValidate(ExecutionOptions opts) => true; + protected override TransactionResult Execute(Transaction tx, in BlockExecutionContext blCtx, ITxTracer tracer, ExecutionOptions opts) { if (!validate) diff --git a/src/Nethermind/Nethermind.Facade/Simulate/SimulateTxMutatorTracer.cs b/src/Nethermind/Nethermind.Facade/Simulate/SimulateTxMutatorTracer.cs index 4234b78edf9..d5e78e34023 100644 --- a/src/Nethermind/Nethermind.Facade/Simulate/SimulateTxMutatorTracer.cs +++ b/src/Nethermind/Nethermind.Facade/Simulate/SimulateTxMutatorTracer.cs @@ -17,8 +17,6 @@ namespace Nethermind.Facade.Simulate; internal sealed class SimulateTxMutatorTracer : TxTracer, ITxLogsMutator { - public const int ExecutionError = -32015; - private static readonly Hash256 transferSignature = new AbiSignature("Transfer", AbiType.Address, AbiType.Address, AbiType.UInt256).Hash; @@ -87,10 +85,9 @@ public override void MarkAsFailed(Address recipient, long gasSpent, byte[] outpu GasUsed = (ulong)gasSpent, Error = new Error { - Code = ExecutionError, // revert error code stub Message = error }, - ReturnData = null, + ReturnData = output, Status = StatusCode.Failure }; } diff --git a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/Simulate/EthSimulateTestsHiveBase.cs b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/Simulate/EthSimulateTestsHiveBase.cs index 7c1b85e4325..d0ab6c1e05c 100644 --- a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/Simulate/EthSimulateTestsHiveBase.cs +++ b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Eth/Simulate/EthSimulateTestsHiveBase.cs @@ -18,6 +18,7 @@ public class EthSimulateTestsHiveBase { private static readonly object[] HiveTestCases = { +new object[] {"baseFee", "{\"blockStateCalls\": [\r\n {\r\n \"blockOverrides\": {\r\n \"blobBaseFee\": \"0x0\"\r\n },\r\n \"stateOverrides\": {\r\n \"0xc000000000000000000000000000000000000000\": {\r\n \"balance\": \"0x5f5e100\"\r\n },\r\n \"0xc200000000000000000000000000000000000000\": {\r\n \"code\": \"0x\"\r\n }\r\n },\r\n \"calls\": [\r\n {\r\n \"from\": \"0xc000000000000000000000000000000000000000\",\r\n \"to\": \"0xc200000000000000000000000000000000000000\",\r\n \"maxFeePerBlobGas\": \"0xa\",\r\n \"blobVersionedHashes\": [\r\n \"0x010657f37554c781402a22917dee2f75def7ab966d7b770905398eba3c444014\"\r\n ]\r\n }\r\n ]\r\n },\r\n {\r\n \"blockOverrides\": {\r\n \"blobBaseFee\": \"0x1\"\r\n },\r\n \"calls\": [\r\n {\r\n \"from\": \"0xc000000000000000000000000000000000000000\",\r\n \"to\": \"0xc200000000000000000000000000000000000000\",\r\n \"maxFeePerBlobGas\": \"0xa\",\r\n \"blobVersionedHashes\": [\r\n \"0x010657f37554c781402a22917dee2f75def7ab966d7b770905398eba3c444014\"\r\n ]\r\n }\r\n ]\r\n }\r\n ]\r\n }"}, new object[] {"multicall-add-more-non-defined-BlockStateCalls-than-fit-but-now-with-fit", "{\"blockStateCalls\": [{\"blockOverrides\": {\"number\": \"0xa\"}, \"stateOverrides\": {\"0xc100000000000000000000000000000000000000\": {\"code\": \"0x608060405234801561001057600080fd5b506000366060484641444543425a3a60014361002c919061009b565b406040516020016100469a99989796959493929190610138565b6040516020818303038152906040529050915050805190602001f35b6000819050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006100a682610062565b91506100b183610062565b92508282039050818111156100c9576100c861006c565b5b92915050565b6100d881610062565b82525050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000610109826100de565b9050919050565b610119816100fe565b82525050565b6000819050919050565b6101328161011f565b82525050565b60006101408201905061014e600083018d6100cf565b61015b602083018c6100cf565b610168604083018b610110565b610175606083018a6100cf565b61018260808301896100cf565b61018f60a08301886100cf565b61019c60c08301876100cf565b6101a960e08301866100cf565b6101b76101008301856100cf565b6101c5610120830184610129565b9b9a505050505050505050505056fea26469706673582212205139ae3ba8d46d11c29815d001b725f9840c90e330884ed070958d5af4813d8764736f6c63430008120033\"}}, \"calls\": [{\"from\": \"0xc000000000000000000000000000000000000000\", \"to\": \"0xc100000000000000000000000000000000000000\", \"input\": \"0x\"}]}, {\"calls\": [{\"from\": \"0xc000000000000000000000000000000000000000\", \"to\": \"0xc100000000000000000000000000000000000000\", \"input\": \"0x\"}]}, {\"blockOverrides\": {\"number\": \"0x14\"}, \"calls\": [{\"from\": \"0xc000000000000000000000000000000000000000\", \"to\": \"0xc100000000000000000000000000000000000000\", \"input\": \"0x\"}]}, {\"calls\": [{\"from\": \"0xc000000000000000000000000000000000000000\", \"to\": \"0xc100000000000000000000000000000000000000\", \"input\": \"0x\"}]}]}"}, new object[] {"multicall-basefee-too-low-without-validation-38012", "{\"blockStateCalls\": [{\"blockOverrides\": {\"baseFeePerGas\": \"0xa\"}, \"stateOverrides\": {\"0xc000000000000000000000000000000000000000\": {\"balance\": \"0x7d0\"}}, \"calls\": [{\"from\": \"0xc100000000000000000000000000000000000000\", \"to\": \"0xc100000000000000000000000000000000000000\", \"maxFeePerGas\": \"0x0\", \"maxPriorityFeePerGas\": \"0x0\"}]}]}"}, //new object[] {"multicall-block-override-reflected-in-contract-simple", "{\"blockStateCalls\": [{\"blockOverrides\": {\"number\": \"0x12a\", \"time\": \"0x64\"}}, {\"blockOverrides\": {\"number\": \"0x14\", \"time\": \"0x65\"}}, {\"blockOverrides\": {\"number\": \"0x15\", \"time\": \"0xc8\"}}]}"}, diff --git a/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/SimulateTxExecutor.cs b/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/SimulateTxExecutor.cs index 898f13ae6b2..c0bf2db8e26 100644 --- a/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/SimulateTxExecutor.cs +++ b/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/SimulateTxExecutor.cs @@ -3,11 +3,13 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using System.Threading; using Nethermind.Blockchain.Find; using Nethermind.Config; using Nethermind.Core; +using Nethermind.Core.Collections; using Nethermind.Facade; using Nethermind.Facade.Eth; using Nethermind.Facade.Proxy.Models.Simulate; @@ -42,10 +44,7 @@ protected override SimulatePayload Prepare(Simulat StateOverrides = blockStateCall.StateOverrides, Calls = blockStateCall.Calls?.Select(callTransactionModel => { - if (callTransactionModel.Type == TxType.Legacy) - { - callTransactionModel.Type = TxType.EIP1559; - } + UpdateTxType(callTransactionModel); bool hadGasLimitInRequest = callTransactionModel.Gas.HasValue; bool hadNonceInRequest = callTransactionModel.Nonce.HasValue; @@ -70,6 +69,19 @@ protected override SimulatePayload Prepare(Simulat return result; } + private static void UpdateTxType(TransactionForRpc callTransactionModel) + { + if (callTransactionModel.Type == TxType.Legacy) + { + callTransactionModel.Type = TxType.EIP1559; + } + + if (callTransactionModel.BlobVersionedHashes is not null) + { + callTransactionModel.Type = TxType.Blob; + } + } + public override ResultWrapper> Execute( SimulatePayload call, BlockParameter? blockParameter) @@ -194,19 +206,28 @@ protected override ResultWrapper> Execute(Blo { SimulateOutput results = _blockchainBridge.Simulate(header, tx, token); - if (results.Error is not null && (results.Error.Contains("invalid transaction") - || results.Error.Contains("InsufficientBalanceException") - )) - results.ErrorCode = ErrorCodes.InvalidTransaction; - - if (results.Error is not null && results.Error.Contains("InvalidBlockException")) - results.ErrorCode = ErrorCodes.InvalidParams; - - - if (results.Error is not null && results.Error.Contains("below intrinsic gas")) - results.ErrorCode = ErrorCodes.InsufficientIntrinsicGas; - + foreach (SimulateBlockResult result in results.Items) + { + foreach (SimulateCallResult? call in result.Calls) + { + if (call?.Error is not null && call.Error.Message != "") + { + call.Error.Code = ErrorCodes.ExecutionError; + } + } + } + if (results.Error is not null) + { + results.ErrorCode = results.Error switch + { + var x when x.Contains("invalid transaction") => ErrorCodes.InvalidTransaction, + var x when x.Contains("InsufficientBalanceException") => ErrorCodes.InvalidTransaction, + var x when x.Contains("InvalidBlockException") => ErrorCodes.InvalidParams, + var x when x.Contains("below intrinsic gas") => ErrorCodes.InsufficientIntrinsicGas, + _ => results.ErrorCode + }; + } return results.Error is null ? ResultWrapper>.Success(results.Items)