Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Accept "latest" and "finalized" as block number values for debug_traceBlockByNumber method #4259

Merged
merged 3 commits into from
Jul 13, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 3 additions & 9 deletions src/Nethermind/Nethermind.Consensus/Tracing/GethStyleTracer.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2021 Demerzel Solutions Limited
// Copyright (c) 2021 Demerzel Solutions Limited
// This file is part of the Nethermind library.
//
// The Nethermind library is free software: you can redistribute it and/or modify
Expand Down Expand Up @@ -122,16 +122,10 @@ public GethLikeTxTrace Trace(Keccak blockHash, int txIndex, GethTraceOptions opt
_processor.Process(block, ProcessingOptions.Trace, blockTracer.WithCancellation(cancellationToken));
return blockTracer.BuildResult().SingleOrDefault();
}

public GethLikeTxTrace[] TraceBlock(Keccak blockHash, GethTraceOptions options, CancellationToken cancellationToken)
public GethLikeTxTrace[] TraceBlock(BlockParameter blockParameter, GethTraceOptions options, CancellationToken cancellationToken)
{
Block block = _blockTree.FindBlock(blockHash, BlockTreeLookupOptions.None);
return TraceBlock(block, options, cancellationToken);
}
var block = _blockTree.FindBlock(blockParameter);

public GethLikeTxTrace[] TraceBlock(long blockNumber, GethTraceOptions options, CancellationToken cancellationToken)
{
Block? block = _blockTree.FindBlock(blockNumber, BlockTreeLookupOptions.RequireCanonical);
return TraceBlock(block, options, cancellationToken);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2021 Demerzel Solutions Limited
// Copyright (c) 2021 Demerzel Solutions Limited
// This file is part of the Nethermind library.
//
// The Nethermind library is free software: you can redistribute it and/or modify
Expand Down Expand Up @@ -31,8 +31,7 @@ public interface IGethStyleTracer
GethLikeTxTrace Trace(Keccak blockHash, int txIndex, GethTraceOptions options, CancellationToken cancellationToken);
GethLikeTxTrace Trace(Rlp blockRlp, Keccak txHash, GethTraceOptions options, CancellationToken cancellationToken);
GethLikeTxTrace? Trace(BlockParameter blockParameter, Transaction tx, GethTraceOptions options, CancellationToken cancellationToken);
GethLikeTxTrace[] TraceBlock(Keccak blockHash, GethTraceOptions options, CancellationToken cancellationToken);
GethLikeTxTrace[] TraceBlock(long blockNumber, GethTraceOptions options, CancellationToken cancellationToken);
GethLikeTxTrace[] TraceBlock(BlockParameter blockParameter, GethTraceOptions options, CancellationToken cancellationToken);
GethLikeTxTrace[] TraceBlock(Rlp blockRlp, GethTraceOptions options, CancellationToken cancellationToken);
}
}
13 changes: 13 additions & 0 deletions src/Nethermind/Nethermind.Core.Test/Builders/TestItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@
// along with the Nethermind. If not, see <http://www.gnu.org/licenses/>.

using System;
using System.IO;
using System.Net;
using System.Text.Json;
using Nethermind.Core.Crypto;
using Nethermind.Crypto;
using Nethermind.Int256;
Expand Down Expand Up @@ -108,6 +110,17 @@ public static Keccak KeccakFromNumber(int i)

public static Bloom NonZeroBloom;

public static T CloneObject<T>(T value)
{
using var stream = new MemoryStream();

JsonSerializer.Serialize(stream, value);

stream.Position = 0;

return JsonSerializer.Deserialize<T>(stream)!;
}

