From 97618a14bf97f52d3fa230fe0a48fc684f285c91 Mon Sep 17 00:00:00 2001 From: Shubham Sonthalia Date: Sun, 15 Sep 2024 18:03:37 +0530 Subject: [PATCH 1/5] Adding debug_traceCallMany method. --- .../Modules/DebugModuleTests.cs | 55 +++++++------ .../Modules/DebugModule/DebugModuleFactory.cs | 11 ++- .../Modules/DebugModule/DebugRpcModule.cs | 80 ++++++++++++++++++- 3 files changed, 117 insertions(+), 29 deletions(-) diff --git a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/DebugModuleTests.cs b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/DebugModuleTests.cs index 00faf0cd169..46d209bea93 100644 --- a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/DebugModuleTests.cs +++ b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/DebugModuleTests.cs @@ -26,6 +26,7 @@ using Nethermind.JsonRpc.Modules.Eth; using Nethermind.Logging; using Nethermind.Serialization.Rlp; +using Nethermind.State; using NSubstitute; using NSubstitute.ReturnsExtensions; using NUnit.Framework; @@ -40,6 +41,8 @@ public class DebugModuleTests private readonly ISpecProvider specProvider = Substitute.For(); private readonly IDebugBridge debugBridge = Substitute.For(); private readonly MemDb _blocksDb = new(); + private readonly IBlockFinder _blockFinder = Substitute.For(); + private readonly IStateReader _stateReader = Substitute.For(); [Test] public async Task Get_from_db() @@ -50,7 +53,7 @@ public async Task Get_from_db() IConfigProvider configProvider = Substitute.For(); - DebugRpcModule rpcModule = new(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider); + DebugRpcModule rpcModule = new(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider, _blockFinder, _stateReader); using var response = await RpcTest.TestRequest(rpcModule, "debug_getFromDb", "STATE", key.ToHexString(true)) as JsonRpcSuccessResponse; @@ -64,7 +67,7 @@ public async Task Get_from_db_null_value() debugBridge.GetDbValue(Arg.Any(), Arg.Any()).Returns((byte[])null!); IConfigProvider configProvider = Substitute.For(); - DebugRpcModule rpcModule = new(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider); + DebugRpcModule rpcModule = new(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider, _blockFinder, _stateReader); byte[] key = new byte[] { 1, 2, 3 }; using var response = await RpcTest.TestRequest(rpcModule, "debug_getFromDb", "STATE", key.ToHexString(true)) as @@ -86,7 +89,7 @@ public async Task Get_chain_level(string parameter) new BlockInfo(TestItem.KeccakB, 1001), })); - DebugRpcModule rpcModule = new(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider); + DebugRpcModule rpcModule = new(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider, _blockFinder, _stateReader); using var response = await RpcTest.TestRequest(rpcModule, "debug_getChainLevel", parameter) as JsonRpcSuccessResponse; var chainLevel = response?.Result as ChainLevelForRpc; Assert.NotNull(chainLevel); @@ -101,7 +104,7 @@ public async Task Get_block_rlp_by_hash() Rlp rlp = decoder.Encode(Build.A.Block.WithNumber(1).TestObject); debugBridge.GetBlockRlp(new BlockParameter(Keccak.Zero)).Returns(rlp.Bytes); - DebugRpcModule rpcModule = new(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider); + DebugRpcModule rpcModule = new(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider, _blockFinder, _stateReader); using var response = await RpcTest.TestRequest(rpcModule, "debug_getBlockRlpByHash", $"{Keccak.Zero.Bytes.ToHexString()}") as JsonRpcSuccessResponse; Assert.That((byte[]?)response?.Result, Is.EqualTo(rlp.Bytes)); } @@ -114,7 +117,7 @@ public async Task Get_raw_Header() Rlp rlp = decoder.Encode(blk.Header); debugBridge.GetBlock(new BlockParameter((long)0)).Returns(blk); - DebugRpcModule rpcModule = new(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider); + DebugRpcModule rpcModule = new(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider, _blockFinder, _stateReader); using var response = await RpcTest.TestRequest(rpcModule, "debug_getRawHeader", $"{Keccak.Zero.Bytes.ToHexString()}") as JsonRpcSuccessResponse; Assert.That((byte[]?)response?.Result, Is.EqualTo(rlp.Bytes)); } @@ -127,7 +130,7 @@ public async Task Get_block_rlp() Rlp rlp = decoder.Encode(Build.A.Block.WithNumber(1).TestObject); localDebugBridge.GetBlockRlp(new BlockParameter(1)).Returns(rlp.Bytes); - DebugRpcModule rpcModule = new(LimboLogs.Instance, localDebugBridge, jsonRpcConfig, specProvider); + DebugRpcModule rpcModule = new(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider, _blockFinder, _stateReader); using var response = await RpcTest.TestRequest(rpcModule, "debug_getBlockRlp", "1") as JsonRpcSuccessResponse; Assert.That((byte[]?)response?.Result, Is.EqualTo(rlp.Bytes)); @@ -141,7 +144,7 @@ public async Task Get_rawblock() Rlp rlp = decoder.Encode(Build.A.Block.WithNumber(1).TestObject); localDebugBridge.GetBlockRlp(new BlockParameter(1)).Returns(rlp.Bytes); - DebugRpcModule rpcModule = new(LimboLogs.Instance, localDebugBridge, jsonRpcConfig, specProvider); + DebugRpcModule rpcModule = new(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider, _blockFinder, _stateReader); using var response = await RpcTest.TestRequest(rpcModule, "debug_getRawBlock", "1") as JsonRpcSuccessResponse; Assert.That((byte[]?)response?.Result, Is.EqualTo(rlp.Bytes)); @@ -152,7 +155,7 @@ public async Task Get_block_rlp_when_missing() { debugBridge.GetBlockRlp(new BlockParameter(1)).ReturnsNull(); - DebugRpcModule rpcModule = new(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider); + DebugRpcModule rpcModule = new(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider, _blockFinder, _stateReader); using var response = await RpcTest.TestRequest(rpcModule, "debug_getBlockRlp", "1") as JsonRpcErrorResponse; Assert.That(response?.Error?.Code, Is.EqualTo(-32001)); @@ -163,7 +166,7 @@ public async Task Get_rawblock_when_missing() { debugBridge.GetBlockRlp(new BlockParameter(1)).ReturnsNull(); - DebugRpcModule rpcModule = new(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider); + DebugRpcModule rpcModule = new(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider, _blockFinder, _stateReader); using var response = await RpcTest.TestRequest(rpcModule, "debug_getRawBlock", "1") as JsonRpcErrorResponse; Assert.That(response?.Error?.Code, Is.EqualTo(-32001)); @@ -176,7 +179,7 @@ public async Task Get_block_rlp_by_hash_when_missing() Rlp rlp = decoder.Encode(Build.A.Block.WithNumber(1).TestObject); debugBridge.GetBlockRlp(new BlockParameter(Keccak.Zero)).ReturnsNull(); - DebugRpcModule rpcModule = new(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider); + DebugRpcModule rpcModule = new(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider, _blockFinder, _stateReader); using var response = await RpcTest.TestRequest(rpcModule, "debug_getBlockRlpByHash", $"{Keccak.Zero.Bytes.ToHexString()}") as JsonRpcErrorResponse; Assert.That(response?.Error?.Code, Is.EqualTo(-32001)); @@ -214,7 +217,7 @@ public async Task Get_trace() debugBridge.GetTransactionTrace(Arg.Any(), Arg.Any(), Arg.Any()).Returns(trace); - DebugRpcModule rpcModule = new(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider); + DebugRpcModule rpcModule = new(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider, _blockFinder, _stateReader); string response = await RpcTest.TestSerializedRequest(rpcModule, "debug_traceTransaction", TestItem.KeccakA.ToString(true), "{}"); Assert.That(response, Is.EqualTo("{\"jsonrpc\":\"2.0\",\"result\":{\"gas\":\"0x0\",\"failed\":false,\"returnValue\":\"0xa2\",\"structLogs\":[{\"pc\":0,\"op\":\"STOP\",\"gas\":22000,\"gasCost\":1,\"depth\":1,\"error\":null,\"stack\":[\"0000000000000000000000000000000000000000000000000000000000000007\",\"0000000000000000000000000000000000000000000000000000000000000008\"],\"memory\":[\"0000000000000000000000000000000000000000000000000000000000000005\",\"0000000000000000000000000000000000000000000000000000000000000006\"],\"storage\":{\"0000000000000000000000000000000000000000000000000000000000000001\":\"0000000000000000000000000000000000000000000000000000000000000002\",\"0000000000000000000000000000000000000000000000000000000000000003\":\"0000000000000000000000000000000000000000000000000000000000000004\"}}]},\"id\":67}")); @@ -227,7 +230,7 @@ public async Task Get_js_trace() debugBridge.GetTransactionTrace(Arg.Any(), Arg.Any(), Arg.Any()).Returns(trace); - DebugRpcModule rpcModule = new(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider); + DebugRpcModule rpcModule = new(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider, _blockFinder, _stateReader); string response = await RpcTest.TestSerializedRequest(rpcModule, "debug_traceTransaction", TestItem.KeccakA.ToString(true), "{}"); Assert.That(response, Is.EqualTo("{\"jsonrpc\":\"2.0\",\"result\":{\"customProperty\":1},\"id\":67}")); @@ -263,7 +266,7 @@ public async Task Get_trace_with_options() debugBridge.GetTransactionTrace(Arg.Any(), Arg.Any(), Arg.Any()).Returns(trace); - DebugRpcModule rpcModule = new(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider); + DebugRpcModule rpcModule = new(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider, _blockFinder, _stateReader); string response = await RpcTest.TestSerializedRequest(rpcModule, "debug_traceTransaction", TestItem.KeccakA.ToString(true), "{\"disableStack\" : true}"); Assert.That(response, Is.EqualTo("{\"jsonrpc\":\"2.0\",\"result\":{\"gas\":\"0x0\",\"failed\":false,\"returnValue\":\"0xa2\",\"structLogs\":[{\"pc\":0,\"op\":\"STOP\",\"gas\":22000,\"gasCost\":1,\"depth\":1,\"error\":null,\"stack\":[],\"memory\":[\"0000000000000000000000000000000000000000000000000000000000000005\",\"0000000000000000000000000000000000000000000000000000000000000006\"],\"storage\":{\"0000000000000000000000000000000000000000000000000000000000000001\":\"0000000000000000000000000000000000000000000000000000000000000002\",\"0000000000000000000000000000000000000000000000000000000000000003\":\"0000000000000000000000000000000000000000000000000000000000000004\"}}]},\"id\":67}")); @@ -302,7 +305,7 @@ public void Debug_getBadBlocks_test() AddBlockResult result = blockTree.SuggestBlock(block1); Assert.That(result, Is.EqualTo(AddBlockResult.InvalidBlock)); - DebugRpcModule rpcModule = new(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider); + DebugRpcModule rpcModule = new(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider, _blockFinder, _stateReader); ResultWrapper> blocks = rpcModule.debug_getBadBlocks(); Assert.That(blocks.Data.Count, Is.EqualTo(1)); Assert.That(blocks.Data.ElementAt(0).Hash, Is.EqualTo(block1.Hash)); @@ -315,7 +318,7 @@ public async Task Get_trace_with_javascript_setup() GethTraceOptions passedOption = null!; debugBridge.GetTransactionTrace(Arg.Any(), Arg.Any(), Arg.Do(arg => passedOption = arg)) .Returns(new GethLikeTxTrace()); - DebugRpcModule rpcModule = new(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider); + DebugRpcModule rpcModule = new(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider, _blockFinder, _stateReader); await RpcTest.TestSerializedRequest(rpcModule, "debug_traceTransaction", TestItem.KeccakA.ToString(true), "{\"disableStack\" : true, \"tracerConfig\" : {\"a\":true} }"); passedOption.TracerConfig!.ToString().Should().Be("{\"a\":true}"); } @@ -354,7 +357,7 @@ public void Debug_traceCall_test() debugBridge.GetTransactionTrace(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any()).Returns(trace); - DebugRpcModule rpcModule = new(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider); + DebugRpcModule rpcModule = new(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider, _blockFinder, _stateReader); ResultWrapper debugTraceCall = rpcModule.debug_traceCall(txForRpc, null, gtOptions); var expected = ResultWrapper.Success( new GethLikeTxTrace() @@ -400,7 +403,7 @@ public void Debug_traceCall_test() public async Task Migrate_receipts() { debugBridge.MigrateReceipts(Arg.Any()).Returns(true); - IDebugRpcModule rpcModule = new DebugRpcModule(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider); + IDebugRpcModule rpcModule = new DebugRpcModule(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider, _blockFinder, _stateReader); string response = await RpcTest.TestSerializedRequest(rpcModule, "debug_migrateReceipts", "100"); Assert.NotNull(response); } @@ -409,7 +412,7 @@ public async Task Migrate_receipts() public async Task Update_head_block() { debugBridge.UpdateHeadBlock(Arg.Any()); - IDebugRpcModule rpcModule = new DebugRpcModule(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider); + IDebugRpcModule rpcModule = new DebugRpcModule(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider, _blockFinder, _stateReader); await RpcTest.TestSerializedRequest(rpcModule, "debug_resetHead", TestItem.KeccakA.ToString()); debugBridge.Received().UpdateHeadBlock(TestItem.KeccakA); } @@ -425,7 +428,7 @@ public void TraceBlock_Success() .GetBlockTrace(blockRlp, Arg.Any(), Arg.Any()) .Returns(traces); - var rpcModule = new DebugRpcModule(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider); + var rpcModule = new DebugRpcModule(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider, _blockFinder, _stateReader); var actual = rpcModule.debug_traceBlock(blockRlp.Bytes); var expected = ResultWrapper.Success(tracesClone); @@ -441,7 +444,7 @@ public void TraceBlock_Fail() .GetBlockTrace(blockRlp, Arg.Any(), Arg.Any()) .Returns(default(GethLikeTxTrace[])); - var rpcModule = new DebugRpcModule(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider); + var rpcModule = new DebugRpcModule(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider, _blockFinder, _stateReader); var actual = rpcModule.debug_traceBlock(blockRlp.Bytes); var expected = ResultWrapper.Fail($"Trace is null for RLP {blockRlp.Bytes.ToHexString()}", ErrorCodes.ResourceNotFound); @@ -460,7 +463,7 @@ static IEnumerable GetFileNames(Hash256 hash) => .TraceBlockToFile(Arg.Is(blockHash), Arg.Any(), Arg.Any()) .Returns(c => GetFileNames(c.ArgAt(0))); - var rpcModule = new DebugRpcModule(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider); + var rpcModule = new DebugRpcModule(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider, _blockFinder, _stateReader); var actual = rpcModule.debug_standardTraceBlockToFile(blockHash); var expected = ResultWrapper>.Success(GetFileNames(blockHash)); @@ -479,7 +482,7 @@ static IEnumerable GetFileNames(Hash256 hash) => .TraceBadBlockToFile(Arg.Is(blockHash), Arg.Any(), Arg.Any()) .Returns(c => GetFileNames(c.ArgAt(0))); - var rpcModule = new DebugRpcModule(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider); + var rpcModule = new DebugRpcModule(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider, _blockFinder, _stateReader); var actual = rpcModule.debug_standardTraceBadBlockToFile(blockHash); var expected = ResultWrapper>.Success(GetFileNames(blockHash)); @@ -497,7 +500,7 @@ public void TraceBlockByHash_Success() .GetBlockTrace(new BlockParameter(blockHash), Arg.Any(), Arg.Any()) .Returns(traces); - var rpcModule = new DebugRpcModule(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider); + var rpcModule = new DebugRpcModule(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider, _blockFinder, _stateReader); var actual = rpcModule.debug_traceBlockByHash(blockHash); var expected = ResultWrapper.Success(tracesClone); @@ -513,7 +516,7 @@ public void TraceBlockByHash_Fail() .GetBlockTrace(new BlockParameter(blockHash), Arg.Any(), Arg.Any()) .Returns(default(GethLikeTxTrace[])); - var rpcModule = new DebugRpcModule(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider); + var rpcModule = new DebugRpcModule(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider, _blockFinder, _stateReader); var actual = rpcModule.debug_traceBlockByHash(blockHash); var expected = ResultWrapper.Fail($"Trace is null for block {blockHash}", ErrorCodes.ResourceNotFound); @@ -531,7 +534,7 @@ public void TraceBlockByNumber_Success() .GetBlockTrace(blockNumber, Arg.Any(), Arg.Any()) .Returns(traces); - var rpcModule = new DebugRpcModule(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider); + var rpcModule = new DebugRpcModule(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider, _blockFinder, _stateReader); var actual = rpcModule.debug_traceBlockByNumber(blockNumber); var expected = ResultWrapper.Success(tracesClone); @@ -547,7 +550,7 @@ public void TraceBlockByNumber_Fail() .GetBlockTrace(blockNumber, Arg.Any(), Arg.Any()) .Returns(default(GethLikeTxTrace[])); - var rpcModule = new DebugRpcModule(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider); + var rpcModule = new DebugRpcModule(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider, _blockFinder, _stateReader); var actual = rpcModule.debug_traceBlockByNumber(blockNumber); var expected = ResultWrapper.Fail($"Trace is null for block {blockNumber}", ErrorCodes.ResourceNotFound); diff --git a/src/Nethermind/Nethermind.JsonRpc/Modules/DebugModule/DebugModuleFactory.cs b/src/Nethermind/Nethermind.JsonRpc/Modules/DebugModule/DebugModuleFactory.cs index a394e5a36ea..228914cd036 100644 --- a/src/Nethermind/Nethermind.JsonRpc/Modules/DebugModule/DebugModuleFactory.cs +++ b/src/Nethermind/Nethermind.JsonRpc/Modules/DebugModule/DebugModuleFactory.cs @@ -6,6 +6,7 @@ using System.IO.Abstractions; using Nethermind.Blockchain; using Nethermind.Blockchain.Blocks; +using Nethermind.Blockchain.Find; using Nethermind.Blockchain.Receipts; using Nethermind.Config; using Nethermind.Consensus.Processing; @@ -41,6 +42,8 @@ public class DebugModuleFactory : ModuleFactoryBase private readonly IBlockStore _badBlockStore; private readonly IFileSystem _fileSystem; private readonly ILogger _logger; + private readonly IBlockFinder _blockFinder; + private readonly IStateReader _stateReader; public DebugModuleFactory( IWorldStateManager worldStateManager, @@ -57,7 +60,9 @@ public DebugModuleFactory( ISyncModeSelector syncModeSelector, IBlockStore badBlockStore, IFileSystem fileSystem, - ILogManager logManager) + ILogManager logManager, + IBlockFinder blockFinder, + IStateReader stateReader) { _worldStateManager = worldStateManager; _dbProvider = dbProvider.AsReadOnly(false); @@ -75,6 +80,8 @@ public DebugModuleFactory( _badBlockStore = badBlockStore; _fileSystem = fileSystem ?? throw new ArgumentNullException(nameof(fileSystem)); _logger = logManager.GetClassLogger(); + _blockFinder = blockFinder ?? throw new ArgumentNullException(nameof(blockFinder)); + _stateReader = stateReader ?? throw new ArgumentNullException(nameof(stateReader)); } public override IDebugRpcModule Create() @@ -122,6 +129,6 @@ public override IDebugRpcModule Create() _syncModeSelector, _badBlockStore); - return new DebugRpcModule(_logManager, debugBridge, _jsonRpcConfig, _specProvider); + return new DebugRpcModule(_logManager, debugBridge, _jsonRpcConfig, _specProvider, _blockFinder, _stateReader); } } diff --git a/src/Nethermind/Nethermind.JsonRpc/Modules/DebugModule/DebugRpcModule.cs b/src/Nethermind/Nethermind.JsonRpc/Modules/DebugModule/DebugRpcModule.cs index 9c0b2919d32..dbee77b1fc8 100644 --- a/src/Nethermind/Nethermind.JsonRpc/Modules/DebugModule/DebugRpcModule.cs +++ b/src/Nethermind/Nethermind.JsonRpc/Modules/DebugModule/DebugRpcModule.cs @@ -19,6 +19,10 @@ using Nethermind.JsonRpc.Modules.Eth; using Nethermind.Core.Specs; using Nethermind.Facade.Eth; +using Nethermind.Evm.Tracing.ParityStyle; +using Nethermind.Int256; +using Newtonsoft.Json; +using Nethermind.State; namespace Nethermind.JsonRpc.Modules.DebugModule; @@ -30,8 +34,10 @@ public class DebugRpcModule : IDebugRpcModule private readonly IJsonRpcConfig _jsonRpcConfig; private readonly ISpecProvider _specProvider; private readonly BlockDecoder _blockDecoder; + private readonly IBlockFinder _blockFinder; + private readonly IStateReader _stateReader; - public DebugRpcModule(ILogManager logManager, IDebugBridge debugBridge, IJsonRpcConfig jsonRpcConfig, ISpecProvider specProvider) + public DebugRpcModule(ILogManager logManager, IDebugBridge debugBridge, IJsonRpcConfig jsonRpcConfig, ISpecProvider specProvider, IBlockFinder blockFinder, IStateReader stateReader) { _debugBridge = debugBridge ?? throw new ArgumentNullException(nameof(debugBridge)); _jsonRpcConfig = jsonRpcConfig ?? throw new ArgumentNullException(nameof(jsonRpcConfig)); @@ -39,6 +45,8 @@ public DebugRpcModule(ILogManager logManager, IDebugBridge debugBridge, IJsonRpc _logger = logManager.GetClassLogger(); _traceTimeout = TimeSpan.FromMilliseconds(_jsonRpcConfig.Timeout); _blockDecoder = new BlockDecoder(); + _blockFinder = blockFinder; + _stateReader = stateReader; } public ResultWrapper debug_getChainLevel(in long number) @@ -85,6 +93,45 @@ public ResultWrapper debug_traceCall(TransactionForRpc call, Bl if (_logger.IsTrace) _logger.Trace($"{nameof(debug_traceTransaction)} request {tx.Hash}, result: trace"); return ResultWrapper.Success(transactionTrace); } + public ResultWrapper> debug_traceCallMany(TransactionForRpcWithTraceTypes[] calls, BlockParameter? blockParameter = null) + { + blockParameter ??= BlockParameter.Latest; + using CancellationTokenSource cancellationTokenSource = new(_traceTimeout); + CancellationToken cancellationToken = cancellationTokenSource.Token; + + SearchResult headerSearch = SearchBlockHeaderForTraceCall(blockParameter); + if (headerSearch.IsError) + { + return ResultWrapper>.Fail(headerSearch); + } + + if (!_stateReader.HasStateForBlock(headerSearch.Object)) + { + return ResultWrapper>.Fail($"No state available for block {headerSearch.Object.ToString(BlockHeader.Format.FullHashAndNumber)}", ErrorCodes.ResourceUnavailable); + } + + Dictionary traceTypeByTransaction = new(calls.Length); + Transaction[] txs = new Transaction[calls.Length]; + for (int i = 0; i < calls.Length; i++) + { + calls[i].Transaction.EnsureDefaults(_jsonRpcConfig.GasCap); + Transaction tx = calls[i].Transaction.ToTransaction(); + tx.Hash = new Hash256(new UInt256((ulong)i).ToBigEndian()); + txs[i] = tx; + } + + Block block = new(headerSearch.Object!, txs, Enumerable.Empty()); + + IReadOnlyCollection traces = _debugBridge.GetBlockTrace(blockParameter, cancellationToken); + + if (traces is null) + { + return ResultWrapper>.Fail($"Failed to trace block transactions for input txns: {JsonConvert.SerializeObject(calls)}", ErrorCodes.ResourceNotFound); + } + + if (_logger.IsTrace) _logger.Trace($"{nameof(debug_traceCallMany)} with input transactions: {JsonConvert.SerializeObject(calls)} returned the result: {traces}"); + return ResultWrapper>.Success(traces); + } public ResultWrapper debug_traceTransactionByBlockhashAndIndex(Hash256 blockhash, int index, GethTraceOptions options = null) { @@ -378,4 +425,35 @@ public ResultWrapper> debug_getBadBlocks() IEnumerable badBlocks = _debugBridge.GetBadBlocks().Select(block => new BadBlock(block, true, _specProvider, _blockDecoder)); return ResultWrapper>.Success(badBlocks); } + + private SearchResult SearchBlockHeaderForTraceCall(BlockParameter blockParameter) + { + SearchResult headerSearch = _blockFinder.SearchForHeader(blockParameter); + if (headerSearch.IsError) + { + return headerSearch; + } + + BlockHeader header = headerSearch.Object; + if (header!.IsGenesis) + { + UInt256 baseFee = header.BaseFeePerGas; + header = new BlockHeader( + header.Hash!, + Keccak.OfAnEmptySequenceRlp, + Address.Zero, + header.Difficulty, + header.Number + 1, + header.GasLimit, + header.Timestamp + 1, + header.ExtraData, + header.BlobGasUsed, + header.ExcessBlobGas); + + header.TotalDifficulty = 2 * header.Difficulty; + header.BaseFeePerGas = baseFee; + } + + return new SearchResult(header); + } } From a7e29c739a588c465e45e30c1e55ad6db0c43a68 Mon Sep 17 00:00:00 2001 From: Shubham Sonthalia Date: Mon, 16 Sep 2024 09:33:13 +0530 Subject: [PATCH 2/5] Adding new parameters and methods to DebugBridge --- .../Modules/DebugModuleTests.cs | 52 +++++++++---------- .../Modules/DebugModule/DebugBridge.cs | 42 ++++++++++++++- .../Modules/DebugModule/DebugModuleFactory.cs | 7 ++- .../Modules/DebugModule/DebugRpcModule.cs | 41 ++------------- .../Modules/DebugModule/IDebugBridge.cs | 2 + 5 files changed, 75 insertions(+), 69 deletions(-) diff --git a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/DebugModuleTests.cs b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/DebugModuleTests.cs index 46d209bea93..9fb18504973 100644 --- a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/DebugModuleTests.cs +++ b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/DebugModuleTests.cs @@ -53,7 +53,7 @@ public async Task Get_from_db() IConfigProvider configProvider = Substitute.For(); - DebugRpcModule rpcModule = new(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider, _blockFinder, _stateReader); + DebugRpcModule rpcModule = new(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider); using var response = await RpcTest.TestRequest(rpcModule, "debug_getFromDb", "STATE", key.ToHexString(true)) as JsonRpcSuccessResponse; @@ -67,7 +67,7 @@ public async Task Get_from_db_null_value() debugBridge.GetDbValue(Arg.Any(), Arg.Any()).Returns((byte[])null!); IConfigProvider configProvider = Substitute.For(); - DebugRpcModule rpcModule = new(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider, _blockFinder, _stateReader); + DebugRpcModule rpcModule = new(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider); byte[] key = new byte[] { 1, 2, 3 }; using var response = await RpcTest.TestRequest(rpcModule, "debug_getFromDb", "STATE", key.ToHexString(true)) as @@ -89,7 +89,7 @@ public async Task Get_chain_level(string parameter) new BlockInfo(TestItem.KeccakB, 1001), })); - DebugRpcModule rpcModule = new(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider, _blockFinder, _stateReader); + DebugRpcModule rpcModule = new(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider); using var response = await RpcTest.TestRequest(rpcModule, "debug_getChainLevel", parameter) as JsonRpcSuccessResponse; var chainLevel = response?.Result as ChainLevelForRpc; Assert.NotNull(chainLevel); @@ -104,7 +104,7 @@ public async Task Get_block_rlp_by_hash() Rlp rlp = decoder.Encode(Build.A.Block.WithNumber(1).TestObject); debugBridge.GetBlockRlp(new BlockParameter(Keccak.Zero)).Returns(rlp.Bytes); - DebugRpcModule rpcModule = new(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider, _blockFinder, _stateReader); + DebugRpcModule rpcModule = new(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider); using var response = await RpcTest.TestRequest(rpcModule, "debug_getBlockRlpByHash", $"{Keccak.Zero.Bytes.ToHexString()}") as JsonRpcSuccessResponse; Assert.That((byte[]?)response?.Result, Is.EqualTo(rlp.Bytes)); } @@ -117,7 +117,7 @@ public async Task Get_raw_Header() Rlp rlp = decoder.Encode(blk.Header); debugBridge.GetBlock(new BlockParameter((long)0)).Returns(blk); - DebugRpcModule rpcModule = new(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider, _blockFinder, _stateReader); + DebugRpcModule rpcModule = new(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider); using var response = await RpcTest.TestRequest(rpcModule, "debug_getRawHeader", $"{Keccak.Zero.Bytes.ToHexString()}") as JsonRpcSuccessResponse; Assert.That((byte[]?)response?.Result, Is.EqualTo(rlp.Bytes)); } @@ -130,7 +130,7 @@ public async Task Get_block_rlp() Rlp rlp = decoder.Encode(Build.A.Block.WithNumber(1).TestObject); localDebugBridge.GetBlockRlp(new BlockParameter(1)).Returns(rlp.Bytes); - DebugRpcModule rpcModule = new(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider, _blockFinder, _stateReader); + DebugRpcModule rpcModule = new(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider); using var response = await RpcTest.TestRequest(rpcModule, "debug_getBlockRlp", "1") as JsonRpcSuccessResponse; Assert.That((byte[]?)response?.Result, Is.EqualTo(rlp.Bytes)); @@ -144,7 +144,7 @@ public async Task Get_rawblock() Rlp rlp = decoder.Encode(Build.A.Block.WithNumber(1).TestObject); localDebugBridge.GetBlockRlp(new BlockParameter(1)).Returns(rlp.Bytes); - DebugRpcModule rpcModule = new(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider, _blockFinder, _stateReader); + DebugRpcModule rpcModule = new(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider); using var response = await RpcTest.TestRequest(rpcModule, "debug_getRawBlock", "1") as JsonRpcSuccessResponse; Assert.That((byte[]?)response?.Result, Is.EqualTo(rlp.Bytes)); @@ -155,7 +155,7 @@ public async Task Get_block_rlp_when_missing() { debugBridge.GetBlockRlp(new BlockParameter(1)).ReturnsNull(); - DebugRpcModule rpcModule = new(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider, _blockFinder, _stateReader); + DebugRpcModule rpcModule = new(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider); using var response = await RpcTest.TestRequest(rpcModule, "debug_getBlockRlp", "1") as JsonRpcErrorResponse; Assert.That(response?.Error?.Code, Is.EqualTo(-32001)); @@ -166,7 +166,7 @@ public async Task Get_rawblock_when_missing() { debugBridge.GetBlockRlp(new BlockParameter(1)).ReturnsNull(); - DebugRpcModule rpcModule = new(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider, _blockFinder, _stateReader); + DebugRpcModule rpcModule = new(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider); using var response = await RpcTest.TestRequest(rpcModule, "debug_getRawBlock", "1") as JsonRpcErrorResponse; Assert.That(response?.Error?.Code, Is.EqualTo(-32001)); @@ -179,7 +179,7 @@ public async Task Get_block_rlp_by_hash_when_missing() Rlp rlp = decoder.Encode(Build.A.Block.WithNumber(1).TestObject); debugBridge.GetBlockRlp(new BlockParameter(Keccak.Zero)).ReturnsNull(); - DebugRpcModule rpcModule = new(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider, _blockFinder, _stateReader); + DebugRpcModule rpcModule = new(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider); using var response = await RpcTest.TestRequest(rpcModule, "debug_getBlockRlpByHash", $"{Keccak.Zero.Bytes.ToHexString()}") as JsonRpcErrorResponse; Assert.That(response?.Error?.Code, Is.EqualTo(-32001)); @@ -217,7 +217,7 @@ public async Task Get_trace() debugBridge.GetTransactionTrace(Arg.Any(), Arg.Any(), Arg.Any()).Returns(trace); - DebugRpcModule rpcModule = new(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider, _blockFinder, _stateReader); + DebugRpcModule rpcModule = new(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider); string response = await RpcTest.TestSerializedRequest(rpcModule, "debug_traceTransaction", TestItem.KeccakA.ToString(true), "{}"); Assert.That(response, Is.EqualTo("{\"jsonrpc\":\"2.0\",\"result\":{\"gas\":\"0x0\",\"failed\":false,\"returnValue\":\"0xa2\",\"structLogs\":[{\"pc\":0,\"op\":\"STOP\",\"gas\":22000,\"gasCost\":1,\"depth\":1,\"error\":null,\"stack\":[\"0000000000000000000000000000000000000000000000000000000000000007\",\"0000000000000000000000000000000000000000000000000000000000000008\"],\"memory\":[\"0000000000000000000000000000000000000000000000000000000000000005\",\"0000000000000000000000000000000000000000000000000000000000000006\"],\"storage\":{\"0000000000000000000000000000000000000000000000000000000000000001\":\"0000000000000000000000000000000000000000000000000000000000000002\",\"0000000000000000000000000000000000000000000000000000000000000003\":\"0000000000000000000000000000000000000000000000000000000000000004\"}}]},\"id\":67}")); @@ -230,7 +230,7 @@ public async Task Get_js_trace() debugBridge.GetTransactionTrace(Arg.Any(), Arg.Any(), Arg.Any()).Returns(trace); - DebugRpcModule rpcModule = new(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider, _blockFinder, _stateReader); + DebugRpcModule rpcModule = new(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider); string response = await RpcTest.TestSerializedRequest(rpcModule, "debug_traceTransaction", TestItem.KeccakA.ToString(true), "{}"); Assert.That(response, Is.EqualTo("{\"jsonrpc\":\"2.0\",\"result\":{\"customProperty\":1},\"id\":67}")); @@ -266,7 +266,7 @@ public async Task Get_trace_with_options() debugBridge.GetTransactionTrace(Arg.Any(), Arg.Any(), Arg.Any()).Returns(trace); - DebugRpcModule rpcModule = new(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider, _blockFinder, _stateReader); + DebugRpcModule rpcModule = new(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider); string response = await RpcTest.TestSerializedRequest(rpcModule, "debug_traceTransaction", TestItem.KeccakA.ToString(true), "{\"disableStack\" : true}"); Assert.That(response, Is.EqualTo("{\"jsonrpc\":\"2.0\",\"result\":{\"gas\":\"0x0\",\"failed\":false,\"returnValue\":\"0xa2\",\"structLogs\":[{\"pc\":0,\"op\":\"STOP\",\"gas\":22000,\"gasCost\":1,\"depth\":1,\"error\":null,\"stack\":[],\"memory\":[\"0000000000000000000000000000000000000000000000000000000000000005\",\"0000000000000000000000000000000000000000000000000000000000000006\"],\"storage\":{\"0000000000000000000000000000000000000000000000000000000000000001\":\"0000000000000000000000000000000000000000000000000000000000000002\",\"0000000000000000000000000000000000000000000000000000000000000003\":\"0000000000000000000000000000000000000000000000000000000000000004\"}}]},\"id\":67}")); @@ -305,7 +305,7 @@ public void Debug_getBadBlocks_test() AddBlockResult result = blockTree.SuggestBlock(block1); Assert.That(result, Is.EqualTo(AddBlockResult.InvalidBlock)); - DebugRpcModule rpcModule = new(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider, _blockFinder, _stateReader); + DebugRpcModule rpcModule = new(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider); ResultWrapper> blocks = rpcModule.debug_getBadBlocks(); Assert.That(blocks.Data.Count, Is.EqualTo(1)); Assert.That(blocks.Data.ElementAt(0).Hash, Is.EqualTo(block1.Hash)); @@ -318,7 +318,7 @@ public async Task Get_trace_with_javascript_setup() GethTraceOptions passedOption = null!; debugBridge.GetTransactionTrace(Arg.Any(), Arg.Any(), Arg.Do(arg => passedOption = arg)) .Returns(new GethLikeTxTrace()); - DebugRpcModule rpcModule = new(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider, _blockFinder, _stateReader); + DebugRpcModule rpcModule = new(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider); await RpcTest.TestSerializedRequest(rpcModule, "debug_traceTransaction", TestItem.KeccakA.ToString(true), "{\"disableStack\" : true, \"tracerConfig\" : {\"a\":true} }"); passedOption.TracerConfig!.ToString().Should().Be("{\"a\":true}"); } @@ -357,7 +357,7 @@ public void Debug_traceCall_test() debugBridge.GetTransactionTrace(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any()).Returns(trace); - DebugRpcModule rpcModule = new(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider, _blockFinder, _stateReader); + DebugRpcModule rpcModule = new(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider); ResultWrapper debugTraceCall = rpcModule.debug_traceCall(txForRpc, null, gtOptions); var expected = ResultWrapper.Success( new GethLikeTxTrace() @@ -403,7 +403,7 @@ public void Debug_traceCall_test() public async Task Migrate_receipts() { debugBridge.MigrateReceipts(Arg.Any()).Returns(true); - IDebugRpcModule rpcModule = new DebugRpcModule(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider, _blockFinder, _stateReader); + IDebugRpcModule rpcModule = new DebugRpcModule(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider); string response = await RpcTest.TestSerializedRequest(rpcModule, "debug_migrateReceipts", "100"); Assert.NotNull(response); } @@ -412,7 +412,7 @@ public async Task Migrate_receipts() public async Task Update_head_block() { debugBridge.UpdateHeadBlock(Arg.Any()); - IDebugRpcModule rpcModule = new DebugRpcModule(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider, _blockFinder, _stateReader); + IDebugRpcModule rpcModule = new DebugRpcModule(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider); await RpcTest.TestSerializedRequest(rpcModule, "debug_resetHead", TestItem.KeccakA.ToString()); debugBridge.Received().UpdateHeadBlock(TestItem.KeccakA); } @@ -428,7 +428,7 @@ public void TraceBlock_Success() .GetBlockTrace(blockRlp, Arg.Any(), Arg.Any()) .Returns(traces); - var rpcModule = new DebugRpcModule(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider, _blockFinder, _stateReader); + var rpcModule = new DebugRpcModule(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider); var actual = rpcModule.debug_traceBlock(blockRlp.Bytes); var expected = ResultWrapper.Success(tracesClone); @@ -444,7 +444,7 @@ public void TraceBlock_Fail() .GetBlockTrace(blockRlp, Arg.Any(), Arg.Any()) .Returns(default(GethLikeTxTrace[])); - var rpcModule = new DebugRpcModule(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider, _blockFinder, _stateReader); + var rpcModule = new DebugRpcModule(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider); var actual = rpcModule.debug_traceBlock(blockRlp.Bytes); var expected = ResultWrapper.Fail($"Trace is null for RLP {blockRlp.Bytes.ToHexString()}", ErrorCodes.ResourceNotFound); @@ -463,7 +463,7 @@ static IEnumerable GetFileNames(Hash256 hash) => .TraceBlockToFile(Arg.Is(blockHash), Arg.Any(), Arg.Any()) .Returns(c => GetFileNames(c.ArgAt(0))); - var rpcModule = new DebugRpcModule(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider, _blockFinder, _stateReader); + var rpcModule = new DebugRpcModule(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider); var actual = rpcModule.debug_standardTraceBlockToFile(blockHash); var expected = ResultWrapper>.Success(GetFileNames(blockHash)); @@ -482,7 +482,7 @@ static IEnumerable GetFileNames(Hash256 hash) => .TraceBadBlockToFile(Arg.Is(blockHash), Arg.Any(), Arg.Any()) .Returns(c => GetFileNames(c.ArgAt(0))); - var rpcModule = new DebugRpcModule(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider, _blockFinder, _stateReader); + var rpcModule = new DebugRpcModule(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider); var actual = rpcModule.debug_standardTraceBadBlockToFile(blockHash); var expected = ResultWrapper>.Success(GetFileNames(blockHash)); @@ -500,7 +500,7 @@ public void TraceBlockByHash_Success() .GetBlockTrace(new BlockParameter(blockHash), Arg.Any(), Arg.Any()) .Returns(traces); - var rpcModule = new DebugRpcModule(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider, _blockFinder, _stateReader); + var rpcModule = new DebugRpcModule(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider); var actual = rpcModule.debug_traceBlockByHash(blockHash); var expected = ResultWrapper.Success(tracesClone); @@ -516,7 +516,7 @@ public void TraceBlockByHash_Fail() .GetBlockTrace(new BlockParameter(blockHash), Arg.Any(), Arg.Any()) .Returns(default(GethLikeTxTrace[])); - var rpcModule = new DebugRpcModule(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider, _blockFinder, _stateReader); + var rpcModule = new DebugRpcModule(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider); var actual = rpcModule.debug_traceBlockByHash(blockHash); var expected = ResultWrapper.Fail($"Trace is null for block {blockHash}", ErrorCodes.ResourceNotFound); @@ -534,7 +534,7 @@ public void TraceBlockByNumber_Success() .GetBlockTrace(blockNumber, Arg.Any(), Arg.Any()) .Returns(traces); - var rpcModule = new DebugRpcModule(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider, _blockFinder, _stateReader); + var rpcModule = new DebugRpcModule(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider); var actual = rpcModule.debug_traceBlockByNumber(blockNumber); var expected = ResultWrapper.Success(tracesClone); @@ -550,7 +550,7 @@ public void TraceBlockByNumber_Fail() .GetBlockTrace(blockNumber, Arg.Any(), Arg.Any()) .Returns(default(GethLikeTxTrace[])); - var rpcModule = new DebugRpcModule(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider, _blockFinder, _stateReader); + var rpcModule = new DebugRpcModule(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider); var actual = rpcModule.debug_traceBlockByNumber(blockNumber); var expected = ResultWrapper.Fail($"Trace is null for block {blockNumber}", ErrorCodes.ResourceNotFound); diff --git a/src/Nethermind/Nethermind.JsonRpc/Modules/DebugModule/DebugBridge.cs b/src/Nethermind/Nethermind.JsonRpc/Modules/DebugModule/DebugBridge.cs index dd7d34ebc82..8876153aadd 100644 --- a/src/Nethermind/Nethermind.JsonRpc/Modules/DebugModule/DebugBridge.cs +++ b/src/Nethermind/Nethermind.JsonRpc/Modules/DebugModule/DebugBridge.cs @@ -17,7 +17,9 @@ using Nethermind.Core.Specs; using Nethermind.Db; using Nethermind.Evm.Tracing.GethStyle; +using Nethermind.Int256; using Nethermind.Serialization.Rlp; +using Nethermind.State; using Nethermind.State.Proofs; using Nethermind.Synchronization.ParallelSync; using Nethermind.Synchronization.Reporting; @@ -36,6 +38,7 @@ public class DebugBridge : IDebugBridge private readonly IBlockStore _badBlockStore; private readonly IBlockStore _blockStore; private readonly Dictionary _dbMappings; + private readonly IStateReader _stateReader; public DebugBridge( IConfigProvider configProvider, @@ -46,7 +49,8 @@ public DebugBridge( IReceiptsMigration receiptsMigration, ISpecProvider specProvider, ISyncModeSelector syncModeSelector, - IBlockStore badBlockStore) + IBlockStore badBlockStore, + IStateReader stateReader) { _configProvider = configProvider ?? throw new ArgumentNullException(nameof(configProvider)); _tracer = tracer ?? throw new ArgumentNullException(nameof(tracer)); @@ -56,12 +60,14 @@ public DebugBridge( _specProvider = specProvider ?? throw new ArgumentNullException(nameof(specProvider)); _syncModeSelector = syncModeSelector ?? throw new ArgumentNullException(nameof(syncModeSelector)); _badBlockStore = badBlockStore; + _stateReader = stateReader ?? throw new ArgumentNullException(nameof(stateReader)); dbProvider = dbProvider ?? throw new ArgumentNullException(nameof(dbProvider)); IDb blockInfosDb = dbProvider.BlockInfosDb ?? throw new ArgumentNullException(nameof(dbProvider.BlockInfosDb)); IDb blocksDb = dbProvider.BlocksDb ?? throw new ArgumentNullException(nameof(dbProvider.BlocksDb)); IDb headersDb = dbProvider.HeadersDb ?? throw new ArgumentNullException(nameof(dbProvider.HeadersDb)); IDb codeDb = dbProvider.CodeDb ?? throw new ArgumentNullException(nameof(dbProvider.CodeDb)); IDb metadataDb = dbProvider.MetadataDb ?? throw new ArgumentNullException(nameof(dbProvider.MetadataDb)); + _dbMappings = new Dictionary(StringComparer.InvariantCultureIgnoreCase) { @@ -212,4 +218,38 @@ public IEnumerable TraceBadBlockToFile( CancellationToken cancellationToken, GethTraceOptions? gethTraceOptions = null) => _tracer.TraceBadBlockToFile(blockHash, gethTraceOptions ?? GethTraceOptions.Default, cancellationToken); + + public SearchResult SearchBlockHeaderForTraceCall(BlockParameter blockParameter) + { + SearchResult headerSearch = _blockTree.SearchForHeader(blockParameter); + if (headerSearch.IsError) + { + return headerSearch; + } + + BlockHeader header = headerSearch.Object; + if (header!.IsGenesis) + { + UInt256 baseFee = header.BaseFeePerGas; + header = new BlockHeader( + header.Hash!, + Keccak.OfAnEmptySequenceRlp, + Address.Zero, + header.Difficulty, + header.Number + 1, + header.GasLimit, + header.Timestamp + 1, + header.ExtraData, + header.BlobGasUsed, + header.ExcessBlobGas); + + header.TotalDifficulty = 2 * header.Difficulty; + header.BaseFeePerGas = baseFee; + } + + return new SearchResult(header); + } + + public bool HasStateForBlock(BlockHeader header) => _stateReader.HasStateForBlock(header); + } diff --git a/src/Nethermind/Nethermind.JsonRpc/Modules/DebugModule/DebugModuleFactory.cs b/src/Nethermind/Nethermind.JsonRpc/Modules/DebugModule/DebugModuleFactory.cs index 228914cd036..436bbe3674b 100644 --- a/src/Nethermind/Nethermind.JsonRpc/Modules/DebugModule/DebugModuleFactory.cs +++ b/src/Nethermind/Nethermind.JsonRpc/Modules/DebugModule/DebugModuleFactory.cs @@ -42,7 +42,6 @@ public class DebugModuleFactory : ModuleFactoryBase private readonly IBlockStore _badBlockStore; private readonly IFileSystem _fileSystem; private readonly ILogger _logger; - private readonly IBlockFinder _blockFinder; private readonly IStateReader _stateReader; public DebugModuleFactory( @@ -80,7 +79,6 @@ public DebugModuleFactory( _badBlockStore = badBlockStore; _fileSystem = fileSystem ?? throw new ArgumentNullException(nameof(fileSystem)); _logger = logManager.GetClassLogger(); - _blockFinder = blockFinder ?? throw new ArgumentNullException(nameof(blockFinder)); _stateReader = stateReader ?? throw new ArgumentNullException(nameof(stateReader)); } @@ -127,8 +125,9 @@ public override IDebugRpcModule Create() _receiptsMigration, _specProvider, _syncModeSelector, - _badBlockStore); + _badBlockStore, + _stateReader); - return new DebugRpcModule(_logManager, debugBridge, _jsonRpcConfig, _specProvider, _blockFinder, _stateReader); + return new DebugRpcModule(_logManager, debugBridge, _jsonRpcConfig, _specProvider); } } diff --git a/src/Nethermind/Nethermind.JsonRpc/Modules/DebugModule/DebugRpcModule.cs b/src/Nethermind/Nethermind.JsonRpc/Modules/DebugModule/DebugRpcModule.cs index dbee77b1fc8..76028bcfcc0 100644 --- a/src/Nethermind/Nethermind.JsonRpc/Modules/DebugModule/DebugRpcModule.cs +++ b/src/Nethermind/Nethermind.JsonRpc/Modules/DebugModule/DebugRpcModule.cs @@ -34,10 +34,8 @@ public class DebugRpcModule : IDebugRpcModule private readonly IJsonRpcConfig _jsonRpcConfig; private readonly ISpecProvider _specProvider; private readonly BlockDecoder _blockDecoder; - private readonly IBlockFinder _blockFinder; - private readonly IStateReader _stateReader; - public DebugRpcModule(ILogManager logManager, IDebugBridge debugBridge, IJsonRpcConfig jsonRpcConfig, ISpecProvider specProvider, IBlockFinder blockFinder, IStateReader stateReader) + public DebugRpcModule(ILogManager logManager, IDebugBridge debugBridge, IJsonRpcConfig jsonRpcConfig, ISpecProvider specProvider) { _debugBridge = debugBridge ?? throw new ArgumentNullException(nameof(debugBridge)); _jsonRpcConfig = jsonRpcConfig ?? throw new ArgumentNullException(nameof(jsonRpcConfig)); @@ -45,8 +43,6 @@ public DebugRpcModule(ILogManager logManager, IDebugBridge debugBridge, IJsonRpc _logger = logManager.GetClassLogger(); _traceTimeout = TimeSpan.FromMilliseconds(_jsonRpcConfig.Timeout); _blockDecoder = new BlockDecoder(); - _blockFinder = blockFinder; - _stateReader = stateReader; } public ResultWrapper debug_getChainLevel(in long number) @@ -99,13 +95,13 @@ public ResultWrapper> debug_traceCallMany(Transacti using CancellationTokenSource cancellationTokenSource = new(_traceTimeout); CancellationToken cancellationToken = cancellationTokenSource.Token; - SearchResult headerSearch = SearchBlockHeaderForTraceCall(blockParameter); + SearchResult headerSearch = _debugBridge.SearchBlockHeaderForTraceCall(blockParameter); if (headerSearch.IsError) { return ResultWrapper>.Fail(headerSearch); } - if (!_stateReader.HasStateForBlock(headerSearch.Object)) + if (!_debugBridge.HasStateForBlock(headerSearch.Object)) { return ResultWrapper>.Fail($"No state available for block {headerSearch.Object.ToString(BlockHeader.Format.FullHashAndNumber)}", ErrorCodes.ResourceUnavailable); } @@ -425,35 +421,4 @@ public ResultWrapper> debug_getBadBlocks() IEnumerable badBlocks = _debugBridge.GetBadBlocks().Select(block => new BadBlock(block, true, _specProvider, _blockDecoder)); return ResultWrapper>.Success(badBlocks); } - - private SearchResult SearchBlockHeaderForTraceCall(BlockParameter blockParameter) - { - SearchResult headerSearch = _blockFinder.SearchForHeader(blockParameter); - if (headerSearch.IsError) - { - return headerSearch; - } - - BlockHeader header = headerSearch.Object; - if (header!.IsGenesis) - { - UInt256 baseFee = header.BaseFeePerGas; - header = new BlockHeader( - header.Hash!, - Keccak.OfAnEmptySequenceRlp, - Address.Zero, - header.Difficulty, - header.Number + 1, - header.GasLimit, - header.Timestamp + 1, - header.ExtraData, - header.BlobGasUsed, - header.ExcessBlobGas); - - header.TotalDifficulty = 2 * header.Difficulty; - header.BaseFeePerGas = baseFee; - } - - return new SearchResult(header); - } } diff --git a/src/Nethermind/Nethermind.JsonRpc/Modules/DebugModule/IDebugBridge.cs b/src/Nethermind/Nethermind.JsonRpc/Modules/DebugModule/IDebugBridge.cs index 9b8db38d2cf..1d3299625e9 100644 --- a/src/Nethermind/Nethermind.JsonRpc/Modules/DebugModule/IDebugBridge.cs +++ b/src/Nethermind/Nethermind.JsonRpc/Modules/DebugModule/IDebugBridge.cs @@ -39,4 +39,6 @@ public interface IDebugBridge public IEnumerable GetBadBlocks(); TxReceipt[]? GetReceiptsForBlock(BlockParameter param); Transaction? GetTransactionFromHash(Hash256 hash); + public SearchResult SearchBlockHeaderForTraceCall(BlockParameter blockParameter); + public bool HasStateForBlock(BlockHeader header); } From be56e2b3a975aec7620ca80de6a0be579824993f Mon Sep 17 00:00:00 2001 From: Shubham Sonthalia Date: Mon, 16 Sep 2024 09:38:41 +0530 Subject: [PATCH 3/5] Removing fields from DebugModuleTests --- .../Nethermind.JsonRpc.Test/Modules/DebugModuleTests.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/DebugModuleTests.cs b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/DebugModuleTests.cs index 9fb18504973..d39c5763252 100644 --- a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/DebugModuleTests.cs +++ b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/DebugModuleTests.cs @@ -41,8 +41,7 @@ public class DebugModuleTests private readonly ISpecProvider specProvider = Substitute.For(); private readonly IDebugBridge debugBridge = Substitute.For(); private readonly MemDb _blocksDb = new(); - private readonly IBlockFinder _blockFinder = Substitute.For(); - private readonly IStateReader _stateReader = Substitute.For(); + [Test] public async Task Get_from_db() From 2b6991596f4de24bd630ec60d1627e6adc435583 Mon Sep 17 00:00:00 2001 From: Shubham Sonthalia Date: Mon, 16 Sep 2024 09:42:59 +0530 Subject: [PATCH 4/5] Resolving errors --- .../Nethermind.JsonRpc.Test/Modules/DebugModuleTests.cs | 6 ++---- .../Modules/DebugModule/DebugModuleFactory.cs | 1 - 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/DebugModuleTests.cs b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/DebugModuleTests.cs index d39c5763252..00faf0cd169 100644 --- a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/DebugModuleTests.cs +++ b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/DebugModuleTests.cs @@ -26,7 +26,6 @@ using Nethermind.JsonRpc.Modules.Eth; using Nethermind.Logging; using Nethermind.Serialization.Rlp; -using Nethermind.State; using NSubstitute; using NSubstitute.ReturnsExtensions; using NUnit.Framework; @@ -42,7 +41,6 @@ public class DebugModuleTests private readonly IDebugBridge debugBridge = Substitute.For(); private readonly MemDb _blocksDb = new(); - [Test] public async Task Get_from_db() { @@ -129,7 +127,7 @@ public async Task Get_block_rlp() Rlp rlp = decoder.Encode(Build.A.Block.WithNumber(1).TestObject); localDebugBridge.GetBlockRlp(new BlockParameter(1)).Returns(rlp.Bytes); - DebugRpcModule rpcModule = new(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider); + DebugRpcModule rpcModule = new(LimboLogs.Instance, localDebugBridge, jsonRpcConfig, specProvider); using var response = await RpcTest.TestRequest(rpcModule, "debug_getBlockRlp", "1") as JsonRpcSuccessResponse; Assert.That((byte[]?)response?.Result, Is.EqualTo(rlp.Bytes)); @@ -143,7 +141,7 @@ public async Task Get_rawblock() Rlp rlp = decoder.Encode(Build.A.Block.WithNumber(1).TestObject); localDebugBridge.GetBlockRlp(new BlockParameter(1)).Returns(rlp.Bytes); - DebugRpcModule rpcModule = new(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider); + DebugRpcModule rpcModule = new(LimboLogs.Instance, localDebugBridge, jsonRpcConfig, specProvider); using var response = await RpcTest.TestRequest(rpcModule, "debug_getRawBlock", "1") as JsonRpcSuccessResponse; Assert.That((byte[]?)response?.Result, Is.EqualTo(rlp.Bytes)); diff --git a/src/Nethermind/Nethermind.JsonRpc/Modules/DebugModule/DebugModuleFactory.cs b/src/Nethermind/Nethermind.JsonRpc/Modules/DebugModule/DebugModuleFactory.cs index 436bbe3674b..833568c0066 100644 --- a/src/Nethermind/Nethermind.JsonRpc/Modules/DebugModule/DebugModuleFactory.cs +++ b/src/Nethermind/Nethermind.JsonRpc/Modules/DebugModule/DebugModuleFactory.cs @@ -60,7 +60,6 @@ public DebugModuleFactory( IBlockStore badBlockStore, IFileSystem fileSystem, ILogManager logManager, - IBlockFinder blockFinder, IStateReader stateReader) { _worldStateManager = worldStateManager; From bec97104c388d046f4570ffcc6a0af02775060de Mon Sep 17 00:00:00 2001 From: Shubham Sonthalia Date: Mon, 16 Sep 2024 20:46:38 +0530 Subject: [PATCH 5/5] Write test for debug_traceCallMany --- .../Steps/RegisterRpcModules.cs | 3 +- .../Modules/DebugModuleTests.cs | 103 ++++++++++++++++++ .../Modules/DebugModule/DebugRpcModule.cs | 2 +- .../Modules/DebugModule/IDebugRpcModule.cs | 3 + 4 files changed, 109 insertions(+), 2 deletions(-) diff --git a/src/Nethermind/Nethermind.Init/Steps/RegisterRpcModules.cs b/src/Nethermind/Nethermind.Init/Steps/RegisterRpcModules.cs index db5341d33b4..7c661f2703f 100644 --- a/src/Nethermind/Nethermind.Init/Steps/RegisterRpcModules.cs +++ b/src/Nethermind/Nethermind.Init/Steps/RegisterRpcModules.cs @@ -113,7 +113,8 @@ public virtual async Task Execute(CancellationToken cancellationToken) _api.SyncModeSelector, _api.BadBlocksStore, _api.FileSystem, - _api.LogManager); + _api.LogManager, + _api.StateReader); rpcModuleProvider.RegisterBoundedByCpuCount(debugModuleFactory, _jsonRpcConfig.Timeout); RegisterTraceRpcModule(rpcModuleProvider); diff --git a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/DebugModuleTests.cs b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/DebugModuleTests.cs index 00faf0cd169..2a47edc552f 100644 --- a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/DebugModuleTests.cs +++ b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/DebugModuleTests.cs @@ -396,6 +396,109 @@ public void Debug_traceCall_test() debugTraceCall.Should().BeEquivalentTo(expected); } + [Test] + public void Debug_traceCallMany_test() + { + GethTxTraceEntry entry = new(); + + entry.Storage = new Dictionary + { + {"1".PadLeft(64, '0'), "2".PadLeft(64, '0')}, + {"3".PadLeft(64, '0'), "4".PadLeft(64, '0')}, + }; + + entry.Memory = new string[] + { + "5".PadLeft(64, '0'), + "6".PadLeft(64, '0') + }; + entry.Stack = new string[] { }; + entry.Opcode = "STOP"; + entry.Gas = 22000; + entry.GasCost = 1; + entry.Depth = 1; + + var traces = new List(); + traces.Add(new GethLikeTxTrace() + { + ReturnValue = Bytes.FromHexString("a2"), + Entries = new List(), + }); + traces[0].Entries.Add(entry); + + + GethTraceOptions gtOptions = new(); + + Transaction transaction = Build.A.Transaction.WithTo(TestItem.AddressA).WithHash(TestItem.KeccakA).TestObject; + TransactionForRpc txForRpc = new(transaction); + TransactionForRpcWithTraceTypes transactionForRpcWithTraceTypes = new(); + transactionForRpcWithTraceTypes.Transaction = txForRpc; + transactionForRpcWithTraceTypes.TraceTypes = new string[1]; + + BlockHeader blockHeader = new BlockHeader( + new Hash256("0x0000000000000000000000000000000000000000000000000000000000000000"), + new Hash256("0x0000000000000000000000000000000000000000000000000000000000000000"), + new Address("0xfffffffffffffffffffffffffffffffffffffffe"), + 1000000, + 123456, + 8000000, + 1694890200, + new byte[] { 0x54, 0x65, 0x73, 0x74, 0x45, 0x78, 0x74, 0x72, 0x61, 0x44, 0x61, 0x74, 0x61 }, + 500000, + 100000, + new Hash256("0x0000000000000000000000000000000000000000000000000000000000000000") + ); + + debugBridge.GetBlockTrace(Arg.Any(), Arg.Any(), Arg.Any()).Returns(traces); + debugBridge.HasStateForBlock(Arg.Any()).Returns(true); + debugBridge.SearchBlockHeaderForTraceCall(Arg.Any()).Returns(new JsonRpc.Modules.SearchResult(blockHeader)); + + DebugRpcModule rpcModule = new(LimboLogs.Instance, debugBridge, jsonRpcConfig, specProvider); + ResultWrapper> debug_traceCallMany_output = rpcModule.debug_traceCallMany(new TransactionForRpcWithTraceTypes[] { transactionForRpcWithTraceTypes }, null); + + + var expected = ResultWrapper>.Success( + new List() + { + new GethLikeTxTrace() + { + Failed = false, + Entries = new List() + { + new GethTxTraceEntry() + { + Gas = 22000, + GasCost = 1, + Depth = 1, + Memory = new string[] + { + "0000000000000000000000000000000000000000000000000000000000000005", + "0000000000000000000000000000000000000000000000000000000000000006" + }, + Opcode = "STOP", + ProgramCounter = 0, + Stack = Array.Empty(), + Storage = new Dictionary() + { + { + "0000000000000000000000000000000000000000000000000000000000000001", + "0000000000000000000000000000000000000000000000000000000000000002" + }, + { + "0000000000000000000000000000000000000000000000000000000000000003", + "0000000000000000000000000000000000000000000000000000000000000004" + }, + } + } + }, + Gas = 0, + ReturnValue = new byte[] { 162 } + } + }); + + debug_traceCallMany_output.Should().BeEquivalentTo(expected); + } + [Test] public async Task Migrate_receipts() { diff --git a/src/Nethermind/Nethermind.JsonRpc/Modules/DebugModule/DebugRpcModule.cs b/src/Nethermind/Nethermind.JsonRpc/Modules/DebugModule/DebugRpcModule.cs index 76028bcfcc0..8e139ee5b3d 100644 --- a/src/Nethermind/Nethermind.JsonRpc/Modules/DebugModule/DebugRpcModule.cs +++ b/src/Nethermind/Nethermind.JsonRpc/Modules/DebugModule/DebugRpcModule.cs @@ -125,7 +125,7 @@ public ResultWrapper> debug_traceCallMany(Transacti return ResultWrapper>.Fail($"Failed to trace block transactions for input txns: {JsonConvert.SerializeObject(calls)}", ErrorCodes.ResourceNotFound); } - if (_logger.IsTrace) _logger.Trace($"{nameof(debug_traceCallMany)} with input transactions: {JsonConvert.SerializeObject(calls)} returned the result: {traces}"); + if (_logger.IsTrace) _logger.Trace($"{nameof(debug_traceCallMany)} with input transactions: {calls} returned the result: {traces}"); return ResultWrapper>.Success(traces); } diff --git a/src/Nethermind/Nethermind.JsonRpc/Modules/DebugModule/IDebugRpcModule.cs b/src/Nethermind/Nethermind.JsonRpc/Modules/DebugModule/IDebugRpcModule.cs index dc0a8bd9014..c834b1442cd 100644 --- a/src/Nethermind/Nethermind.JsonRpc/Modules/DebugModule/IDebugRpcModule.cs +++ b/src/Nethermind/Nethermind.JsonRpc/Modules/DebugModule/IDebugRpcModule.cs @@ -33,6 +33,9 @@ public interface IDebugRpcModule : IRpcModule [JsonRpcMethod(Description = "This method lets you run an eth_call within the context of the given block execution using the final state of parent block as the base. The block can be specified either by hash or by number. It takes the same input object as a eth_call. It returns the same output as debug_traceTransaction.", IsImplemented = true, IsSharable = true)] ResultWrapper debug_traceCall(TransactionForRpc call, BlockParameter? blockParameter = null, GethTraceOptions? options = null); + [JsonRpcMethod(Description = "This method lets you run trace_callMany for a list of transactions.It doesn't charge fees. It returns a list of Trace objects.", IsImplemented = true, IsSharable = true)] + ResultWrapper> debug_traceCallMany(TransactionForRpcWithTraceTypes[] calls, BlockParameter? blockParameter = null); + [JsonRpcMethod(Description = "", IsSharable = true)] ResultWrapper debug_traceTransactionByBlockAndIndex(BlockParameter blockParameter, int txIndex, GethTraceOptions options = null);