public static Address GetRandomAddress(Random? random = null)
{
byte[] bytes = new byte[20];
Expand Down
155 changes: 144 additions & 11 deletions src/Nethermind/Nethermind.JsonRpc.Test/Modules/DebugModuleTests.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2021 Demerzel Solutions Limited
// Copyright (c) 2021 Demerzel Solutions Limited
// This file is part of the Nethermind library.
//
// The Nethermind library is free software: you can redistribute it and/or modify
Expand All @@ -15,6 +15,7 @@
// along with the Nethermind. If not, see <http://www.gnu.org/licenses/>.

using System.Collections.Generic;
using System.Linq;
using System.Threading;
using FluentAssertions;
using Nethermind.Blockchain.Find;
Expand All @@ -28,7 +29,6 @@
using Nethermind.JsonRpc.Modules.DebugModule;
using Nethermind.Logging;
using Nethermind.Serialization.Rlp;
using Newtonsoft.Json;
using NSubstitute;
using NUnit.Framework;

Expand All @@ -44,8 +44,8 @@ public class DebugModuleTests
[Test]
public void Get_from_db()
{
byte[] key = new byte[] {1, 2, 3};
byte[] value = new byte[] {4, 5, 6};
byte[] key = new byte[] { 1, 2, 3 };
byte[] value = new byte[] { 4, 5, 6 };
debugBridge.GetDbValue(Arg.Any<string>(), Arg.Any<byte[]>()).Returns(value);

IConfigProvider configProvider = Substitute.For<IConfigProvider>();
Expand All @@ -58,8 +58,8 @@ public void Get_from_db()
[Test]
public void Get_from_db_null_value()
{
byte[] key = new byte[] {1, 2, 3};
debugBridge.GetDbValue(Arg.Any<string>(), Arg.Any<byte[]>()).Returns((byte[]) null);
byte[] key = new byte[] { 1, 2, 3 };
debugBridge.GetDbValue(Arg.Any<string>(), Arg.Any<byte[]>()).Returns((byte[])null);

IConfigProvider configProvider = Substitute.For<IConfigProvider>();
DebugRpcModule rpcModule = new(LimboLogs.Instance, debugBridge, jsonRpcConfig);
Expand Down Expand Up @@ -98,7 +98,7 @@ public void Get_block_rlp_by_hash()

DebugRpcModule rpcModule = new(LimboLogs.Instance, debugBridge, jsonRpcConfig);
JsonRpcSuccessResponse response = RpcTest.TestRequest<IDebugRpcModule>(rpcModule, "debug_getBlockRlpByHash", $"{Keccak.Zero.Bytes.ToHexString()}") as JsonRpcSuccessResponse;
Assert.AreEqual(rlp.Bytes, (byte[]) response?.Result);
Assert.AreEqual(rlp.Bytes, (byte[])response?.Result);
}

[Test]
Expand All @@ -112,13 +112,13 @@ public void Get_block_rlp()
DebugRpcModule rpcModule = new(LimboLogs.Instance, debugBridge, jsonRpcConfig);
JsonRpcSuccessResponse response = RpcTest.TestRequest<IDebugRpcModule>(rpcModule, "debug_getBlockRlp", "1") as JsonRpcSuccessResponse;

Assert.AreEqual(rlp.Bytes, (byte[]) response?.Result);
Assert.AreEqual(rlp.Bytes, (byte[])response?.Result);
}

[Test]
public void Get_block_rlp_when_missing()
{
debugBridge.GetBlockRlp(1).Returns((byte[]) null);
debugBridge.GetBlockRlp(1).Returns((byte[])null);

DebugRpcModule rpcModule = new(LimboLogs.Instance, debugBridge, jsonRpcConfig);
JsonRpcErrorResponse response = RpcTest.TestRequest<IDebugRpcModule>(rpcModule, "debug_getBlockRlp", "1") as JsonRpcErrorResponse;
Expand All @@ -131,7 +131,7 @@ public void Get_block_rlp_by_hash_when_missing()
{
BlockDecoder decoder = new();
Rlp rlp = decoder.Encode(Build.A.Block.WithNumber(1).TestObject);
debugBridge.GetBlockRlp(Keccak.Zero).Returns((byte[]) null);
debugBridge.GetBlockRlp(Keccak.Zero).Returns((byte[])null);

DebugRpcModule rpcModule = new(LimboLogs.Instance, debugBridge, jsonRpcConfig);
JsonRpcErrorResponse response = RpcTest.TestRequest<IDebugRpcModule>(rpcModule, "debug_getBlockRlpByHash", $"{Keccak.Zero.Bytes.ToHexString()}") as JsonRpcErrorResponse;
Expand Down Expand Up @@ -219,7 +219,7 @@ public void Get_trace_with_options()
public void Debug_traceCall_test()
{
GethTxTraceEntry entry = new();

entry.Storage = new Dictionary<string, string>
{
{"1".PadLeft(64, '0'), "2".PadLeft(64, '0')},
Expand Down Expand Up @@ -308,5 +308,138 @@ public void Update_head_block()
RpcTest.TestSerializedRequest(rpcModule, "debug_resetHead", TestItem.KeccakA.ToString());
debugBridge.Received().UpdateHeadBlock(TestItem.KeccakA);
}

[Test]
public void TraceBlock_Success()
{
var traces = Enumerable.Repeat(MockGethLikeTrace(), 2).ToArray();
var tracesClone = TestItem.CloneObject(traces);
var blockRlp = new Rlp(TestItem.RandomDataA);

debugBridge
.GetBlockTrace(blockRlp, Arg.Any<CancellationToken>(), Arg.Any<GethTraceOptions>())
.Returns(traces);

var rpcModule = new DebugRpcModule(LimboLogs.Instance, debugBridge, jsonRpcConfig);
var actual = rpcModule.debug_traceBlock(blockRlp.Bytes);
var expected = ResultWrapper<GethLikeTxTrace[]>.Success(tracesClone);

actual.Should().BeEquivalentTo(expected);
}

[Test]
public void TraceBlock_Fail()
{
var blockRlp = new Rlp(TestItem.RandomDataA);

debugBridge
.GetBlockTrace(blockRlp, Arg.Any<CancellationToken>(), Arg.Any<GethTraceOptions>())
.Returns(default(GethLikeTxTrace[]));

var rpcModule = new DebugRpcModule(LimboLogs.Instance, debugBridge, jsonRpcConfig);
var actual = rpcModule.debug_traceBlock(blockRlp.Bytes);
var expected = ResultWrapper<GethLikeTxTrace[]>.Fail($"Trace is null for RLP {blockRlp.Bytes.ToHexString()}", ErrorCodes.ResourceNotFound);

actual.Should().BeEquivalentTo(expected);
}

[Test]
public void TraceBlockByHash_Success()
{
var traces = Enumerable.Repeat(MockGethLikeTrace(), 2).ToArray();
var tracesClone = TestItem.CloneObject(traces);
var blockHash = TestItem.KeccakA;

debugBridge
.GetBlockTrace(new BlockParameter(blockHash), Arg.Any<CancellationToken>(), Arg.Any<GethTraceOptions>())
.Returns(traces);

var rpcModule = new DebugRpcModule(LimboLogs.Instance, debugBridge, jsonRpcConfig);
var actual = rpcModule.debug_traceBlockByHash(blockHash);
var expected = ResultWrapper<GethLikeTxTrace[]>.Success(tracesClone);

actual.Should().BeEquivalentTo(expected);
}

[Test]
public void TraceBlockByHash_Fail()
{
var blockHash = TestItem.KeccakA;

debugBridge
.GetBlockTrace(new BlockParameter(blockHash), Arg.Any<CancellationToken>(), Arg.Any<GethTraceOptions>())
.Returns(default(GethLikeTxTrace[]));

var rpcModule = new DebugRpcModule(LimboLogs.Instance, debugBridge, jsonRpcConfig);
var actual = rpcModule.debug_traceBlockByHash(blockHash);
var expected = ResultWrapper<GethLikeTxTrace[]>.Fail($"Trace is null for block {blockHash}", ErrorCodes.ResourceNotFound);

actual.Should().BeEquivalentTo(expected);
}

[Test]
public void TraceBlockByNumber_Success()
{
var traces = Enumerable.Repeat(MockGethLikeTrace(), 2).ToArray();
var tracesClone = TestItem.CloneObject(traces);
var blockNumber = BlockParameter.Latest;

debugBridge
.GetBlockTrace(blockNumber, Arg.Any<CancellationToken>(), Arg.Any<GethTraceOptions>())
.Returns(traces);

var rpcModule = new DebugRpcModule(LimboLogs.Instance, debugBridge, jsonRpcConfig);
var actual = rpcModule.debug_traceBlockByNumber(blockNumber);
var expected = ResultWrapper<GethLikeTxTrace[]>.Success(tracesClone);

actual.Should().BeEquivalentTo(expected);
}

[Test]
public void TraceBlockByNumber_Fail()
{
var blockNumber = BlockParameter.Latest;

debugBridge
.GetBlockTrace(blockNumber, Arg.Any<CancellationToken>(), Arg.Any<GethTraceOptions>())
.Returns(default(GethLikeTxTrace[]));

var rpcModule = new DebugRpcModule(LimboLogs.Instance, debugBridge, jsonRpcConfig);
var actual = rpcModule.debug_traceBlockByNumber(blockNumber);
var expected = ResultWrapper<GethLikeTxTrace[]>.Fail($"Trace is null for block {blockNumber}", ErrorCodes.ResourceNotFound);

actual.Should().BeEquivalentTo(expected);
}

private static GethLikeTxTrace MockGethLikeTrace()
{
var trace = new GethLikeTxTrace { ReturnValue = new byte[] { 0xA2 } };

trace.Entries.Add(new GethTxTraceEntry
{
Depth = 1,
Gas = 22000,
GasCost = 1,
Memory = new List<string>
{
"5".PadLeft(64, '0'),
"6".PadLeft(64, '0')
},
Operation = "STOP",
Pc = 32,
Stack = new List<string>
{
"7".PadLeft(64, '0'),
"8".PadLeft(64, '0')
},
Storage = new Dictionary<string, string>
{
{"1".PadLeft(64, '0'), "2".PadLeft(64, '0')},
{"3".PadLeft(64, '0'), "4".PadLeft(64, '0')},
}
});

return trace;
}
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2021 Demerzel Solutions Limited
// Copyright (c) 2021 Demerzel Solutions Limited
// This file is part of the Nethermind library.
//
// The Nethermind library is free software: you can redistribute it and/or modify
Expand Down Expand Up @@ -147,14 +147,9 @@ public GethLikeTxTrace GetTransactionTrace(Rlp blockRlp, Keccak transactionHash,
return _tracer.Trace(blockParameter, transaction, gethTraceOptions ?? GethTraceOptions.Default, cancellationToken);
}

public GethLikeTxTrace[] GetBlockTrace(Keccak blockHash,CancellationToken cancellationToken, GethTraceOptions gethTraceOptions = null)
public GethLikeTxTrace[] GetBlockTrace(BlockParameter blockParameter, CancellationToken cancellationToken, GethTraceOptions gethTraceOptions = null)
{
return _tracer.TraceBlock(blockHash, gethTraceOptions ?? GethTraceOptions.Default, cancellationToken);
}

public GethLikeTxTrace[] GetBlockTrace(long blockNumber, CancellationToken cancellationToken, GethTraceOptions gethTraceOptions = null)
{
return _tracer.TraceBlock(blockNumber, gethTraceOptions ?? GethTraceOptions.Default, cancellationToken);
return _tracer.TraceBlock(blockParameter, gethTraceOptions ?? GethTraceOptions.Default, cancellationToken);
}

public GethLikeTxTrace[] GetBlockTrace(Rlp blockRlp, CancellationToken cancellationToken,GethTraceOptions gethTraceOptions = null)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2021 Demerzel Solutions Limited
// Copyright (c) 2021 Demerzel Solutions Limited
// This file is part of the Nethermind library.
//
// The Nethermind library is free software: you can redistribute it and/or modify
Expand Down Expand Up @@ -163,43 +163,44 @@ public Task<ResultWrapper<bool>> debug_insertReceipts(BlockParameter blockParame

public ResultWrapper<GethLikeTxTrace[]> debug_traceBlock(byte[] blockRlp, GethTraceOptions options = null)
{
using CancellationTokenSource cancellationTokenSource = new(_traceTimeout);
CancellationToken cancellationToken = cancellationTokenSource.Token;
using var cancellationTokenSource = new CancellationTokenSource(_traceTimeout);
var cancellationToken = cancellationTokenSource.Token;
var blockTrace = _debugBridge.GetBlockTrace(new Rlp(blockRlp), cancellationToken, options);

if (blockTrace == null)
{
return ResultWrapper<GethLikeTxTrace[]>.Fail($"Trace is null for RLP {blockRlp.ToHexString()}", ErrorCodes.ResourceNotFound);
}

if (_logger.IsTrace) _logger.Trace($"{nameof(debug_traceBlock)} request {blockRlp.ToHexString()}, result: {blockTrace}");

return ResultWrapper<GethLikeTxTrace[]>.Success(blockTrace);
}

public ResultWrapper<GethLikeTxTrace[]> debug_traceBlockByNumber(UInt256 blockNumber, GethTraceOptions options = null)
public ResultWrapper<GethLikeTxTrace[]> debug_traceBlockByNumber(BlockParameter blockNumber, GethTraceOptions options = null)
{
using CancellationTokenSource cancellationTokenSource = new(_traceTimeout);
CancellationToken cancellationToken = cancellationTokenSource.Token;
var blockTrace = _debugBridge.GetBlockTrace((long)blockNumber, cancellationToken, options);
using var cancellationTokenSource = new CancellationTokenSource(_traceTimeout);
var cancellationToken = cancellationTokenSource.Token;
var blockTrace = _debugBridge.GetBlockTrace(blockNumber, cancellationToken, options);

if (blockTrace == null)
{
return ResultWrapper<GethLikeTxTrace[]>.Fail($"Trace is null for block {blockNumber}", ErrorCodes.ResourceNotFound);
}

if (_logger.IsTrace) _logger.Trace($"{nameof(debug_traceBlockByNumber)} request {blockNumber}, result: blockTrace");
if (_logger.IsTrace) _logger.Trace($"{nameof(debug_traceBlockByNumber)} request {blockNumber}, result: {blockTrace}");

return ResultWrapper<GethLikeTxTrace[]>.Success(blockTrace);
}

public ResultWrapper<GethLikeTxTrace[]> debug_traceBlockByHash(Keccak blockHash, GethTraceOptions options = null)
{
using CancellationTokenSource cancellationTokenSource = new(_traceTimeout);
CancellationToken cancellationToken = cancellationTokenSource.Token;
GethLikeTxTrace[] gethLikeBlockTrace = _debugBridge.GetBlockTrace(blockHash, cancellationToken, options);
if (gethLikeBlockTrace == null)
{
using var cancellationTokenSource = new CancellationTokenSource(_traceTimeout);
var cancellationToken = cancellationTokenSource.Token;
var blockTrace = _debugBridge.GetBlockTrace(new BlockParameter(blockHash), cancellationToken, options);

if (blockTrace == null)
return ResultWrapper<GethLikeTxTrace[]>.Fail($"Trace is null for block {blockHash}", ErrorCodes.ResourceNotFound);
}

if (_logger.IsTrace) _logger.Trace($"{nameof(debug_traceBlockByHash)} request {blockHash}, result: blockTrace");
return ResultWrapper<GethLikeTxTrace[]>.Success(gethLikeBlockTrace);
if (_logger.IsTrace) _logger.Trace($"{nameof(debug_traceBlockByHash)} request {blockHash}, result: {blockTrace}");

return ResultWrapper<GethLikeTxTrace[]>.Success(blockTrace);
}

public ResultWrapper<GethLikeTxTrace[]> debug_traceBlockFromFile(string fileName, GethTraceOptions options = null)
Expand Down
Loading