diff --git a/.github/workflows/run-nethermind-tests-with-code-coverage.yml b/.github/workflows/run-nethermind-tests-with-code-coverage.yml
index 7cabadcc3ce..caa37594451 100644
--- a/.github/workflows/run-nethermind-tests-with-code-coverage.yml
+++ b/.github/workflows/run-nethermind-tests-with-code-coverage.yml
@@ -175,6 +175,9 @@ jobs:
- name: Nethermind.Sockets.Test
run: |
dotnet test -c Release $EXCLUDE_TEST_PROJECTS src/Nethermind/Nethermind.Sockets.Test
+ - name: Nethermind.JsonRpc.TraceStore.Tests
+ run: |
+ dotnet test -c Release $EXCLUDE_TEST_PROJECTS src/Nethermind/Nethermind.JsonRpc.TraceStore.Tests
- name: Upload Codecov Report
if: matrix.os == 'ubuntu-latest'
uses: actions/upload-artifact@v2
diff --git a/.github/workflows/run-nethermind-tests.yml b/.github/workflows/run-nethermind-tests.yml
index fee65bf10eb..536758697da 100644
--- a/.github/workflows/run-nethermind-tests.yml
+++ b/.github/workflows/run-nethermind-tests.yml
@@ -45,6 +45,9 @@ jobs:
- name: Nethermind.AccountAbstraction.Test
run: |
dotnet test src/Nethermind/Nethermind.AccountAbstraction.Test -c ${{ env.BUILD_CONFIG }}
+ - name: Nethermind.JsonRpc.TraceStore.Tests
+ run: |
+ dotnet test src/Nethermind/Nethermind.JsonRpc.TraceStore.Tests -c ${{ env.BUILD_CONFIG }}
neth-tests2:
name: Running Nethermind Tests 2
diff --git a/scripts/deployment/archive-packages.sh b/scripts/deployment/archive-packages.sh
index 86ac4ee6789..08a5479df4d 100755
--- a/scripts/deployment/archive-packages.sh
+++ b/scripts/deployment/archive-packages.sh
@@ -35,11 +35,11 @@ dotnet build -c release Nethermind.Runner.csproj
cd $RELEASE_DIRECTORY
-cp $RELEASE_DIRECTORY/$RELEASE_PATH/Nethermind.{Api,HealthChecks,EthStats,Merge.Plugin,Mev}.dll $LIN_RELEASE/plugins
-cp $RELEASE_DIRECTORY/$RELEASE_PATH/Nethermind.{Api,HealthChecks,EthStats,Merge.Plugin,Mev}.dll $OSX_RELEASE/plugins
-cp $RELEASE_DIRECTORY/$RELEASE_PATH/Nethermind.{Api,HealthChecks,EthStats,Merge.Plugin,Mev}.dll $WIN_RELEASE/plugins
-cp $RELEASE_DIRECTORY/$RELEASE_PATH/Nethermind.{Api,HealthChecks,EthStats,Merge.Plugin,Mev}.dll $LIN_ARM64_RELEASE/plugins
-cp $RELEASE_DIRECTORY/$RELEASE_PATH/Nethermind.{Api,HealthChecks,EthStats,Merge.Plugin,Mev}.dll $OSX_ARM64_RELEASE/plugins
+cp $RELEASE_DIRECTORY/$RELEASE_PATH/Nethermind.{Api,HealthChecks,EthStats,Merge.Plugin,Mev,JsonRpc.TraceStore}.dll $LIN_RELEASE/plugins
+cp $RELEASE_DIRECTORY/$RELEASE_PATH/Nethermind.{Api,HealthChecks,EthStats,Merge.Plugin,Mev,JsonRpc.TraceStore}.dll $OSX_RELEASE/plugins
+cp $RELEASE_DIRECTORY/$RELEASE_PATH/Nethermind.{Api,HealthChecks,EthStats,Merge.Plugin,Mev,JsonRpc.TraceStore}.dll $WIN_RELEASE/plugins
+cp $RELEASE_DIRECTORY/$RELEASE_PATH/Nethermind.{Api,HealthChecks,EthStats,Merge.Plugin,Mev,JsonRpc.TraceStore}.dll $LIN_ARM64_RELEASE/plugins
+cp $RELEASE_DIRECTORY/$RELEASE_PATH/Nethermind.{Api,HealthChecks,EthStats,Merge.Plugin,Mev,JsonRpc.TraceStore}.dll $OSX_ARM64_RELEASE/plugins
cd $LIN_RELEASE && zip -r $LIN-$VERSION-$COMMIT_HASH-$DATE.zip . && cd ..
cd $OSX_RELEASE && zip -r $OSX-$VERSION-$COMMIT_HASH-$DATE.zip . && cd ..
diff --git a/src/Nethermind/Directory.Build.props b/src/Nethermind/Directory.Build.props
index 9eae93a3e38..2f48d62cfa1 100644
--- a/src/Nethermind/Directory.Build.props
+++ b/src/Nethermind/Directory.Build.props
@@ -11,7 +11,7 @@
Demerzel Solutions Limited
Nethermind
$(Commit.Substring(0, 8))
- 1.14.6
+ 1.14.7
diff --git a/src/Nethermind/Nethermind.Consensus/BlocksConfig.cs b/src/Nethermind/Nethermind.Consensus/BlocksConfig.cs
index 0a35c9330b3..74ccd6aefe1 100644
--- a/src/Nethermind/Nethermind.Consensus/BlocksConfig.cs
+++ b/src/Nethermind/Nethermind.Consensus/BlocksConfig.cs
@@ -1,19 +1,5 @@
-// 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
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The Nethermind library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the Nethermind. If not, see .
-//
+// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited
+// SPDX-License-Identifier: LGPL-3.0-only
using System;
using System.Reflection;
diff --git a/src/Nethermind/Nethermind.Consensus/IBlocksConfig.cs b/src/Nethermind/Nethermind.Consensus/IBlocksConfig.cs
index 126c39cf714..883979611c7 100644
--- a/src/Nethermind/Nethermind.Consensus/IBlocksConfig.cs
+++ b/src/Nethermind/Nethermind.Consensus/IBlocksConfig.cs
@@ -1,18 +1,5 @@
-// 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
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The Nethermind library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the Nethermind. If not, see .
+// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited
+// SPDX-License-Identifier: LGPL-3.0-only
using System.Collections.Generic;
using System.Reflection;
diff --git a/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs b/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs
index 7e15499e59a..b7ecf989966 100644
--- a/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs
+++ b/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs
@@ -223,10 +223,10 @@ protected virtual TxReceipt[] ProcessBlock(
_receiptsTracer.SetOtherTracer(blockTracer);
_receiptsTracer.StartNewBlockTrace(block);
TxReceipt[] receipts = _blockTransactionsExecutor.ProcessTransactions(block, options, _receiptsTracer, spec);
- _receiptsTracer.EndBlockTrace();
block.Header.ReceiptsRoot = receipts.GetReceiptsRoot(spec, block.ReceiptsRoot);
ApplyMinerRewards(block, blockTracer, spec);
+ _receiptsTracer.EndBlockTrace();
_stateProvider.Commit(spec);
_stateProvider.RecalculateStateRoot();
diff --git a/src/Nethermind/Nethermind.Consensus/Processing/BlockRef.cs b/src/Nethermind/Nethermind.Consensus/Processing/BlockRef.cs
index 45a1a5915d7..d36ada35785 100644
--- a/src/Nethermind/Nethermind.Consensus/Processing/BlockRef.cs
+++ b/src/Nethermind/Nethermind.Consensus/Processing/BlockRef.cs
@@ -46,5 +46,7 @@ public bool Resolve(IBlockTree blockTree)
return true;
}
+
+ public override string ToString() => Block?.ToString() ?? BlockHash.ToString();
}
}
diff --git a/src/Nethermind/Nethermind.Core.Test/Collections/ArrayPoolListTests.cs b/src/Nethermind/Nethermind.Core.Test/Collections/ArrayPoolListTests.cs
index 21489c39657..239fd3ba7b2 100644
--- a/src/Nethermind/Nethermind.Core.Test/Collections/ArrayPoolListTests.cs
+++ b/src/Nethermind/Nethermind.Core.Test/Collections/ArrayPoolListTests.cs
@@ -175,5 +175,18 @@ public void Set_should_throw(int item)
Action action = () => list[item] = 1;
action.Should().Throw();
}
+
+ [TestCase(1, 16)]
+ [TestCase(14, 16)]
+ [TestCase(15, 32)]
+ [TestCase(20, 32)]
+ [TestCase(100, 128)]
+ public void AddRange_should_expand(int items, int expectedCapacity)
+ {
+ ArrayPoolList list = new(16) { 0, 1 };
+ list.AddRange(Enumerable.Range(2, items));
+ list.Should().BeEquivalentTo(Enumerable.Range(0, items + 2));
+ list.Capacity.Should().Be(expectedCapacity);
+ }
}
}
diff --git a/src/Nethermind/Nethermind.Core/BlockInfo.cs b/src/Nethermind/Nethermind.Core/BlockInfo.cs
index 27f4aeebd60..52fc8f7e8ff 100644
--- a/src/Nethermind/Nethermind.Core/BlockInfo.cs
+++ b/src/Nethermind/Nethermind.Core/BlockInfo.cs
@@ -76,5 +76,7 @@ public bool IsBeaconInfo
/// This property is not serialized
///
public long BlockNumber { get; set; }
+
+ public override string ToString() => BlockHash.ToString();
}
}
diff --git a/src/Nethermind/Nethermind.Core/Collections/ArrayPoolList.cs b/src/Nethermind/Nethermind.Core/Collections/ArrayPoolList.cs
index 4e870523ae2..e5292e4386e 100644
--- a/src/Nethermind/Nethermind.Core/Collections/ArrayPoolList.cs
+++ b/src/Nethermind/Nethermind.Core/Collections/ArrayPoolList.cs
@@ -7,15 +7,13 @@
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Threading;
-using System.Threading.Tasks;
-using Nethermind.Core.Crypto;
namespace Nethermind.Core.Collections
{
public class ArrayPoolList : IList, IReadOnlyList, IDisposable
{
private readonly ArrayPool _arrayPool;
- private T[] _array;
+ protected T[] _array;
private int _count = 0;
private int _capacity;
private bool _disposed;
@@ -60,6 +58,13 @@ public void Add(T item)
_array[_count++] = item;
}
+ public void AddRange(Span items)
+ {
+ GuardResize(items.Length);
+ items.CopyTo(_array.AsSpan(_count, items.Length));
+ _count += items.Length;
+ }
+
public void Clear()
{
_count = 0;
@@ -100,12 +105,17 @@ public void Insert(int index, T item)
_count++;
}
- private void GuardResize()
+ private void GuardResize(int itemsToAdd = 1)
{
GuardDispose();
- if (_count == _capacity)
+ int newCount = _count + itemsToAdd;
+ if (newCount > _capacity)
{
int newCapacity = _capacity * 2;
+ while (newCount > newCapacity)
+ {
+ newCapacity *= 2;
+ }
T[] newArray = _arrayPool.Rent(newCapacity);
_array.CopyTo(newArray, 0);
T[] oldArray = Interlocked.Exchange(ref _array, newArray);
@@ -198,5 +208,7 @@ public void Dispose()
_disposed = true;
}
}
+
+ public Span AsSpan() => _array.AsSpan(0, _count);
}
}
diff --git a/src/Nethermind/Nethermind.Core/Collections/ByteArrayPoolList.cs b/src/Nethermind/Nethermind.Core/Collections/ByteArrayPoolList.cs
new file mode 100644
index 00000000000..e29a61473e5
--- /dev/null
+++ b/src/Nethermind/Nethermind.Core/Collections/ByteArrayPoolList.cs
@@ -0,0 +1,25 @@
+// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited
+// SPDX-License-Identifier: LGPL-3.0-only
+
+using System.Buffers;
+using System.Collections.Generic;
+using System.IO;
+
+namespace Nethermind.Core.Collections;
+
+public class ByteArrayPoolList : ArrayPoolList
+{
+ public ByteArrayPoolList(int capacity) : base(capacity)
+ {
+ }
+
+ public ByteArrayPoolList(int capacity, IEnumerable enumerable) : base(capacity, enumerable)
+ {
+ }
+
+ public ByteArrayPoolList(ArrayPool arrayPool, int capacity) : base(arrayPool, capacity)
+ {
+ }
+
+ public MemoryStream AsMemoryStream() => new(_array, 0, Count);
+}
diff --git a/src/Nethermind/Nethermind.Core/Extensions/Bytes.cs b/src/Nethermind/Nethermind.Core/Extensions/Bytes.cs
index 08423bc5d8a..1ea0d825f7e 100644
--- a/src/Nethermind/Nethermind.Core/Extensions/Bytes.cs
+++ b/src/Nethermind/Nethermind.Core/Extensions/Bytes.cs
@@ -504,20 +504,8 @@ public static void StreamHex(this byte[] bytes, StreamWriter streamWriter)
}
}
- public static string ToHexString(this byte[] bytes, bool withZeroX)
- {
- return ToHexString(bytes, withZeroX, false, false);
- }
-
- public static string ToHexString(this byte[] bytes, bool withZeroX, bool noLeadingZeros)
- {
- return ToHexString(bytes, withZeroX, noLeadingZeros, false);
- }
-
- public static string ToHexString(this byte[] bytes, bool withZeroX, bool noLeadingZeros, bool withEip55Checksum)
- {
- return ByteArrayToHexViaLookup32(bytes, withZeroX, noLeadingZeros, withEip55Checksum);
- }
+ public static string ToHexString(this byte[] bytes, bool withZeroX, bool noLeadingZeros = false, bool withEip55Checksum = false) =>
+ ByteArrayToHexViaLookup32(bytes, withZeroX, noLeadingZeros, withEip55Checksum);
private struct StateSmall
{
diff --git a/src/Nethermind/Nethermind.Core/Resettables/ResettableList.cs b/src/Nethermind/Nethermind.Core/Resettables/ResettableList.cs
index 404a827b2ca..fbadec7b090 100644
--- a/src/Nethermind/Nethermind.Core/Resettables/ResettableList.cs
+++ b/src/Nethermind/Nethermind.Core/Resettables/ResettableList.cs
@@ -7,9 +7,9 @@
namespace Nethermind.Core.Resettables;
-public class ResettableList : IList
+public class ResettableList : IList, IReadOnlyCollection
{
- private List _wrapped;
+ private readonly List _wrapped;
private readonly int _startCapacity;
private readonly int _resetRatio;
private int _currentCapacity;
diff --git a/src/Nethermind/Nethermind.Db.Rocks/DbOnTheRocks.cs b/src/Nethermind/Nethermind.Db.Rocks/DbOnTheRocks.cs
index 06537770272..8cfb5cba3f5 100644
--- a/src/Nethermind/Nethermind.Db.Rocks/DbOnTheRocks.cs
+++ b/src/Nethermind/Nethermind.Db.Rocks/DbOnTheRocks.cs
@@ -196,9 +196,11 @@ protected internal void UpdateWriteMetrics()
propertyName);
try
{
- return (T?)dbConfig.GetType()
- .GetProperty(prefixed, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance)?
- .GetValue(dbConfig);
+ Type type = dbConfig.GetType();
+ PropertyInfo? propertyInfo = type.GetProperty(prefixed, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
+ // if no custom db property default to generic one
+ propertyInfo ??= type.GetProperty(propertyName, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
+ return (T?)propertyInfo?.GetValue(dbConfig);
}
catch (Exception e)
{
diff --git a/src/Nethermind/Nethermind.Db/RocksDbInitializer.cs b/src/Nethermind/Nethermind.Db/RocksDbInitializer.cs
index 359446ded33..e9a659c7a4d 100644
--- a/src/Nethermind/Nethermind.Db/RocksDbInitializer.cs
+++ b/src/Nethermind/Nethermind.Db/RocksDbInitializer.cs
@@ -68,9 +68,6 @@ protected async Task InitAllAsync()
await Task.WhenAll(allInitializers);
}
- protected static string GetTitleDbName(string dbName)
- {
- return char.ToUpper(dbName[0]) + dbName.Substring(1);
- }
+ protected static string GetTitleDbName(string dbName) => char.ToUpper(dbName[0]) + dbName.Substring(1);
}
}
diff --git a/src/Nethermind/Nethermind.Evm/Tracing/BlockTracerBase.cs b/src/Nethermind/Nethermind.Evm/Tracing/BlockTracerBase.cs
index e240f6c6033..34a74ca56d4 100644
--- a/src/Nethermind/Nethermind.Evm/Tracing/BlockTracerBase.cs
+++ b/src/Nethermind/Nethermind.Evm/Tracing/BlockTracerBase.cs
@@ -4,6 +4,7 @@
using System.Collections.Generic;
using Nethermind.Core;
using Nethermind.Core.Crypto;
+using Nethermind.Core.Resettables;
using Nethermind.Int256;
namespace Nethermind.Evm.Tracing
@@ -16,13 +17,13 @@ public abstract class BlockTracerBase : IBlockTracer where TTra
protected BlockTracerBase()
{
- TxTraces = new List();
+ TxTraces = new ResettableList();
}
protected BlockTracerBase(Keccak? txHash)
{
_txHash = txHash;
- TxTraces = new List();
+ TxTraces = new ResettableList();
}
private TTracer? CurrentTxTracer { get; set; }
@@ -36,7 +37,10 @@ public virtual void ReportReward(Address author, string rewardType, UInt256 rewa
{
}
- public abstract void StartNewBlockTrace(Block block);
+ public virtual void StartNewBlockTrace(Block block)
+ {
+ TxTraces.Reset();
+ }
ITxTracer IBlockTracer.StartNewTxTrace(Transaction? tx)
{
@@ -58,18 +62,15 @@ void IBlockTracer.EndTxTrace()
}
}
- public abstract void EndBlockTrace();
+ public virtual void EndBlockTrace() { }
protected virtual bool ShouldTraceTx(Transaction? tx)
{
return IsTracingEntireBlock || tx?.Hash == _txHash;
}
- protected List TxTraces { get; }
+ protected ResettableList TxTraces { get; }
- public IReadOnlyCollection BuildResult()
- {
- return TxTraces;
- }
+ public IReadOnlyCollection BuildResult() => TxTraces;
}
}
diff --git a/src/Nethermind/Nethermind.Evm/Tracing/GethStyle/GethLikeBlockTracer.cs b/src/Nethermind/Nethermind.Evm/Tracing/GethStyle/GethLikeBlockTracer.cs
index b3534128577..4dd03ca6f5e 100644
--- a/src/Nethermind/Nethermind.Evm/Tracing/GethStyle/GethLikeBlockTracer.cs
+++ b/src/Nethermind/Nethermind.Evm/Tracing/GethStyle/GethLikeBlockTracer.cs
@@ -24,13 +24,5 @@ public GethLikeBlockTracer(Keccak txHash, GethTraceOptions options)
protected override GethLikeTxTracer OnStart(Transaction? tx) => new(_options);
protected override GethLikeTxTrace OnEnd(GethLikeTxTracer txTracer) => txTracer.BuildResult();
-
- public override void StartNewBlockTrace(Block block)
- {
- }
-
- public override void EndBlockTrace()
- {
- }
}
}
diff --git a/src/Nethermind/Nethermind.Evm/Tracing/IBlockTracer.cs b/src/Nethermind/Nethermind.Evm/Tracing/IBlockTracer.cs
index 360332c64e7..9e9aad8b2e9 100644
--- a/src/Nethermind/Nethermind.Evm/Tracing/IBlockTracer.cs
+++ b/src/Nethermind/Nethermind.Evm/Tracing/IBlockTracer.cs
@@ -15,16 +15,45 @@ namespace Nethermind.Evm.Tracing
///
public interface IBlockTracer
{
+ ///
+ /// Is reward state change traced
+ ///
+ ///
+ /// Controls
+ /// -
+ ///
bool IsTracingRewards { get; }
+ ///
+ /// Reports rewards for bock.
+ ///
+ /// Author/coinbase for reward.
+ /// Type of reward.
+ /// Value of reward.
+ /// Depends on
void ReportReward(Address author, string rewardType, UInt256 rewardValue);
+ ///
+ /// Starts a trace for new block.
+ ///
+ /// Block to be traced.
void StartNewBlockTrace(Block block);
+ ///
+ /// Starts new transaction trace in a block.
+ ///
+ /// Transaction this trace is started for. Null if it's reward trace.
+ /// Returns tracer for transaction.
ITxTracer StartNewTxTrace(Transaction? tx);
+ ///
+ /// Ends last transaction trace .
+ ///
void EndTxTrace();
+ ///
+ /// Ends block trace .
+ ///
void EndBlockTrace();
}
}
diff --git a/src/Nethermind/Nethermind.Evm/Tracing/ITxTracer.cs b/src/Nethermind/Nethermind.Evm/Tracing/ITxTracer.cs
index e6bc2a03ee3..f6400a3a87b 100644
--- a/src/Nethermind/Nethermind.Evm/Tracing/ITxTracer.cs
+++ b/src/Nethermind/Nethermind.Evm/Tracing/ITxTracer.cs
@@ -16,83 +16,234 @@ public interface ITxTracer : IStateTracer, IStorageTracer
///
/// Defines whether MarkAsSuccess or MarkAsFailed will be called
///
+ ///
+ /// Controls
+ /// -
+ /// -
+ ///
bool IsTracingReceipt { get; }
+
///
/// High level calls with information on the target account
///
+ ///
+ /// Controls
+ /// -
+ /// -
+ /// -
+ /// -
+ ///
bool IsTracingActions { get; }
+
///
/// SSTORE and SLOAD level storage operations
///
+ ///
+ /// Controls
+ /// -
+ /// -
+ /// -
+ /// -
+ ///
bool IsTracingOpLevelStorage { get; }
+
///
/// EVM memory access operations
///
+ ///
+ /// Controls
+ /// -
+ /// -
+ ///
bool IsTracingMemory { get; }
+
+ ///
+ /// EVM instructions
+ ///
+ ///
+ /// Controls
+ /// -
+ /// -
+ /// -
+ /// -
+ /// -
+ /// -
+ ///
bool IsTracingInstructions { get; }
+
///
/// Updates of refund counter
///
+ ///
+ /// Controls
+ /// -
+ /// -
+ ///
bool IsTracingRefunds { get; }
+
///
/// Code deployment
///
+ ///
+ /// Controls
+ /// -
+ ///
bool IsTracingCode { get; }
+
///
/// EVM stack tracing after each operation
///
+ ///
+ /// Controls
+ /// -
+ ///
bool IsTracingStack { get; }
///
/// Traces blockhash calls
///
+ ///
+ /// Controls
+ /// -
+ ///
bool IsTracingBlockHash { get; }
///
/// Traces storage access
///
+ ///
+ /// Controls
+ /// -
+ ///
bool IsTracingAccess { get; }
///
/// Traces fees and burned fees
///
+ ///
+ /// Controls
+ /// -
+ ///
bool IsTracingFees { get; }
+ ///
+ /// Transaction completed successfully
+ ///
+ /// Transaction recipient
+ /// Gas spent on transaction execution
+ /// Output of transaction
+ /// Logs for transaction
+ /// State root after transaction, depends on EIP-658
+ /// Depends on
void MarkAsSuccess(Address recipient, long gasSpent, byte[] output, LogEntry[] logs, Keccak? stateRoot = null);
+ ///
+ /// Transaction failed
+ ///
+ /// Transaction recipient
+ /// Gas spent on transaction execution
+ /// Output of transaction
+ /// Error that failed the transaction
+ /// State root after transaction, depends on EIP-658
+ /// Depends on
void MarkAsFailed(Address recipient, long gasSpent, byte[] output, string error, Keccak? stateRoot = null);
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// Depends on
void StartOperation(int depth, long gas, Instruction opcode, int pc, bool isPostMerge = false);
+ ///
+ ///
+ ///
+ ///
+ /// Depends on
void ReportOperationError(EvmExceptionType error);
+ ///
+ ///
+ ///
+ ///
+ /// Depends on
void ReportOperationRemainingGas(long gas);
+ ///
+ ///
+ ///
+ ///
+ /// Depends on
void SetOperationStack(List stackTrace);
+ ///
+ ///
+ ///
+ ///
+ /// Depends on
void ReportStackPush(in ReadOnlySpan stackItem);
+ ///
+
+ ///
+ ///
+ /// Depends on
void ReportStackPush(byte stackItem)
{
ReportStackPush(new[] { stackItem });
}
+ ///
+ ///
+ ///
+ ///
+ /// Depends on
void ReportStackPush(in ZeroPaddedSpan stackItem)
{
ReportStackPush(stackItem.ToArray().AsSpan());
}
+ ///
+ ///
+ ///
+ /// Depends on
void ReportStackPush(in ZeroPaddedMemory stackItem)
{
ReportStackPush(stackItem.ToArray().AsSpan());
}
+ ///
+ ///
+ ///
+ ///
+ /// Depends on
void SetOperationMemory(List memoryTrace);
+ ///
+ ///
+ ///
+ ///
+ /// Depends on
void SetOperationMemorySize(ulong newSize);
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// Depends on
void ReportMemoryChange(long offset, in ReadOnlySpan data);
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// Depends on
void ReportMemoryChange(UInt256 offset, in ReadOnlySpan data)
{
if (offset.u1 <= 0 && offset.u2 <= 0 && offset.u3 <= 0 && offset.u0 <= long.MaxValue)
@@ -101,43 +252,142 @@ void ReportMemoryChange(UInt256 offset, in ReadOnlySpan data)
}
}
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// Depends on
void ReportMemoryChange(long offset, byte data)
{
ReportMemoryChange(offset, new[] { data });
}
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// Depends on
void ReportMemoryChange(long offset, in ZeroPaddedSpan data)
{
ReportMemoryChange(offset, data.ToArray());
}
+ ///
+ ///
+ ///
+ ///
+ /// Depends on
void ReportMemoryChange(long offset, in ZeroPaddedMemory data)
{
ReportMemoryChange(offset, data.ToArray());
}
- void ReportStorageChange(in ReadOnlySpan key, in ReadOnlySpan value);
-
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// Depends on
void SetOperationStorage(Address address, UInt256 storageIndex, ReadOnlySpan newValue, ReadOnlySpan currentValue);
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// Depends on
void SetOperationTransientStorage(Address storageCellAddress, UInt256 storageIndex, Span newValue, byte[] currentValue) { }
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// Depends on
void LoadOperationStorage(Address address, UInt256 storageIndex, ReadOnlySpan value);
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// Depends on
void LoadOperationTransientStorage(Address storageCellAddress, UInt256 storageIndex, byte[] value) { }
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// Depends on
void ReportSelfDestruct(Address address, UInt256 balance, Address refundAddress);
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// Depends on
void ReportAction(long gas, UInt256 value, Address @from, Address to, ReadOnlyMemory input, ExecutionType callType, bool isPrecompileCall = false);
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// Depends on
void ReportActionEnd(long gas, ReadOnlyMemory output);
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// Depends on
void ReportActionError(EvmExceptionType evmExceptionType, long gasLeft) => ReportActionError(evmExceptionType);
+ ///
+ ///
+ ///
+ ///
+ /// Depends on
void ReportActionError(EvmExceptionType evmExceptionType);
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// Depends on
void ReportActionEnd(long gas, Address deploymentAddress, ReadOnlyMemory deployedCode);
+ ///
+ ///
+ ///
+ ///
+ /// Depends on
void ReportBlockHash(Keccak blockHash);
+ ///
+ ///
+ ///
+ ///
+ /// Depends on
void ReportByteCode(byte[] byteCode);
///
@@ -145,11 +395,37 @@ void LoadOperationTransientStorage(Address storageCellAddress, UInt256 storageIn
///
///
///
+ /// Depends on
void ReportGasUpdateForVmTrace(long refund, long gasAvailable);
+ ///
+ ///
+ ///
+ ///
+ /// Depends on
void ReportRefund(long refund);
+
+ ///
+ ///
+ ///
+ ///
+ /// Depends on
void ReportExtraGasPressure(long extraGasPressure);
+
+ ///
+ /// Reports access to storage cell
+ ///
+ /// address
+ /// cell
+ /// Depends on
void ReportAccess(IReadOnlySet accessedAddresses, IReadOnlySet accessedStorageCells);
+
+ ///
+ /// Reports fees of a transaction
+ ///
+ /// Fees sent to block author
+ /// EIP-1559 burnt fees
+ /// Depends on
void ReportFees(UInt256 fees, UInt256 burntFees);
}
}
diff --git a/src/Nethermind/Nethermind.Evm/Tracing/ParityStyle/ParityLikeBlockTracer.cs b/src/Nethermind/Nethermind.Evm/Tracing/ParityStyle/ParityLikeBlockTracer.cs
index f17c8e81cfe..62e6c1e8964 100644
--- a/src/Nethermind/Nethermind.Evm/Tracing/ParityStyle/ParityLikeBlockTracer.cs
+++ b/src/Nethermind/Nethermind.Evm/Tracing/ParityStyle/ParityLikeBlockTracer.cs
@@ -1,6 +1,7 @@
// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited
// SPDX-License-Identifier: LGPL-3.0-only
+using System;
using System.Collections.Generic;
using System.Linq;
using Nethermind.Core;
@@ -52,7 +53,7 @@ public override void ReportReward(Address author, string rewardType, UInt256 rew
Value = rewardValue,
Author = author,
CallType = "reward",
- TraceAddress = new int[] { },
+ TraceAddress = Array.Empty(),
Type = "reward",
Result = null
};
@@ -62,10 +63,7 @@ public override void ReportReward(Address author, string rewardType, UInt256 rew
public override void StartNewBlockTrace(Block block)
{
_block = block;
- }
-
- public override void EndBlockTrace()
- {
+ base.StartNewBlockTrace(block);
}
}
}
diff --git a/src/Nethermind/Nethermind.Evm/Tracing/ParityStyle/ParityLikeTxTracer.cs b/src/Nethermind/Nethermind.Evm/Tracing/ParityStyle/ParityLikeTxTracer.cs
index e0960caa7ed..0fdbcd8e8e9 100644
--- a/src/Nethermind/Nethermind.Evm/Tracing/ParityStyle/ParityLikeTxTracer.cs
+++ b/src/Nethermind/Nethermind.Evm/Tracing/ParityStyle/ParityLikeTxTracer.cs
@@ -37,7 +37,7 @@ public ParityLikeTxTracer(Block block, Transaction? tx, ParityTraceTypes parityT
_trace = new ParityLikeTxTrace
{
TransactionHash = tx?.Hash,
- TransactionPosition = tx is null ? (int?)null : Array.IndexOf(block.Transactions!, tx),
+ TransactionPosition = tx is null ? null : Array.IndexOf(block.Transactions!, tx),
BlockNumber = block.Number,
BlockHash = block.Hash!
};
diff --git a/src/Nethermind/Nethermind.Evm/Tracing/ParityStyle/ParityResult.cs b/src/Nethermind/Nethermind.Evm/Tracing/ParityStyle/ParityResult.cs
index 9a09806e0a4..a84a116c226 100644
--- a/src/Nethermind/Nethermind.Evm/Tracing/ParityStyle/ParityResult.cs
+++ b/src/Nethermind/Nethermind.Evm/Tracing/ParityStyle/ParityResult.cs
@@ -8,8 +8,8 @@ namespace Nethermind.Evm.Tracing.ParityStyle
public class ParityTraceResult
{
public long GasUsed { get; set; }
- public byte[] Output { get; set; }
- public Address Address { get; set; }
- public byte[] Code { get; set; }
+ public byte[]? Output { get; set; }
+ public Address? Address { get; set; }
+ public byte[]? Code { get; set; }
}
}
diff --git a/src/Nethermind/Nethermind.Evm/Tracing/Proofs/ProofBlockTracer.cs b/src/Nethermind/Nethermind.Evm/Tracing/Proofs/ProofBlockTracer.cs
index 94d1537e368..f0c632b61e1 100644
--- a/src/Nethermind/Nethermind.Evm/Tracing/Proofs/ProofBlockTracer.cs
+++ b/src/Nethermind/Nethermind.Evm/Tracing/Proofs/ProofBlockTracer.cs
@@ -23,13 +23,5 @@ public ProofBlockTracer(Keccak? txHash, bool treatSystemAccountDifferently) : ba
/// Tracer of the transaction that just has been processed.
/// Just returns the
protected override ProofTxTracer OnEnd(ProofTxTracer txTracer) => txTracer;
-
- public override void StartNewBlockTrace(Block block)
- {
- }
-
- public override void EndBlockTrace()
- {
- }
}
}
diff --git a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/RpcModuleProviderTests.cs b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/RpcModuleProviderTests.cs
index f389ebcbfa6..38555e54510 100644
--- a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/RpcModuleProviderTests.cs
+++ b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/RpcModuleProviderTests.cs
@@ -94,5 +94,25 @@ public void Method_resolution_is_scoped_to_url_enabled_modules()
ModuleResolution fallbackResolution = _moduleProvider.Check("proof_call", new JsonRpcContext(RpcEndpoint.Http));
Assert.AreEqual(ModuleResolution.Enabled, fallbackResolution);
}
+
+ [Test]
+ public void Allows_to_get_modules()
+ {
+ SingletonModulePool pool = new(Substitute.For());
+ _moduleProvider.Register(pool);
+ _moduleProvider.GetPool(ModuleType.Net).Should().Be(pool);
+ }
+
+ [Test]
+ public void Allows_to_replace_modules()
+ {
+ SingletonModulePool pool = new(Substitute.For());
+ _moduleProvider.Register(pool);
+
+ SingletonModulePool pool2 = new(Substitute.For());
+ _moduleProvider.Register(pool2);
+
+ _moduleProvider.GetPool(ModuleType.Net).Should().Be(pool2);
+ }
}
}
diff --git a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/TestRpcModuleProvider.cs b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/TestRpcModuleProvider.cs
index ce88d758e95..abf6bf8de2e 100644
--- a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/TestRpcModuleProvider.cs
+++ b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/TestRpcModuleProvider.cs
@@ -59,24 +59,14 @@ private void EnableModule() where TOther : IRpcModule
public IReadOnlyCollection Converters => _provider.Converters;
public IReadOnlyCollection Enabled => _provider.All;
public IReadOnlyCollection All => _provider.All;
- public ModuleResolution Check(string methodName, JsonRpcContext context)
- {
- return _provider.Check(methodName, context);
- }
+ public ModuleResolution Check(string methodName, JsonRpcContext context) => _provider.Check(methodName, context);
- public (MethodInfo, bool) Resolve(string methodName)
- {
- return _provider.Resolve(methodName);
- }
+ public (MethodInfo, bool) Resolve(string methodName) => _provider.Resolve(methodName);
- public Task Rent(string methodName, bool readOnly)
- {
- return _provider.Rent(methodName, readOnly);
- }
+ public Task Rent(string methodName, bool readOnly) => _provider.Rent(methodName, readOnly);
- public void Return(string methodName, IRpcModule rpcModule)
- {
- _provider.Return(methodName, rpcModule);
- }
+ public void Return(string methodName, IRpcModule rpcModule) => _provider.Return(methodName, rpcModule);
+
+ public IRpcModulePool? GetPool(string moduleType) => _provider.GetPool(moduleType);
}
}
diff --git a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/TraceRpcModuleTests.cs b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/TraceRpcModuleTests.cs
index ef3782d3b78..63c37833776 100644
--- a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/TraceRpcModuleTests.cs
+++ b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/TraceRpcModuleTests.cs
@@ -97,7 +97,7 @@ public async Task Tx_positions_are_fine()
string serialized = RpcTest.TestSerializedRequest(
EthModuleFactory.Converters.Union(TraceModuleFactory.Converters).ToList(), context.TraceRpcModule,
"trace_block", "latest");
- Assert.AreEqual("{\"jsonrpc\":\"2.0\",\"result\":[{\"action\":{\"callType\":\"call\",\"from\":\"0x942921b14f1b1c385cd7e0cc2ef7abe5598c8358\",\"gas\":\"0x0\",\"input\":\"0x\",\"to\":\"0x0000000000000000000000000000000000000000\",\"value\":\"0x1\"},\"blockHash\":\"0xcd3d2c10309822aec4cbbfa80ba905ba1de62834a3b40f8012520734db2763ca\",\"blockNumber\":15,\"result\":{\"gasUsed\":\"0x0\",\"output\":\"0x\"},\"subtraces\":0,\"traceAddress\":[],\"transactionHash\":\"0xa1e0e640b433d5a8931881b8eee7b1a125474b04e430c0bf8afff52584c53273\",\"transactionPosition\":0,\"type\":\"call\"},{\"action\":{\"callType\":\"call\",\"from\":\"0x942921b14f1b1c385cd7e0cc2ef7abe5598c8358\",\"gas\":\"0x0\",\"input\":\"0x\",\"to\":\"0x0000000000000000000000000000000000000000\",\"value\":\"0x1\"},\"blockHash\":\"0xcd3d2c10309822aec4cbbfa80ba905ba1de62834a3b40f8012520734db2763ca\",\"blockNumber\":15,\"result\":{\"gasUsed\":\"0x0\",\"output\":\"0x\"},\"subtraces\":0,\"traceAddress\":[],\"transactionHash\":\"0x5cf5d4a0a93000beb1cfb373508ce4c0153ab491be99b3c927f482346c86a0e1\",\"transactionPosition\":1,\"type\":\"call\"},{\"action\":{\"callType\":\"call\",\"from\":\"0x942921b14f1b1c385cd7e0cc2ef7abe5598c8358\",\"gas\":\"0x0\",\"input\":\"0x\",\"to\":\"0x0000000000000000000000000000000000000000\",\"value\":\"0x1\"},\"blockHash\":\"0xcd3d2c10309822aec4cbbfa80ba905ba1de62834a3b40f8012520734db2763ca\",\"blockNumber\":15,\"result\":{\"gasUsed\":\"0x0\",\"output\":\"0x\"},\"subtraces\":0,\"traceAddress\":[],\"transactionHash\":\"0x02d2cde9120e37722f607771ebaa0d4e98c5d99a8a9e7df6872e8c8c9f5c0bc5\",\"transactionPosition\":2,\"type\":\"call\"},{\"action\":{\"callType\":\"call\",\"from\":\"0x942921b14f1b1c385cd7e0cc2ef7abe5598c8358\",\"gas\":\"0x0\",\"input\":\"0x\",\"to\":\"0x0000000000000000000000000000000000000000\",\"value\":\"0x1\"},\"blockHash\":\"0xcd3d2c10309822aec4cbbfa80ba905ba1de62834a3b40f8012520734db2763ca\",\"blockNumber\":15,\"result\":{\"gasUsed\":\"0x0\",\"output\":\"0x\"},\"subtraces\":0,\"traceAddress\":[],\"transactionHash\":\"0xe50a2a2d170011b1f9ee080c3810bed0c63dbb1b2b2c541c78ada5b222cc3fd2\",\"transactionPosition\":3,\"type\":\"call\"},{\"action\":{\"callType\":\"call\",\"from\":\"0x942921b14f1b1c385cd7e0cc2ef7abe5598c8358\",\"gas\":\"0x0\",\"input\":\"0x\",\"to\":\"0x0000000000000000000000000000000000000000\",\"value\":\"0x1\"},\"blockHash\":\"0xcd3d2c10309822aec4cbbfa80ba905ba1de62834a3b40f8012520734db2763ca\",\"blockNumber\":15,\"result\":{\"gasUsed\":\"0x0\",\"output\":\"0x\"},\"subtraces\":0,\"traceAddress\":[],\"transactionHash\":\"0xff0d4524d379fc15c41a9b0444b943e1a530779b7d09c8863858267c5ef92b24\",\"transactionPosition\":4,\"type\":\"call\"},{\"action\":{\"callType\":\"call\",\"from\":\"0x942921b14f1b1c385cd7e0cc2ef7abe5598c8358\",\"gas\":\"0x0\",\"input\":\"0x\",\"to\":\"0x0000000000000000000000000000000000000000\",\"value\":\"0x1\"},\"blockHash\":\"0xcd3d2c10309822aec4cbbfa80ba905ba1de62834a3b40f8012520734db2763ca\",\"blockNumber\":15,\"result\":{\"gasUsed\":\"0x0\",\"output\":\"0x\"},\"subtraces\":0,\"traceAddress\":[],\"transactionHash\":\"0xf9b69366c82084e3799dc4a7ad87dc173ef4923d853bc250de86b81786f2972a\",\"transactionPosition\":5,\"type\":\"call\"},{\"action\":{\"callType\":\"call\",\"from\":\"0x942921b14f1b1c385cd7e0cc2ef7abe5598c8358\",\"gas\":\"0x0\",\"input\":\"0x\",\"to\":\"0x0000000000000000000000000000000000000000\",\"value\":\"0x1\"},\"blockHash\":\"0xcd3d2c10309822aec4cbbfa80ba905ba1de62834a3b40f8012520734db2763ca\",\"blockNumber\":15,\"result\":{\"gasUsed\":\"0x0\",\"output\":\"0x\"},\"subtraces\":0,\"traceAddress\":[],\"transactionHash\":\"0x28171c29b23cd96f032fe43f444402af4555ee5f074d5d0d0a1089d940f136e7\",\"transactionPosition\":6,\"type\":\"call\"},{\"action\":{\"callType\":\"call\",\"from\":\"0x942921b14f1b1c385cd7e0cc2ef7abe5598c8358\",\"gas\":\"0x0\",\"input\":\"0x\",\"to\":\"0x0000000000000000000000000000000000000000\",\"value\":\"0x1\"},\"blockHash\":\"0xcd3d2c10309822aec4cbbfa80ba905ba1de62834a3b40f8012520734db2763ca\",\"blockNumber\":15,\"result\":{\"gasUsed\":\"0x0\",\"output\":\"0x\"},\"subtraces\":0,\"traceAddress\":[],\"transactionHash\":\"0x09b01caf4b7ecfe9d02251b2e478f2da0fdf08412e3fa1ff963fa80635dab031\",\"transactionPosition\":7,\"type\":\"call\"},{\"action\":{\"callType\":\"call\",\"from\":\"0x942921b14f1b1c385cd7e0cc2ef7abe5598c8358\",\"gas\":\"0x0\",\"input\":\"0x\",\"to\":\"0x0000000000000000000000000000000000000000\",\"value\":\"0x1\"},\"blockHash\":\"0xcd3d2c10309822aec4cbbfa80ba905ba1de62834a3b40f8012520734db2763ca\",\"blockNumber\":15,\"result\":{\"gasUsed\":\"0x0\",\"output\":\"0x\"},\"subtraces\":0,\"traceAddress\":[],\"transactionHash\":\"0xd82382905afbe4ca4c2b8e54cea43818c91e0014c3827e3020fbd82b732b8239\",\"transactionPosition\":8,\"type\":\"call\"},{\"action\":{\"author\":\"0x475674cb523a0a2736b7f7534390288fce16982c\",\"rewardType\":\"block\",\"value\":\"0x1bc16d674ec80000\"},\"blockHash\":\"0xcd3d2c10309822aec4cbbfa80ba905ba1de62834a3b40f8012520734db2763ca\",\"blockNumber\":15,\"result\":null,\"subtraces\":0,\"traceAddress\":[],\"type\":\"reward\"}],\"id\":67}", serialized);
+ Assert.AreEqual("{\"jsonrpc\":\"2.0\",\"result\":[{\"action\":{\"callType\":\"call\",\"from\":\"0x942921b14f1b1c385cd7e0cc2ef7abe5598c8358\",\"gas\":\"0x0\",\"input\":\"0x\",\"to\":\"0x0000000000000000000000000000000000000000\",\"value\":\"0x1\"},\"blockHash\":\"0xcd3d2c10309822aec4cbbfa80ba905ba1de62834a3b40f8012520734db2763ca\",\"blockNumber\":15,\"result\":{\"gasUsed\":\"0x0\",\"output\":\"0x\"},\"subtraces\":0,\"traceAddress\":[],\"transactionHash\":\"0xa1e0e640b433d5a8931881b8eee7b1a125474b04e430c0bf8afff52584c53273\",\"transactionPosition\":0,\"type\":\"call\"},{\"action\":{\"callType\":\"call\",\"from\":\"0x942921b14f1b1c385cd7e0cc2ef7abe5598c8358\",\"gas\":\"0x0\",\"input\":\"0x\",\"to\":\"0x0000000000000000000000000000000000000000\",\"value\":\"0x1\"},\"blockHash\":\"0xcd3d2c10309822aec4cbbfa80ba905ba1de62834a3b40f8012520734db2763ca\",\"blockNumber\":15,\"result\":{\"gasUsed\":\"0x0\",\"output\":\"0x\"},\"subtraces\":0,\"traceAddress\":[],\"transactionHash\":\"0x5cf5d4a0a93000beb1cfb373508ce4c0153ab491be99b3c927f482346c86a0e1\",\"transactionPosition\":1,\"type\":\"call\"},{\"action\":{\"callType\":\"call\",\"from\":\"0x942921b14f1b1c385cd7e0cc2ef7abe5598c8358\",\"gas\":\"0x0\",\"input\":\"0x\",\"to\":\"0x0000000000000000000000000000000000000000\",\"value\":\"0x1\"},\"blockHash\":\"0xcd3d2c10309822aec4cbbfa80ba905ba1de62834a3b40f8012520734db2763ca\",\"blockNumber\":15,\"result\":{\"gasUsed\":\"0x0\",\"output\":\"0x\"},\"subtraces\":0,\"traceAddress\":[],\"transactionHash\":\"0x02d2cde9120e37722f607771ebaa0d4e98c5d99a8a9e7df6872e8c8c9f5c0bc5\",\"transactionPosition\":2,\"type\":\"call\"},{\"action\":{\"callType\":\"call\",\"from\":\"0x942921b14f1b1c385cd7e0cc2ef7abe5598c8358\",\"gas\":\"0x0\",\"input\":\"0x\",\"to\":\"0x0000000000000000000000000000000000000000\",\"value\":\"0x1\"},\"blockHash\":\"0xcd3d2c10309822aec4cbbfa80ba905ba1de62834a3b40f8012520734db2763ca\",\"blockNumber\":15,\"result\":{\"gasUsed\":\"0x0\",\"output\":\"0x\"},\"subtraces\":0,\"traceAddress\":[],\"transactionHash\":\"0xe50a2a2d170011b1f9ee080c3810bed0c63dbb1b2b2c541c78ada5b222cc3fd2\",\"transactionPosition\":3,\"type\":\"call\"},{\"action\":{\"callType\":\"call\",\"from\":\"0x942921b14f1b1c385cd7e0cc2ef7abe5598c8358\",\"gas\":\"0x0\",\"input\":\"0x\",\"to\":\"0x0000000000000000000000000000000000000000\",\"value\":\"0x1\"},\"blockHash\":\"0xcd3d2c10309822aec4cbbfa80ba905ba1de62834a3b40f8012520734db2763ca\",\"blockNumber\":15,\"result\":{\"gasUsed\":\"0x0\",\"output\":\"0x\"},\"subtraces\":0,\"traceAddress\":[],\"transactionHash\":\"0xff0d4524d379fc15c41a9b0444b943e1a530779b7d09c8863858267c5ef92b24\",\"transactionPosition\":4,\"type\":\"call\"},{\"action\":{\"callType\":\"call\",\"from\":\"0x942921b14f1b1c385cd7e0cc2ef7abe5598c8358\",\"gas\":\"0x0\",\"input\":\"0x\",\"to\":\"0x0000000000000000000000000000000000000000\",\"value\":\"0x1\"},\"blockHash\":\"0xcd3d2c10309822aec4cbbfa80ba905ba1de62834a3b40f8012520734db2763ca\",\"blockNumber\":15,\"result\":{\"gasUsed\":\"0x0\",\"output\":\"0x\"},\"subtraces\":0,\"traceAddress\":[],\"transactionHash\":\"0xf9b69366c82084e3799dc4a7ad87dc173ef4923d853bc250de86b81786f2972a\",\"transactionPosition\":5,\"type\":\"call\"},{\"action\":{\"callType\":\"call\",\"from\":\"0x942921b14f1b1c385cd7e0cc2ef7abe5598c8358\",\"gas\":\"0x0\",\"input\":\"0x\",\"to\":\"0x0000000000000000000000000000000000000000\",\"value\":\"0x1\"},\"blockHash\":\"0xcd3d2c10309822aec4cbbfa80ba905ba1de62834a3b40f8012520734db2763ca\",\"blockNumber\":15,\"result\":{\"gasUsed\":\"0x0\",\"output\":\"0x\"},\"subtraces\":0,\"traceAddress\":[],\"transactionHash\":\"0x28171c29b23cd96f032fe43f444402af4555ee5f074d5d0d0a1089d940f136e7\",\"transactionPosition\":6,\"type\":\"call\"},{\"action\":{\"callType\":\"call\",\"from\":\"0x942921b14f1b1c385cd7e0cc2ef7abe5598c8358\",\"gas\":\"0x0\",\"input\":\"0x\",\"to\":\"0x0000000000000000000000000000000000000000\",\"value\":\"0x1\"},\"blockHash\":\"0xcd3d2c10309822aec4cbbfa80ba905ba1de62834a3b40f8012520734db2763ca\",\"blockNumber\":15,\"result\":{\"gasUsed\":\"0x0\",\"output\":\"0x\"},\"subtraces\":0,\"traceAddress\":[],\"transactionHash\":\"0x09b01caf4b7ecfe9d02251b2e478f2da0fdf08412e3fa1ff963fa80635dab031\",\"transactionPosition\":7,\"type\":\"call\"},{\"action\":{\"callType\":\"call\",\"from\":\"0x942921b14f1b1c385cd7e0cc2ef7abe5598c8358\",\"gas\":\"0x0\",\"input\":\"0x\",\"to\":\"0x0000000000000000000000000000000000000000\",\"value\":\"0x1\"},\"blockHash\":\"0xcd3d2c10309822aec4cbbfa80ba905ba1de62834a3b40f8012520734db2763ca\",\"blockNumber\":15,\"result\":{\"gasUsed\":\"0x0\",\"output\":\"0x\"},\"subtraces\":0,\"traceAddress\":[],\"transactionHash\":\"0xd82382905afbe4ca4c2b8e54cea43818c91e0014c3827e3020fbd82b732b8239\",\"transactionPosition\":8,\"type\":\"call\"},{\"action\":{\"author\":\"0x475674cb523a0a2736b7f7534390288fce16982c\",\"rewardType\":\"block\",\"value\":\"0x1bc16d674ec80000\"},\"blockHash\":\"0xcd3d2c10309822aec4cbbfa80ba905ba1de62834a3b40f8012520734db2763ca\",\"blockNumber\":15,\"subtraces\":0,\"traceAddress\":[],\"type\":\"reward\"}],\"id\":67}", serialized);
}
[Test]
@@ -152,7 +152,7 @@ public async Task Trace_filter_return_expected_json()
EthModuleFactory.Converters.Union(TraceModuleFactory.Converters).ToList(), context.TraceRpcModule,
"trace_filter", new EthereumJsonSerializer().Serialize(traceFilterRequest));
- Assert.AreEqual("{\"jsonrpc\":\"2.0\",\"result\":[{\"action\":{\"callType\":\"call\",\"from\":\"0x942921b14f1b1c385cd7e0cc2ef7abe5598c8358\",\"gas\":\"0x0\",\"input\":\"0x\",\"to\":\"0x0000000000000000000000000000000000000000\",\"value\":\"0x1\"},\"blockHash\":\"0xcd3d2c10309822aec4cbbfa80ba905ba1de62834a3b40f8012520734db2763ca\",\"blockNumber\":15,\"result\":{\"gasUsed\":\"0x0\",\"output\":\"0x\"},\"subtraces\":0,\"traceAddress\":[],\"transactionHash\":\"0xa1e0e640b433d5a8931881b8eee7b1a125474b04e430c0bf8afff52584c53273\",\"transactionPosition\":0,\"type\":\"call\"},{\"action\":{\"callType\":\"call\",\"from\":\"0x942921b14f1b1c385cd7e0cc2ef7abe5598c8358\",\"gas\":\"0x0\",\"input\":\"0x\",\"to\":\"0x0000000000000000000000000000000000000000\",\"value\":\"0x1\"},\"blockHash\":\"0xcd3d2c10309822aec4cbbfa80ba905ba1de62834a3b40f8012520734db2763ca\",\"blockNumber\":15,\"result\":{\"gasUsed\":\"0x0\",\"output\":\"0x\"},\"subtraces\":0,\"traceAddress\":[],\"transactionHash\":\"0x5cf5d4a0a93000beb1cfb373508ce4c0153ab491be99b3c927f482346c86a0e1\",\"transactionPosition\":1,\"type\":\"call\"},{\"action\":{\"callType\":\"call\",\"from\":\"0x942921b14f1b1c385cd7e0cc2ef7abe5598c8358\",\"gas\":\"0x0\",\"input\":\"0x\",\"to\":\"0x0000000000000000000000000000000000000000\",\"value\":\"0x1\"},\"blockHash\":\"0xcd3d2c10309822aec4cbbfa80ba905ba1de62834a3b40f8012520734db2763ca\",\"blockNumber\":15,\"result\":{\"gasUsed\":\"0x0\",\"output\":\"0x\"},\"subtraces\":0,\"traceAddress\":[],\"transactionHash\":\"0x02d2cde9120e37722f607771ebaa0d4e98c5d99a8a9e7df6872e8c8c9f5c0bc5\",\"transactionPosition\":2,\"type\":\"call\"},{\"action\":{\"callType\":\"call\",\"from\":\"0x942921b14f1b1c385cd7e0cc2ef7abe5598c8358\",\"gas\":\"0x0\",\"input\":\"0x\",\"to\":\"0x0000000000000000000000000000000000000000\",\"value\":\"0x1\"},\"blockHash\":\"0xcd3d2c10309822aec4cbbfa80ba905ba1de62834a3b40f8012520734db2763ca\",\"blockNumber\":15,\"result\":{\"gasUsed\":\"0x0\",\"output\":\"0x\"},\"subtraces\":0,\"traceAddress\":[],\"transactionHash\":\"0xe50a2a2d170011b1f9ee080c3810bed0c63dbb1b2b2c541c78ada5b222cc3fd2\",\"transactionPosition\":3,\"type\":\"call\"},{\"action\":{\"callType\":\"call\",\"from\":\"0x942921b14f1b1c385cd7e0cc2ef7abe5598c8358\",\"gas\":\"0x0\",\"input\":\"0x\",\"to\":\"0x0000000000000000000000000000000000000000\",\"value\":\"0x1\"},\"blockHash\":\"0xcd3d2c10309822aec4cbbfa80ba905ba1de62834a3b40f8012520734db2763ca\",\"blockNumber\":15,\"result\":{\"gasUsed\":\"0x0\",\"output\":\"0x\"},\"subtraces\":0,\"traceAddress\":[],\"transactionHash\":\"0xff0d4524d379fc15c41a9b0444b943e1a530779b7d09c8863858267c5ef92b24\",\"transactionPosition\":4,\"type\":\"call\"},{\"action\":{\"callType\":\"call\",\"from\":\"0x942921b14f1b1c385cd7e0cc2ef7abe5598c8358\",\"gas\":\"0x0\",\"input\":\"0x\",\"to\":\"0x0000000000000000000000000000000000000000\",\"value\":\"0x1\"},\"blockHash\":\"0xcd3d2c10309822aec4cbbfa80ba905ba1de62834a3b40f8012520734db2763ca\",\"blockNumber\":15,\"result\":{\"gasUsed\":\"0x0\",\"output\":\"0x\"},\"subtraces\":0,\"traceAddress\":[],\"transactionHash\":\"0xf9b69366c82084e3799dc4a7ad87dc173ef4923d853bc250de86b81786f2972a\",\"transactionPosition\":5,\"type\":\"call\"},{\"action\":{\"callType\":\"call\",\"from\":\"0x942921b14f1b1c385cd7e0cc2ef7abe5598c8358\",\"gas\":\"0x0\",\"input\":\"0x\",\"to\":\"0x0000000000000000000000000000000000000000\",\"value\":\"0x1\"},\"blockHash\":\"0xcd3d2c10309822aec4cbbfa80ba905ba1de62834a3b40f8012520734db2763ca\",\"blockNumber\":15,\"result\":{\"gasUsed\":\"0x0\",\"output\":\"0x\"},\"subtraces\":0,\"traceAddress\":[],\"transactionHash\":\"0x28171c29b23cd96f032fe43f444402af4555ee5f074d5d0d0a1089d940f136e7\",\"transactionPosition\":6,\"type\":\"call\"},{\"action\":{\"callType\":\"call\",\"from\":\"0x942921b14f1b1c385cd7e0cc2ef7abe5598c8358\",\"gas\":\"0x0\",\"input\":\"0x\",\"to\":\"0x0000000000000000000000000000000000000000\",\"value\":\"0x1\"},\"blockHash\":\"0xcd3d2c10309822aec4cbbfa80ba905ba1de62834a3b40f8012520734db2763ca\",\"blockNumber\":15,\"result\":{\"gasUsed\":\"0x0\",\"output\":\"0x\"},\"subtraces\":0,\"traceAddress\":[],\"transactionHash\":\"0x09b01caf4b7ecfe9d02251b2e478f2da0fdf08412e3fa1ff963fa80635dab031\",\"transactionPosition\":7,\"type\":\"call\"},{\"action\":{\"callType\":\"call\",\"from\":\"0x942921b14f1b1c385cd7e0cc2ef7abe5598c8358\",\"gas\":\"0x0\",\"input\":\"0x\",\"to\":\"0x0000000000000000000000000000000000000000\",\"value\":\"0x1\"},\"blockHash\":\"0xcd3d2c10309822aec4cbbfa80ba905ba1de62834a3b40f8012520734db2763ca\",\"blockNumber\":15,\"result\":{\"gasUsed\":\"0x0\",\"output\":\"0x\"},\"subtraces\":0,\"traceAddress\":[],\"transactionHash\":\"0xd82382905afbe4ca4c2b8e54cea43818c91e0014c3827e3020fbd82b732b8239\",\"transactionPosition\":8,\"type\":\"call\"},{\"action\":{\"author\":\"0x475674cb523a0a2736b7f7534390288fce16982c\",\"rewardType\":\"block\",\"value\":\"0x1bc16d674ec80000\"},\"blockHash\":\"0xcd3d2c10309822aec4cbbfa80ba905ba1de62834a3b40f8012520734db2763ca\",\"blockNumber\":15,\"result\":null,\"subtraces\":0,\"traceAddress\":[],\"type\":\"reward\"}],\"id\":67}", serialized, serialized.Replace("\"", "\\\""));
+ Assert.AreEqual("{\"jsonrpc\":\"2.0\",\"result\":[{\"action\":{\"callType\":\"call\",\"from\":\"0x942921b14f1b1c385cd7e0cc2ef7abe5598c8358\",\"gas\":\"0x0\",\"input\":\"0x\",\"to\":\"0x0000000000000000000000000000000000000000\",\"value\":\"0x1\"},\"blockHash\":\"0xcd3d2c10309822aec4cbbfa80ba905ba1de62834a3b40f8012520734db2763ca\",\"blockNumber\":15,\"result\":{\"gasUsed\":\"0x0\",\"output\":\"0x\"},\"subtraces\":0,\"traceAddress\":[],\"transactionHash\":\"0xa1e0e640b433d5a8931881b8eee7b1a125474b04e430c0bf8afff52584c53273\",\"transactionPosition\":0,\"type\":\"call\"},{\"action\":{\"callType\":\"call\",\"from\":\"0x942921b14f1b1c385cd7e0cc2ef7abe5598c8358\",\"gas\":\"0x0\",\"input\":\"0x\",\"to\":\"0x0000000000000000000000000000000000000000\",\"value\":\"0x1\"},\"blockHash\":\"0xcd3d2c10309822aec4cbbfa80ba905ba1de62834a3b40f8012520734db2763ca\",\"blockNumber\":15,\"result\":{\"gasUsed\":\"0x0\",\"output\":\"0x\"},\"subtraces\":0,\"traceAddress\":[],\"transactionHash\":\"0x5cf5d4a0a93000beb1cfb373508ce4c0153ab491be99b3c927f482346c86a0e1\",\"transactionPosition\":1,\"type\":\"call\"},{\"action\":{\"callType\":\"call\",\"from\":\"0x942921b14f1b1c385cd7e0cc2ef7abe5598c8358\",\"gas\":\"0x0\",\"input\":\"0x\",\"to\":\"0x0000000000000000000000000000000000000000\",\"value\":\"0x1\"},\"blockHash\":\"0xcd3d2c10309822aec4cbbfa80ba905ba1de62834a3b40f8012520734db2763ca\",\"blockNumber\":15,\"result\":{\"gasUsed\":\"0x0\",\"output\":\"0x\"},\"subtraces\":0,\"traceAddress\":[],\"transactionHash\":\"0x02d2cde9120e37722f607771ebaa0d4e98c5d99a8a9e7df6872e8c8c9f5c0bc5\",\"transactionPosition\":2,\"type\":\"call\"},{\"action\":{\"callType\":\"call\",\"from\":\"0x942921b14f1b1c385cd7e0cc2ef7abe5598c8358\",\"gas\":\"0x0\",\"input\":\"0x\",\"to\":\"0x0000000000000000000000000000000000000000\",\"value\":\"0x1\"},\"blockHash\":\"0xcd3d2c10309822aec4cbbfa80ba905ba1de62834a3b40f8012520734db2763ca\",\"blockNumber\":15,\"result\":{\"gasUsed\":\"0x0\",\"output\":\"0x\"},\"subtraces\":0,\"traceAddress\":[],\"transactionHash\":\"0xe50a2a2d170011b1f9ee080c3810bed0c63dbb1b2b2c541c78ada5b222cc3fd2\",\"transactionPosition\":3,\"type\":\"call\"},{\"action\":{\"callType\":\"call\",\"from\":\"0x942921b14f1b1c385cd7e0cc2ef7abe5598c8358\",\"gas\":\"0x0\",\"input\":\"0x\",\"to\":\"0x0000000000000000000000000000000000000000\",\"value\":\"0x1\"},\"blockHash\":\"0xcd3d2c10309822aec4cbbfa80ba905ba1de62834a3b40f8012520734db2763ca\",\"blockNumber\":15,\"result\":{\"gasUsed\":\"0x0\",\"output\":\"0x\"},\"subtraces\":0,\"traceAddress\":[],\"transactionHash\":\"0xff0d4524d379fc15c41a9b0444b943e1a530779b7d09c8863858267c5ef92b24\",\"transactionPosition\":4,\"type\":\"call\"},{\"action\":{\"callType\":\"call\",\"from\":\"0x942921b14f1b1c385cd7e0cc2ef7abe5598c8358\",\"gas\":\"0x0\",\"input\":\"0x\",\"to\":\"0x0000000000000000000000000000000000000000\",\"value\":\"0x1\"},\"blockHash\":\"0xcd3d2c10309822aec4cbbfa80ba905ba1de62834a3b40f8012520734db2763ca\",\"blockNumber\":15,\"result\":{\"gasUsed\":\"0x0\",\"output\":\"0x\"},\"subtraces\":0,\"traceAddress\":[],\"transactionHash\":\"0xf9b69366c82084e3799dc4a7ad87dc173ef4923d853bc250de86b81786f2972a\",\"transactionPosition\":5,\"type\":\"call\"},{\"action\":{\"callType\":\"call\",\"from\":\"0x942921b14f1b1c385cd7e0cc2ef7abe5598c8358\",\"gas\":\"0x0\",\"input\":\"0x\",\"to\":\"0x0000000000000000000000000000000000000000\",\"value\":\"0x1\"},\"blockHash\":\"0xcd3d2c10309822aec4cbbfa80ba905ba1de62834a3b40f8012520734db2763ca\",\"blockNumber\":15,\"result\":{\"gasUsed\":\"0x0\",\"output\":\"0x\"},\"subtraces\":0,\"traceAddress\":[],\"transactionHash\":\"0x28171c29b23cd96f032fe43f444402af4555ee5f074d5d0d0a1089d940f136e7\",\"transactionPosition\":6,\"type\":\"call\"},{\"action\":{\"callType\":\"call\",\"from\":\"0x942921b14f1b1c385cd7e0cc2ef7abe5598c8358\",\"gas\":\"0x0\",\"input\":\"0x\",\"to\":\"0x0000000000000000000000000000000000000000\",\"value\":\"0x1\"},\"blockHash\":\"0xcd3d2c10309822aec4cbbfa80ba905ba1de62834a3b40f8012520734db2763ca\",\"blockNumber\":15,\"result\":{\"gasUsed\":\"0x0\",\"output\":\"0x\"},\"subtraces\":0,\"traceAddress\":[],\"transactionHash\":\"0x09b01caf4b7ecfe9d02251b2e478f2da0fdf08412e3fa1ff963fa80635dab031\",\"transactionPosition\":7,\"type\":\"call\"},{\"action\":{\"callType\":\"call\",\"from\":\"0x942921b14f1b1c385cd7e0cc2ef7abe5598c8358\",\"gas\":\"0x0\",\"input\":\"0x\",\"to\":\"0x0000000000000000000000000000000000000000\",\"value\":\"0x1\"},\"blockHash\":\"0xcd3d2c10309822aec4cbbfa80ba905ba1de62834a3b40f8012520734db2763ca\",\"blockNumber\":15,\"result\":{\"gasUsed\":\"0x0\",\"output\":\"0x\"},\"subtraces\":0,\"traceAddress\":[],\"transactionHash\":\"0xd82382905afbe4ca4c2b8e54cea43818c91e0014c3827e3020fbd82b732b8239\",\"transactionPosition\":8,\"type\":\"call\"},{\"action\":{\"author\":\"0x475674cb523a0a2736b7f7534390288fce16982c\",\"rewardType\":\"block\",\"value\":\"0x1bc16d674ec80000\"},\"blockHash\":\"0xcd3d2c10309822aec4cbbfa80ba905ba1de62834a3b40f8012520734db2763ca\",\"blockNumber\":15,\"subtraces\":0,\"traceAddress\":[],\"type\":\"reward\"}],\"id\":67}", serialized, serialized.Replace("\"", "\\\""));
}
[Test]
@@ -534,7 +534,7 @@ public async Task Trace_transaction_with_error_reverted()
traces.Data.ElementAt(0).TransactionHash.Should().Be(transaction2.Hash!);
string serialized = new EthereumJsonSerializer().Serialize(traces.Data);
- Assert.AreEqual("[{\"action\":{\"traceAddress\":[],\"callType\":\"create\",\"includeInTrace\":true,\"isPrecompiled\":false,\"type\":\"create\",\"creationMethod\":\"create\",\"from\":\"0x942921b14f1b1c385cd7e0cc2ef7abe5598c8358\",\"to\":\"0xd6a48bcd4c5ad5adacfab677519c25ce7b2805a5\",\"gas\":\"0x9a6c\",\"value\":\"0x1\",\"input\":\"0x60006000600060006000736b5887043de753ecfa6269f947129068263ffbe261c350f160006000600060006000736b5887043de753ecfa6269f947129068263ffbe261c350f1fd\",\"subtraces\":[{\"traceAddress\":[0],\"callType\":\"call\",\"includeInTrace\":true,\"isPrecompiled\":false,\"type\":\"call\",\"from\":\"0xd6a48bcd4c5ad5adacfab677519c25ce7b2805a5\",\"to\":\"0x6b5887043de753ecfa6269f947129068263ffbe2\",\"gas\":\"0x2dcd\",\"value\":\"0x0\",\"input\":\"0x\",\"result\":{\"gasUsed\":\"0x0\",\"output\":\"0x\"},\"subtraces\":[]},{\"traceAddress\":[1],\"callType\":\"call\",\"includeInTrace\":true,\"isPrecompiled\":false,\"type\":\"call\",\"from\":\"0xd6a48bcd4c5ad5adacfab677519c25ce7b2805a5\",\"to\":\"0x6b5887043de753ecfa6269f947129068263ffbe2\",\"gas\":\"0x2d56\",\"value\":\"0x0\",\"input\":\"0x\",\"result\":{\"gasUsed\":\"0x0\",\"output\":\"0x\"},\"subtraces\":[]}],\"error\":\"Reverted\"},\"blockHash\":\"0xfa74e932520ee416ecb12171c115b3ad14112ffd2d612646ceaff69e54e06a94\",\"blockNumber\":18,\"result\":null,\"subtraces\":2,\"traceAddress\":[],\"transactionHash\":\"0x787616b8756424622f162fc3817331517ef941366f28db452defc0214bc36b22\",\"transactionPosition\":0,\"type\":\"create\",\"error\":\"Reverted\"},{\"action\":{\"traceAddress\":[0],\"callType\":\"call\",\"includeInTrace\":true,\"isPrecompiled\":false,\"type\":\"call\",\"from\":\"0xd6a48bcd4c5ad5adacfab677519c25ce7b2805a5\",\"to\":\"0x6b5887043de753ecfa6269f947129068263ffbe2\",\"gas\":\"0x2dcd\",\"value\":\"0x0\",\"input\":\"0x\",\"result\":{\"gasUsed\":\"0x0\",\"output\":\"0x\"},\"subtraces\":[]},\"blockHash\":\"0xfa74e932520ee416ecb12171c115b3ad14112ffd2d612646ceaff69e54e06a94\",\"blockNumber\":18,\"result\":{\"gasUsed\":\"0x0\",\"output\":\"0x\"},\"subtraces\":0,\"traceAddress\":[0],\"transactionHash\":\"0x787616b8756424622f162fc3817331517ef941366f28db452defc0214bc36b22\",\"transactionPosition\":0,\"type\":\"call\"},{\"action\":{\"traceAddress\":[1],\"callType\":\"call\",\"includeInTrace\":true,\"isPrecompiled\":false,\"type\":\"call\",\"from\":\"0xd6a48bcd4c5ad5adacfab677519c25ce7b2805a5\",\"to\":\"0x6b5887043de753ecfa6269f947129068263ffbe2\",\"gas\":\"0x2d56\",\"value\":\"0x0\",\"input\":\"0x\",\"result\":{\"gasUsed\":\"0x0\",\"output\":\"0x\"},\"subtraces\":[]},\"blockHash\":\"0xfa74e932520ee416ecb12171c115b3ad14112ffd2d612646ceaff69e54e06a94\",\"blockNumber\":18,\"result\":{\"gasUsed\":\"0x0\",\"output\":\"0x\"},\"subtraces\":0,\"traceAddress\":[1],\"transactionHash\":\"0x787616b8756424622f162fc3817331517ef941366f28db452defc0214bc36b22\",\"transactionPosition\":0,\"type\":\"call\"}]", serialized, serialized.Replace("\"", "\\\""));
+ Assert.AreEqual("[{\"action\":{\"traceAddress\":[],\"callType\":\"create\",\"includeInTrace\":true,\"isPrecompiled\":false,\"type\":\"create\",\"creationMethod\":\"create\",\"from\":\"0x942921b14f1b1c385cd7e0cc2ef7abe5598c8358\",\"to\":\"0xd6a48bcd4c5ad5adacfab677519c25ce7b2805a5\",\"gas\":\"0x9a6c\",\"value\":\"0x1\",\"input\":\"0x60006000600060006000736b5887043de753ecfa6269f947129068263ffbe261c350f160006000600060006000736b5887043de753ecfa6269f947129068263ffbe261c350f1fd\",\"subtraces\":[{\"traceAddress\":[0],\"callType\":\"call\",\"includeInTrace\":true,\"isPrecompiled\":false,\"type\":\"call\",\"from\":\"0xd6a48bcd4c5ad5adacfab677519c25ce7b2805a5\",\"to\":\"0x6b5887043de753ecfa6269f947129068263ffbe2\",\"gas\":\"0x2dcd\",\"value\":\"0x0\",\"input\":\"0x\",\"result\":{\"gasUsed\":\"0x0\",\"output\":\"0x\"},\"subtraces\":[]},{\"traceAddress\":[1],\"callType\":\"call\",\"includeInTrace\":true,\"isPrecompiled\":false,\"type\":\"call\",\"from\":\"0xd6a48bcd4c5ad5adacfab677519c25ce7b2805a5\",\"to\":\"0x6b5887043de753ecfa6269f947129068263ffbe2\",\"gas\":\"0x2d56\",\"value\":\"0x0\",\"input\":\"0x\",\"result\":{\"gasUsed\":\"0x0\",\"output\":\"0x\"},\"subtraces\":[]}],\"error\":\"Reverted\"},\"blockHash\":\"0xfa74e932520ee416ecb12171c115b3ad14112ffd2d612646ceaff69e54e06a94\",\"blockNumber\":18,\"subtraces\":2,\"traceAddress\":[],\"transactionHash\":\"0x787616b8756424622f162fc3817331517ef941366f28db452defc0214bc36b22\",\"transactionPosition\":0,\"type\":\"create\",\"error\":\"Reverted\"},{\"action\":{\"traceAddress\":[0],\"callType\":\"call\",\"includeInTrace\":true,\"isPrecompiled\":false,\"type\":\"call\",\"from\":\"0xd6a48bcd4c5ad5adacfab677519c25ce7b2805a5\",\"to\":\"0x6b5887043de753ecfa6269f947129068263ffbe2\",\"gas\":\"0x2dcd\",\"value\":\"0x0\",\"input\":\"0x\",\"result\":{\"gasUsed\":\"0x0\",\"output\":\"0x\"},\"subtraces\":[]},\"blockHash\":\"0xfa74e932520ee416ecb12171c115b3ad14112ffd2d612646ceaff69e54e06a94\",\"blockNumber\":18,\"result\":{\"gasUsed\":\"0x0\",\"output\":\"0x\"},\"subtraces\":0,\"traceAddress\":[0],\"transactionHash\":\"0x787616b8756424622f162fc3817331517ef941366f28db452defc0214bc36b22\",\"transactionPosition\":0,\"type\":\"call\"},{\"action\":{\"traceAddress\":[1],\"callType\":\"call\",\"includeInTrace\":true,\"isPrecompiled\":false,\"type\":\"call\",\"from\":\"0xd6a48bcd4c5ad5adacfab677519c25ce7b2805a5\",\"to\":\"0x6b5887043de753ecfa6269f947129068263ffbe2\",\"gas\":\"0x2d56\",\"value\":\"0x0\",\"input\":\"0x\",\"result\":{\"gasUsed\":\"0x0\",\"output\":\"0x\"},\"subtraces\":[]},\"blockHash\":\"0xfa74e932520ee416ecb12171c115b3ad14112ffd2d612646ceaff69e54e06a94\",\"blockNumber\":18,\"result\":{\"gasUsed\":\"0x0\",\"output\":\"0x\"},\"subtraces\":0,\"traceAddress\":[1],\"transactionHash\":\"0x787616b8756424622f162fc3817331517ef941366f28db452defc0214bc36b22\",\"transactionPosition\":0,\"type\":\"call\"}]", serialized, serialized.Replace("\"", "\\\""));
}
[Test]
public async Task trace_timeout_is_separate_for_rpc_calls()
diff --git a/src/Nethermind/Nethermind.JsonRpc.TraceStore.Tests/DbPersistingBlockTracerTests.cs b/src/Nethermind/Nethermind.JsonRpc.TraceStore.Tests/DbPersistingBlockTracerTests.cs
new file mode 100644
index 00000000000..4f8562f4089
--- /dev/null
+++ b/src/Nethermind/Nethermind.JsonRpc.TraceStore.Tests/DbPersistingBlockTracerTests.cs
@@ -0,0 +1,40 @@
+// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited
+// SPDX-License-Identifier: LGPL-3.0-only
+
+using System.Collections.Generic;
+using System.Text.Json;
+using FluentAssertions;
+using Nethermind.Core;
+using Nethermind.Core.Crypto;
+using Nethermind.Core.Test.Builders;
+using Nethermind.Db;
+using Nethermind.Evm.Tracing.ParityStyle;
+using Nethermind.Logging;
+using NUnit.Framework;
+
+namespace Nethermind.JsonRpc.TraceStore.Tests;
+
+[Parallelizable(ParallelScope.All)]
+public class DbPersistingBlockTracerTests
+{
+ [Test]
+ public void saves_traces_to_db()
+ {
+ ParityLikeBlockTracer parityTracer = new(ParityTraceTypes.Trace);
+ MemDb memDb = new();
+ ParityLikeTraceSerializer serializer = new(LimboLogs.Instance);
+ DbPersistingBlockTracer dbPersistingTracer =
+ new(parityTracer, memDb, serializer, LimboLogs.Instance);
+
+ Transaction transaction = Build.A.Transaction.TestObject;
+ Block block = Build.A.Block.WithTransactions(transaction).TestObject;
+ dbPersistingTracer.StartNewBlockTrace(block);
+ dbPersistingTracer.StartNewTxTrace(transaction);
+ dbPersistingTracer.EndTxTrace();
+ dbPersistingTracer.EndBlockTrace();
+
+ List? traces = serializer.Deserialize(memDb.Get(block.Hash!));
+ traces.Should().BeEquivalentTo(new ParityLikeTxTrace[] { new() { BlockHash = block.Hash, TransactionPosition = 0 } });
+
+ }
+}
diff --git a/src/Nethermind/Nethermind.JsonRpc.TraceStore.Tests/Nethermind.JsonRpc.TraceStore.Tests.csproj b/src/Nethermind/Nethermind.JsonRpc.TraceStore.Tests/Nethermind.JsonRpc.TraceStore.Tests.csproj
new file mode 100644
index 00000000000..91e11929d6b
--- /dev/null
+++ b/src/Nethermind/Nethermind.JsonRpc.TraceStore.Tests/Nethermind.JsonRpc.TraceStore.Tests.csproj
@@ -0,0 +1,27 @@
+
+
+
+ net6.0
+ enable
+
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Nethermind/Nethermind.JsonRpc.TraceStore.Tests/TraceSerializerTests.cs b/src/Nethermind/Nethermind.JsonRpc.TraceStore.Tests/TraceSerializerTests.cs
new file mode 100644
index 00000000000..bfcea492d2c
--- /dev/null
+++ b/src/Nethermind/Nethermind.JsonRpc.TraceStore.Tests/TraceSerializerTests.cs
@@ -0,0 +1,38 @@
+// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited
+// SPDX-License-Identifier: LGPL-3.0-only
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using FluentAssertions;
+using Nethermind.Evm.Tracing.ParityStyle;
+using Nethermind.Logging;
+using Newtonsoft.Json;
+using NUnit.Framework;
+
+namespace Nethermind.JsonRpc.TraceStore.Tests;
+
+public class TraceSerializerTests
+{
+ [Test]
+ public void can_deserialize_deep_graph()
+ {
+ List? traces = Deserialize(new ParityLikeTraceSerializer(LimboLogs.Instance));
+ traces?.Count.Should().Be(36);
+ }
+
+ [Test]
+ public void cant_deserialize_deep_graph()
+ {
+ Func?> traces = () => Deserialize(new ParityLikeTraceSerializer(LimboLogs.Instance, 128));
+ traces.Should().Throw();
+ }
+
+ private List? Deserialize(ITraceSerializer serializer)
+ {
+ Type type = GetType();
+ using Stream stream = type.Assembly.GetManifestResourceStream(type.Namespace + ".xdai-17600039.json")!;
+ List? traces = serializer.Deserialize(stream);
+ return traces;
+ }
+}
diff --git a/src/Nethermind/Nethermind.JsonRpc.TraceStore.Tests/TraceStorePrunerTests.cs b/src/Nethermind/Nethermind.JsonRpc.TraceStore.Tests/TraceStorePrunerTests.cs
new file mode 100644
index 00000000000..dfc76405d52
--- /dev/null
+++ b/src/Nethermind/Nethermind.JsonRpc.TraceStore.Tests/TraceStorePrunerTests.cs
@@ -0,0 +1,68 @@
+// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited
+// SPDX-License-Identifier: LGPL-3.0-only
+
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using FluentAssertions;
+using Nethermind.Blockchain;
+using Nethermind.Blockchain.Find;
+using Nethermind.Core;
+using Nethermind.Core.Crypto;
+using Nethermind.Core.Test.Builders;
+using Nethermind.Db;
+using Nethermind.Evm.Tracing.ParityStyle;
+using Nethermind.Logging;
+using NUnit.Framework;
+
+namespace Nethermind.JsonRpc.TraceStore.Tests;
+
+[Parallelizable(ParallelScope.All)]
+public class TraceStorePrunerTests
+{
+ [Test]
+ public async Task prunes_old_blocks()
+ {
+ IEnumerable GenerateTraces(MemDb db, BlockTree tree)
+ {
+ ParityLikeBlockTracer parityTracer = new(ParityTraceTypes.Trace);
+ ParityLikeTraceSerializer serializer = new(LimboLogs.Instance);
+ DbPersistingBlockTracer dbPersistingTracer =
+ new(parityTracer, db, serializer, LimboLogs.Instance);
+
+ Block? current = tree.Head;
+ while (current is not null)
+ {
+ dbPersistingTracer.StartNewBlockTrace(current);
+ dbPersistingTracer.StartNewTxTrace(Build.A.Transaction.TestObject);
+ dbPersistingTracer.EndTxTrace();
+ dbPersistingTracer.EndBlockTrace();
+ yield return current.Hash!;
+ current = tree.FindParent(current, BlockTreeLookupOptions.None);
+ }
+ }
+
+ void AddNewBlocks(BlockTree tree)
+ {
+ Block headPlus1 = Build.A.Block.WithParent(tree.Head!).TestObject;
+ Block headPlus2 = Build.A.Block.WithParent(headPlus1).TestObject;
+ Block headPlus3 = Build.A.Block.WithParent(headPlus2).TestObject;
+ tree.SuggestBlock(headPlus1);
+ tree.SuggestBlock(headPlus2);
+ tree.SuggestBlock(headPlus3);
+ Block[] blocks = { headPlus1, headPlus2, headPlus3 };
+ tree.UpdateMainChain(blocks, true);
+ }
+
+ MemDb memDb = new();
+ BlockTree blockTree = Build.A.BlockTree().OfChainLength(5).TestObject;
+ TraceStorePruner tracePruner = new(blockTree, memDb, 3, LimboLogs.Instance);
+ List keys = GenerateTraces(memDb, blockTree).ToList();
+ keys.Select(k => memDb.Get(k)).Should().NotContain((byte[]?)null);
+ AddNewBlocks(blockTree);
+ await Task.Delay(100);
+ keys.Skip(3).Select(k => memDb.Get(k)).Should().NotContain((byte[]?)null); // too old were not removed
+ keys.Take(3).Select(k => memDb.Get(k)).Should().OnlyContain(b => b == null); // those were removed
+
+ }
+}
diff --git a/src/Nethermind/Nethermind.JsonRpc.TraceStore.Tests/TraceStoreRpcModuleTests.cs b/src/Nethermind/Nethermind.JsonRpc.TraceStore.Tests/TraceStoreRpcModuleTests.cs
new file mode 100644
index 00000000000..b5a3eec71df
--- /dev/null
+++ b/src/Nethermind/Nethermind.JsonRpc.TraceStore.Tests/TraceStoreRpcModuleTests.cs
@@ -0,0 +1,171 @@
+// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited
+// SPDX-License-Identifier: LGPL-3.0-only
+
+using System.Collections.Generic;
+using System.Linq;
+using FastEnumUtility;
+using FluentAssertions;
+using Nethermind.Blockchain.Find;
+using Nethermind.Blockchain.Receipts;
+using Nethermind.Core;
+using Nethermind.Core.Crypto;
+using Nethermind.Core.Extensions;
+using Nethermind.Core.Test.Builders;
+using Nethermind.Db;
+using Nethermind.Evm.Tracing.ParityStyle;
+using Nethermind.JsonRpc.Data;
+using Nethermind.JsonRpc.Modules.Trace;
+using Nethermind.Logging;
+using NSubstitute;
+using NUnit.Framework;
+
+namespace Nethermind.JsonRpc.TraceStore.Tests;
+
+[Parallelizable(ParallelScope.All)]
+public class TraceStoreRpcModuleTests
+{
+ [Test]
+ public void trace_call_returns_from_inner_module()
+ {
+ TestContext test = new();
+
+ test.Module.trace_call(new TransactionForRpc(Build.A.Transaction.TestObject), new[] { ParityTraceTypes.Trace.ToString() }, BlockParameter.Latest)
+ .Should().BeEquivalentTo(ResultWrapper.Success(new ParityTxTraceFromReplay(test.NonDbTraces[0])));
+ }
+
+ [Test]
+ public void trace_callMany_returns_from_inner_module()
+ {
+ TestContext test = new();
+
+ TransactionForRpcWithTraceTypes[] calls = { new() { TraceTypes = new[] { ParityTraceTypes.Trace.ToString() }, Transaction = new TransactionForRpc(Build.A.Transaction.TestObject) } };
+ test.Module.trace_callMany(calls, BlockParameter.Latest)
+ .Should().BeEquivalentTo(ResultWrapper>.Success(test.NonDbTraces.Select(t => new ParityTxTraceFromReplay(t))));
+ }
+
+ [Test]
+ public void trace_Transaction_returns_from_inner_module()
+ {
+ TestContext test = new();
+
+ test.Module.trace_rawTransaction(Bytes.Empty, new[] { ParityTraceTypes.Trace.ToString() })
+ .Should().BeEquivalentTo(ResultWrapper.Success(new ParityTxTraceFromReplay(test.NonDbTraces[0])));
+ }
+
+ [Test]
+ public void trace_replayTransaction_returns_from_inner_module()
+ {
+ TestContext test = new();
+
+ test.Module.trace_replayTransaction(test.NonDbTraces.First().TransactionHash!, new[] { ParityTraceTypes.Trace.ToString() })
+ .Should().BeEquivalentTo(ResultWrapper.Success(new ParityTxTraceFromReplay(test.NonDbTraces[0])));
+ }
+
+ [Test]
+ public void trace_replayTransaction_returns_from_store()
+ {
+ TestContext test = new();
+
+ test.Module.trace_replayTransaction(test.DbTrace.TransactionHash!, new[] { ParityTraceTypes.Trace.ToString() })
+ .Should().BeEquivalentTo(ResultWrapper.Success(new ParityTxTraceFromReplay(test.DbTrace)));
+ }
+
+ [Test]
+ public void trace_replayBlockTransactions_returns_from_inner_module()
+ {
+ TestContext test = new();
+
+ test.Module.trace_replayBlockTransactions(new BlockParameter(1), new[] { ParityTraceTypes.Trace.ToString() })
+ .Should().BeEquivalentTo(ResultWrapper>.Success(test.NonDbTraces.Select(t => new ParityTxTraceFromReplay(t))));
+ }
+
+ [Test]
+ public void trace_replayBlockTransactions_returns_from_store()
+ {
+ TestContext test = new();
+
+ test.Module.trace_replayBlockTransactions(BlockParameter.Latest, new[] { ParityTraceTypes.Trace.ToString(), ParityTraceTypes.Rewards.ToString() })
+ .Should().BeEquivalentTo(ResultWrapper>.Success(test.DbTraces.Select(t => new ParityTxTraceFromReplay(t))));
+ }
+
+ [Test]
+ public void trace_filter_returns_from_inner_module()
+ {
+ TestContext test = new();
+
+ test.Module.trace_filter(new TraceFilterForRpc { FromBlock = new BlockParameter(1), ToBlock = new BlockParameter(1) })
+ .Should().BeEquivalentTo(ResultWrapper>.Success(test.NonDbTraces.SelectMany(ParityTxTraceFromStore.FromTxTrace)));
+ }
+
+ [Test]
+ public void trace_filter_returns_from_store()
+ {
+ TestContext test = new();
+
+ test.Module.trace_filter(new TraceFilterForRpc { FromBlock = BlockParameter.Latest, ToBlock = BlockParameter.Latest })
+ .Should().BeEquivalentTo(ResultWrapper>.Success(test.DbTraces.SelectMany(ParityTxTraceFromStore.FromTxTrace)));
+ }
+
+ private class TestContext
+ {
+ public ParityLikeTxTrace DbTrace { get; }
+ public ParityLikeTxTrace[] DbTraces { get; }
+ public ParityLikeTxTrace[] NonDbTraces { get; }
+ public ITraceRpcModule InnerModule { get; }
+ public MemDb Store { get; }
+ public IBlockFinder BlockFinder { get; }
+ public IReceiptFinder ReceiptFinder { get; }
+ public TraceStoreRpcModule Module { get; }
+
+ public TestContext()
+ {
+ InnerModule = Substitute.For();
+ Store = new MemDb();
+ BlockFinder = Build.A.BlockTree().OfChainLength(3).TestObject;
+ ReceiptFinder = Substitute.For();
+ ParityLikeTraceSerializer serializer = new(LimboLogs.Instance);
+ Module = new TraceStoreRpcModule(InnerModule, Store, BlockFinder, ReceiptFinder, serializer, LimboLogs.Instance);
+ Keccak dbTransaction = Build.A.Transaction.TestObject.Hash!;
+ Keccak dbBlock = BlockFinder.Head!.Hash!;
+ DbTrace = new() { BlockHash = dbBlock, TransactionHash = dbTransaction };
+ DbTraces = new[] { DbTrace };
+ Keccak nonDbTransaction = TestItem.KeccakA;
+ NonDbTraces = new[] { new ParityLikeTxTrace() { BlockHash = dbBlock, TransactionHash = nonDbTransaction } };
+ Store.Set(dbBlock, serializer.Serialize(DbTraces));
+ ReceiptFinder.FindBlockHash(dbTransaction).Returns(dbBlock);
+ ReceiptFinder.FindBlockHash(nonDbTransaction).Returns(dbBlock);
+
+ ResultWrapper nonDbReplayWrapper = ResultWrapper.Success(new(NonDbTraces[0]));
+ ResultWrapper> nonDbReplaysWrapper = ResultWrapper>.Success(NonDbTraces.Select(t => new ParityTxTraceFromReplay(t)));
+
+ InnerModule.trace_call(Arg.Any(), Arg.Any(), Arg.Any())
+ .Returns(nonDbReplayWrapper);
+
+ InnerModule.trace_callMany(Arg.Any(), Arg.Any())
+ .Returns(nonDbReplaysWrapper);
+
+ InnerModule.trace_rawTransaction(Arg.Any(), Arg.Any())
+ .Returns(nonDbReplayWrapper);
+
+ InnerModule.trace_replayTransaction(nonDbTransaction, Arg.Any())
+ .Returns(nonDbReplayWrapper);
+
+ InnerModule.trace_replayBlockTransactions(Arg.Any(), Arg.Any())
+ .Returns(nonDbReplaysWrapper);
+
+ ResultWrapper> nonDbFromStoreWrapper = ResultWrapper>.Success(NonDbTraces.SelectMany(ParityTxTraceFromStore.FromTxTrace));
+ InnerModule.trace_filter(Arg.Any())
+ .Returns(nonDbFromStoreWrapper);
+
+ InnerModule.trace_block(BlockParameter.Latest)
+ .Returns(nonDbFromStoreWrapper);
+
+ InnerModule.trace_get(nonDbTransaction, new[] { 0L })
+ .Returns(nonDbFromStoreWrapper);
+
+ InnerModule.trace_transaction(nonDbTransaction)
+ .Returns(nonDbFromStoreWrapper);
+
+ }
+ }
+}
diff --git a/src/Nethermind/Nethermind.JsonRpc.TraceStore.Tests/xdai-17600039.json b/src/Nethermind/Nethermind.JsonRpc.TraceStore.Tests/xdai-17600039.json
new file mode 100644
index 00000000000..3bdc7edef35
Binary files /dev/null and b/src/Nethermind/Nethermind.JsonRpc.TraceStore.Tests/xdai-17600039.json differ
diff --git a/src/Nethermind/Nethermind.JsonRpc.TraceStore/DbPersistingBlockTracer.cs b/src/Nethermind/Nethermind.JsonRpc.TraceStore/DbPersistingBlockTracer.cs
new file mode 100644
index 00000000000..af122fb5495
--- /dev/null
+++ b/src/Nethermind/Nethermind.JsonRpc.TraceStore/DbPersistingBlockTracer.cs
@@ -0,0 +1,72 @@
+// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited
+// SPDX-License-Identifier: LGPL-3.0-only
+
+using Nethermind.Core;
+using Nethermind.Core.Crypto;
+using Nethermind.Db;
+using Nethermind.Evm.Tracing;
+using Nethermind.Int256;
+using Nethermind.Logging;
+
+namespace Nethermind.JsonRpc.TraceStore;
+
+///
+/// Tracer that can store traces of decorated tracer in database
+///
+/// Trace type
+/// Transaction tracer type
+public class DbPersistingBlockTracer : IBlockTracer where TTracer : class, ITxTracer
+{
+ private readonly IDb _db;
+ private readonly ITraceSerializer _traceSerializer;
+ private readonly IBlockTracer _blockTracer;
+ private readonly BlockTracerBase _tracerWithResults;
+ private Keccak _currentBlockHash = null!;
+ private long _currentBlockNumber;
+ private readonly ILogger _logger;
+
+ ///
+ /// Creates the tracer
+ ///
+ /// Internal, actual tracer that does the tracing
+ /// Database
+ /// Serializer
+ ///
+ public DbPersistingBlockTracer(BlockTracerBase blockTracer,
+ IDb db,
+ ITraceSerializer traceSerializer,
+ ILogManager logManager)
+ {
+ _db = db;
+ _traceSerializer = traceSerializer;
+ _blockTracer = _tracerWithResults = blockTracer;
+ _logger = logManager.GetClassLogger>();
+ }
+
+ public bool IsTracingRewards => _blockTracer.IsTracingRewards;
+
+ public void ReportReward(Address author, string rewardType, UInt256 rewardValue) =>
+ _blockTracer.ReportReward(author, rewardType, rewardValue);
+
+ public void StartNewBlockTrace(Block block)
+ {
+ _currentBlockHash = block.Hash!;
+ _currentBlockNumber = block.Number;
+ _blockTracer.StartNewBlockTrace(block);
+ }
+
+ public ITxTracer StartNewTxTrace(Transaction? tx) => _blockTracer.StartNewTxTrace(tx);
+
+ public void EndTxTrace() => _blockTracer.EndTxTrace();
+
+ public void EndBlockTrace()
+ {
+ _blockTracer.EndBlockTrace();
+ IReadOnlyCollection result = _tracerWithResults.BuildResult();
+ byte[] tracesSerialized = _traceSerializer.Serialize(result);
+ Keccak currentBlockHash = _currentBlockHash;
+ long currentBlockNumber = _currentBlockNumber;
+ _db.Set(currentBlockHash, tracesSerialized);
+ if (_logger.IsTrace) _logger.Trace($"Saved traces for block {currentBlockNumber} ({currentBlockHash}) with size {tracesSerialized.Length} bytes for {result.Count} traces.");
+ }
+}
diff --git a/src/Nethermind/Nethermind.JsonRpc.TraceStore/ITraceSerializer.cs b/src/Nethermind/Nethermind.JsonRpc.TraceStore/ITraceSerializer.cs
new file mode 100644
index 00000000000..646376a0479
--- /dev/null
+++ b/src/Nethermind/Nethermind.JsonRpc.TraceStore/ITraceSerializer.cs
@@ -0,0 +1,13 @@
+// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited
+// SPDX-License-Identifier: LGPL-3.0-only
+
+using Nethermind.Evm.Tracing.ParityStyle;
+
+namespace Nethermind.JsonRpc.TraceStore;
+
+public interface ITraceSerializer
+{
+ unsafe List? Deserialize(Span serialized);
+ List? Deserialize(Stream serialized);
+ byte[] Serialize(IReadOnlyCollection traces);
+}
diff --git a/src/Nethermind/Nethermind.JsonRpc.TraceStore/ITraceStoreConfig.cs b/src/Nethermind/Nethermind.JsonRpc.TraceStore/ITraceStoreConfig.cs
new file mode 100644
index 00000000000..d2a81a9821d
--- /dev/null
+++ b/src/Nethermind/Nethermind.JsonRpc.TraceStore/ITraceStoreConfig.cs
@@ -0,0 +1,25 @@
+// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited
+// SPDX-License-Identifier: LGPL-3.0-only
+
+using Nethermind.Config;
+using Nethermind.Evm.Tracing.ParityStyle;
+
+namespace Nethermind.JsonRpc.TraceStore;
+
+public interface ITraceStoreConfig : IConfig
+{
+ [ConfigItem(Description = "Defines whether the TraceStore plugin is enabled, if 'true' traces will come from DB if possible.", DefaultValue = "false")]
+ public bool Enabled { get; set; }
+
+ [ConfigItem(Description = "Defines how many blocks counting from head are kept in the TraceStore, if '0' all traces of processed blocks will be kept.", DefaultValue = "10000")]
+ public int BlocksToKeep { get; set; }
+
+ [ConfigItem(Description = "Defines what kind of traces are saved and kept in TraceStore. Available options are: Trace, Rewards, VmTrace, StateDiff or just All.", DefaultValue = "Trace, Rewards")]
+ public ParityTraceTypes TraceTypes { get; set; }
+
+ [ConfigItem(Description = "Verifies all the serialized elements.", DefaultValue = "false", HiddenFromDocs = true)]
+ bool VerifySerialized { get; set; }
+
+ [ConfigItem(Description = "Depth to deserialize traces.", DefaultValue = "1024", HiddenFromDocs = true)]
+ int MaxDepth { get; set; }
+}
diff --git a/src/Nethermind/Nethermind.JsonRpc.TraceStore/Nethermind.JsonRpc.TraceStore.csproj b/src/Nethermind/Nethermind.JsonRpc.TraceStore/Nethermind.JsonRpc.TraceStore.csproj
new file mode 100644
index 00000000000..da0330aae89
--- /dev/null
+++ b/src/Nethermind/Nethermind.JsonRpc.TraceStore/Nethermind.JsonRpc.TraceStore.csproj
@@ -0,0 +1,14 @@
+
+
+
+ net6.0
+ enable
+ enable
+ true
+
+
+
+
+
+
+
diff --git a/src/Nethermind/Nethermind.JsonRpc.TraceStore/ParityLikeTraceSerializer.cs b/src/Nethermind/Nethermind.JsonRpc.TraceStore/ParityLikeTraceSerializer.cs
new file mode 100644
index 00000000000..806efddda33
--- /dev/null
+++ b/src/Nethermind/Nethermind.JsonRpc.TraceStore/ParityLikeTraceSerializer.cs
@@ -0,0 +1,79 @@
+// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited
+// SPDX-License-Identifier: LGPL-3.0-only
+
+using System.IO.Compression;
+using Nethermind.Core.Collections;
+using Nethermind.Evm.Tracing.ParityStyle;
+using Nethermind.JsonRpc.Modules.Trace;
+using Nethermind.Logging;
+using Nethermind.Serialization.Json;
+
+namespace Nethermind.JsonRpc.TraceStore;
+
+public class ParityLikeTraceSerializer : ITraceSerializer
+{
+ private static readonly byte[] _emptyBytes = { 0 };
+ private static readonly List _emptyTraces = new();
+
+ private readonly ILogger? _logger;
+ private readonly IJsonSerializer _jsonSerializer;
+ private readonly bool _verifySerialized;
+
+ public ParityLikeTraceSerializer(ILogManager logManager, int maxDepth = 1024, bool verifySerialized = false)
+ {
+ _jsonSerializer = new EthereumJsonSerializer(maxDepth, new ParityTraceActionCreationConverter());
+ _verifySerialized = verifySerialized;
+ _logger = logManager?.GetClassLogger();
+ }
+
+ public unsafe List? Deserialize(Span serialized)
+ {
+ if (serialized.Length == 1) return _emptyTraces;
+
+ fixed (byte* pBuffer = &serialized[0])
+ {
+ using UnmanagedMemoryStream input = new(pBuffer, serialized.Length);
+ return Deserialize(input);
+ }
+ }
+
+ public List? Deserialize(Stream serialized)
+ {
+ using GZipStream compressionStream = new(serialized, CompressionMode.Decompress);
+ return _jsonSerializer.Deserialize>(compressionStream);
+ }
+
+ public byte[] Serialize(IReadOnlyCollection traces)
+ {
+ if (traces.Count == 0) return _emptyBytes;
+
+ using MemoryStream output = new();
+ using (GZipStream compressionStream = new(output, CompressionMode.Compress))
+ {
+ _jsonSerializer.Serialize(compressionStream, traces);
+ }
+
+ byte[] result = output.ToArray();
+
+ // This is for testing
+ if (_verifySerialized)
+ {
+ Task.Run(() =>
+ {
+ try
+ {
+ Deserialize(result);
+ }
+ catch (Exception e)
+ {
+ ParityLikeTxTrace? trace = traces.FirstOrDefault();
+ string tracesWrittenToPath = Path.Combine(Path.GetTempPath(), $"{trace?.BlockNumber}-{trace?.BlockHash}.zip");
+ if (_logger?.IsError == true) _logger.Error($"Can't deserialize trace logs for block {trace?.BlockNumber} ({trace?.BlockHash}), size {result.Length}, dump: {tracesWrittenToPath}", e);
+ File.WriteAllBytes(tracesWrittenToPath, result);
+ }
+ });
+ }
+
+ return result;
+ }
+}
diff --git a/src/Nethermind/Nethermind.JsonRpc.TraceStore/ParityTraceActionCreationConverter.cs b/src/Nethermind/Nethermind.JsonRpc.TraceStore/ParityTraceActionCreationConverter.cs
new file mode 100644
index 00000000000..b5af77d7ac2
--- /dev/null
+++ b/src/Nethermind/Nethermind.JsonRpc.TraceStore/ParityTraceActionCreationConverter.cs
@@ -0,0 +1,12 @@
+// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited
+// SPDX-License-Identifier: LGPL-3.0-only
+
+using Nethermind.Evm.Tracing.ParityStyle;
+using Newtonsoft.Json.Converters;
+
+namespace Nethermind.JsonRpc.TraceStore;
+
+public class ParityTraceActionCreationConverter : CustomCreationConverter
+{
+ public override ParityTraceAction Create(Type objectType) => new() { Result = null };
+}
diff --git a/src/Nethermind/Nethermind.JsonRpc.TraceStore/TraceStoreConfig.cs b/src/Nethermind/Nethermind.JsonRpc.TraceStore/TraceStoreConfig.cs
new file mode 100644
index 00000000000..17cb9dafb8e
--- /dev/null
+++ b/src/Nethermind/Nethermind.JsonRpc.TraceStore/TraceStoreConfig.cs
@@ -0,0 +1,15 @@
+// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited
+// SPDX-License-Identifier: LGPL-3.0-only
+
+using Nethermind.Evm.Tracing.ParityStyle;
+
+namespace Nethermind.JsonRpc.TraceStore;
+
+public class TraceStoreConfig : ITraceStoreConfig
+{
+ public bool Enabled { get; set; }
+ public int BlocksToKeep { get; set; } = 10000;
+ public ParityTraceTypes TraceTypes { get; set; } = ParityTraceTypes.Trace | ParityTraceTypes.Rewards;
+ public bool VerifySerialized { get; set; } = false;
+ public int MaxDepth { get; set; } = 1024;
+}
diff --git a/src/Nethermind/Nethermind.JsonRpc.TraceStore/TraceStoreModuleFactory.cs b/src/Nethermind/Nethermind.JsonRpc.TraceStore/TraceStoreModuleFactory.cs
new file mode 100644
index 00000000000..408878a85c7
--- /dev/null
+++ b/src/Nethermind/Nethermind.JsonRpc.TraceStore/TraceStoreModuleFactory.cs
@@ -0,0 +1,40 @@
+// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited
+// SPDX-License-Identifier: LGPL-3.0-only
+
+using Nethermind.Blockchain.Find;
+using Nethermind.Blockchain.Receipts;
+using Nethermind.Db;
+using Nethermind.Evm.Tracing.ParityStyle;
+using Nethermind.JsonRpc.Modules;
+using Nethermind.JsonRpc.Modules.Trace;
+using Nethermind.Logging;
+
+namespace Nethermind.JsonRpc.TraceStore;
+
+public class TraceStoreModuleFactory : ModuleFactoryBase
+{
+ private readonly IRpcModuleFactory _innerFactory;
+ private readonly IDbWithSpan _traceStore;
+ private readonly IBlockFinder _blockFinder;
+ private readonly IReceiptFinder _receiptFinder;
+ private readonly ITraceSerializer _traceSerializer;
+ private readonly ILogManager _logManager;
+
+ public TraceStoreModuleFactory(
+ IRpcModuleFactory innerFactory,
+ IDbWithSpan traceStore,
+ IBlockFinder blockFinder,
+ IReceiptFinder receiptFinder,
+ ITraceSerializer traceSerializer,
+ ILogManager logManager)
+ {
+ _innerFactory = innerFactory;
+ _traceStore = traceStore;
+ _blockFinder = blockFinder;
+ _receiptFinder = receiptFinder;
+ _traceSerializer = traceSerializer;
+ _logManager = logManager;
+ }
+
+ public override ITraceRpcModule Create() => new TraceStoreRpcModule(_innerFactory.Create(), _traceStore, _blockFinder, _receiptFinder, _traceSerializer, _logManager);
+}
diff --git a/src/Nethermind/Nethermind.JsonRpc.TraceStore/TraceStorePlugin.cs b/src/Nethermind/Nethermind.JsonRpc.TraceStore/TraceStorePlugin.cs
new file mode 100644
index 00000000000..acfd0351b20
--- /dev/null
+++ b/src/Nethermind/Nethermind.JsonRpc.TraceStore/TraceStorePlugin.cs
@@ -0,0 +1,102 @@
+// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited
+// SPDX-License-Identifier: LGPL-3.0-only
+
+using System.Text.Json;
+using FastEnumUtility;
+using Nethermind.Api;
+using Nethermind.Api.Extensions;
+using Nethermind.Blockchain.Find;
+using Nethermind.Db;
+using Nethermind.Evm.Tracing.ParityStyle;
+using Nethermind.JsonRpc.Modules;
+using Nethermind.JsonRpc.Modules.Trace;
+using Nethermind.Logging;
+
+namespace Nethermind.JsonRpc.TraceStore;
+
+public class TraceStorePlugin : INethermindPlugin
+{
+ private const string DbName = "TraceStore";
+ private INethermindApi _api = null!;
+ private ITraceStoreConfig _config = null!;
+ private IJsonRpcConfig _jsonRpcConfig = null!;
+ private IDbWithSpan? _db;
+ private TraceStorePruner? _pruner;
+ private ILogManager _logManager = null!;
+ private ILogger _logger = null!;
+ private ITraceSerializer? _traceSerializer;
+ public string Name => DbName;
+ public string Description => "Allows to serve traces without the block state, by saving historical traces to DB.";
+ public string Author => "Nethermind";
+ private bool Enabled => _config.Enabled;
+
+ public Task Init(INethermindApi nethermindApi)
+ {
+ _api = nethermindApi;
+ _logManager = _api.LogManager;
+ _config = _api.Config();
+ _jsonRpcConfig = _api.Config();
+ _logger = _logManager.GetClassLogger();
+
+ if (Enabled)
+ {
+ // Setup serialization
+ _traceSerializer = new ParityLikeTraceSerializer(_logManager, _config.MaxDepth, _config.VerifySerialized);
+
+ // Setup DB
+ _db = (IDbWithSpan)_api.RocksDbFactory!.CreateDb(new RocksDbSettings(DbName, DbName.ToLower()));
+ _api.DbProvider!.RegisterDb(DbName, _db);
+
+ //Setup pruning if configured
+ if (_config.BlocksToKeep != 0)
+ {
+ _pruner = new TraceStorePruner(_api.BlockTree!, _db, _config.BlocksToKeep, _logManager);
+ }
+ }
+
+ return Task.CompletedTask;
+ }
+
+ public Task InitNetworkProtocol()
+ {
+ if (Enabled)
+ {
+ if (_logger.IsInfo) _logger.Info($"Starting TraceStore with {_config.TraceTypes} traces.");
+
+ // Setup tracing
+ ParityLikeBlockTracer parityTracer = new(_config.TraceTypes);
+ DbPersistingBlockTracer dbPersistingTracer =
+ new(parityTracer, _db!, _traceSerializer!, _logManager);
+ _api.BlockchainProcessor!.Tracers.Add(dbPersistingTracer);
+ }
+
+ // Potentially we could add protocol for syncing traces.
+ return Task.CompletedTask;
+ }
+
+ public Task InitRpcModules()
+ {
+ if (Enabled && _jsonRpcConfig.Enabled)
+ {
+ IRpcModuleProvider apiRpcModuleProvider = _api.RpcModuleProvider!;
+ if (apiRpcModuleProvider.GetPool(ModuleType.Trace) is IRpcModulePool traceModulePool)
+ {
+ TraceStoreModuleFactory traceModuleFactory = new(traceModulePool.Factory, _db!, _api.BlockTree!, _api.ReceiptFinder!, _traceSerializer!, _logManager);
+ apiRpcModuleProvider.RegisterBoundedByCpuCount(traceModuleFactory, _jsonRpcConfig.Timeout);
+ }
+ }
+
+ return Task.CompletedTask;
+ }
+
+ public ValueTask DisposeAsync()
+ {
+ if (Enabled)
+ {
+ _pruner?.Dispose();
+ _db?.Dispose();
+ }
+
+ return default;
+ }
+}
diff --git a/src/Nethermind/Nethermind.JsonRpc.TraceStore/TraceStorePruner.cs b/src/Nethermind/Nethermind.JsonRpc.TraceStore/TraceStorePruner.cs
new file mode 100644
index 00000000000..ce4091abf40
--- /dev/null
+++ b/src/Nethermind/Nethermind.JsonRpc.TraceStore/TraceStorePruner.cs
@@ -0,0 +1,56 @@
+// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited
+// SPDX-License-Identifier: LGPL-3.0-only
+
+using Nethermind.Blockchain;
+using Nethermind.Core;
+using Nethermind.Db;
+using Nethermind.Logging;
+
+namespace Nethermind.JsonRpc.TraceStore;
+
+///
+/// Prunes tracing history
+///
+public class TraceStorePruner : IDisposable
+{
+ private readonly IBlockTree _blockTree;
+ private readonly IDb _db;
+ private readonly int _blockToKeep;
+ private readonly ILogger _logger;
+
+ public TraceStorePruner(IBlockTree blockTree, IDb db, int blockToKeep, ILogManager logManager)
+ {
+ _blockTree = blockTree;
+ _db = db;
+ _blockToKeep = blockToKeep;
+ _logger = logManager.GetClassLogger();
+ _blockTree.BlockAddedToMain += OnBlockAddedToMain;
+ if (_logger.IsDebug) _logger.Debug($"TraceStore pruning is enabled, keeping last {blockToKeep} blocks.");
+ }
+
+ private void OnBlockAddedToMain(object? sender, BlockReplacementEventArgs e)
+ {
+ Task.Run((() =>
+ {
+ long levelToDelete = e.Block.Number - _blockToKeep;
+ if (levelToDelete > 0)
+ {
+ ChainLevelInfo? level = _blockTree.FindLevel(levelToDelete);
+ if (level is not null)
+ {
+ for (int i = 0; i < level.BlockInfos.Length; i++)
+ {
+ BlockInfo blockInfo = level.BlockInfos[i];
+ if (_logger.IsTrace) _logger.Trace($"Removing traces from TraceStore on level {levelToDelete} for block {blockInfo}.");
+ _db.Delete(blockInfo.BlockHash);
+ }
+ }
+ }
+ }));
+ }
+
+ public void Dispose()
+ {
+ _blockTree.BlockAddedToMain -= OnBlockAddedToMain;
+ }
+}
diff --git a/src/Nethermind/Nethermind.JsonRpc.TraceStore/TraceStoreRpcModule.cs b/src/Nethermind/Nethermind.JsonRpc.TraceStore/TraceStoreRpcModule.cs
new file mode 100644
index 00000000000..6bc6ee1e54b
--- /dev/null
+++ b/src/Nethermind/Nethermind.JsonRpc.TraceStore/TraceStoreRpcModule.cs
@@ -0,0 +1,311 @@
+// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited
+// SPDX-License-Identifier: LGPL-3.0-only
+
+using System.Text.Json;
+using Nethermind.Blockchain.Find;
+using Nethermind.Blockchain.Receipts;
+using Nethermind.Core;
+using Nethermind.Core.Crypto;
+using Nethermind.Db;
+using Nethermind.Evm.Tracing.ParityStyle;
+using Nethermind.JsonRpc.Data;
+using Nethermind.JsonRpc.Modules;
+using Nethermind.JsonRpc.Modules.Trace;
+using Nethermind.Logging;
+
+namespace Nethermind.JsonRpc.TraceStore;
+
+///
+/// Module for tracing using database
+///
+public class TraceStoreRpcModule : ITraceRpcModule
+{
+ private readonly IDbWithSpan _traceStore;
+ private readonly ITraceRpcModule _traceModule;
+ private readonly IBlockFinder _blockFinder;
+ private readonly IReceiptFinder _receiptFinder;
+ private readonly ITraceSerializer _traceSerializer;
+ private readonly ILogger _logger;
+
+ private static readonly IDictionary> _filters = new Dictionary>
+ {
+ { ParityTraceTypes.Trace, FilterTrace },
+ { ParityTraceTypes.StateDiff , FilterStateDiff },
+ { ParityTraceTypes.VmTrace | ParityTraceTypes.Trace, FilterStateVmTrace }
+ };
+
+ public TraceStoreRpcModule(
+ ITraceRpcModule traceModule,
+ IDbWithSpan traceStore,
+ IBlockFinder blockFinder,
+ IReceiptFinder receiptFinder,
+ ITraceSerializer traceSerializer,
+ ILogManager logManager)
+ {
+ _traceStore = traceStore;
+ _traceModule = traceModule;
+ _blockFinder = blockFinder;
+ _receiptFinder = receiptFinder;
+ _traceSerializer = traceSerializer;
+ _logger = logManager.GetClassLogger();
+ }
+
+ public ResultWrapper trace_call(TransactionForRpc call, string[] traceTypes, BlockParameter? blockParameter = null) =>
+ _traceModule.trace_call(call, traceTypes, blockParameter);
+
+ public ResultWrapper> trace_callMany(TransactionForRpcWithTraceTypes[] calls, BlockParameter? blockParameter = null) =>
+ _traceModule.trace_callMany(calls, blockParameter);
+
+ public ResultWrapper trace_rawTransaction(byte[] data, string[] traceTypes) =>
+ _traceModule.trace_rawTransaction(data, traceTypes);
+
+ public ResultWrapper trace_replayTransaction(Keccak txHash, params string[] traceTypes) =>
+ TryTraceTransaction(
+ txHash,
+ TraceRpcModule.GetParityTypes(traceTypes),
+ static t => new ParityTxTraceFromReplay(t),
+ out ResultWrapper? result)
+ && result is not null
+ ? result
+ : _traceModule.trace_replayTransaction(txHash, traceTypes);
+
+ public ResultWrapper> trace_replayBlockTransactions(BlockParameter blockParameter, string[] traceTypes)
+ {
+ SearchResult blockSearch = _blockFinder.SearchForHeader(blockParameter);
+ if (blockSearch.IsError)
+ {
+ return ResultWrapper>.Fail(blockSearch);
+ }
+
+ BlockHeader block = blockSearch.Object!;
+
+ if (TryGetBlockTraces(block, out List? traces) && traces is not null)
+ {
+ FilterTraces(traces, TraceRpcModule.GetParityTypes(traceTypes));
+ return ResultWrapper>.Success(traces.Select(t => new ParityTxTraceFromReplay(t, true)));
+ }
+
+ return _traceModule.trace_replayBlockTransactions(blockParameter, traceTypes);
+ }
+
+ public ResultWrapper> trace_filter(TraceFilterForRpc traceFilterForRpc)
+ {
+ IEnumerable> blocksSearch = _blockFinder.SearchForBlocksOnMainChain(
+ traceFilterForRpc.FromBlock ?? BlockParameter.Latest,
+ traceFilterForRpc.ToBlock ?? BlockParameter.Latest);
+
+ SearchResult? error = null;
+ bool missingTraces = false;
+
+ IEnumerable txTraces = blocksSearch.AsParallel()
+ .AsOrdered()
+ .SelectMany(blockSearch =>
+ {
+ if (blockSearch.IsError)
+ {
+ error = blockSearch;
+ return Enumerable.Empty();
+ }
+
+ Block block = blockSearch.Object!;
+ if (TryGetBlockTraces(block.Header, out List? traces) && traces is not null)
+ {
+ return traces.SelectMany(ParityTxTraceFromStore.FromTxTrace);
+ }
+ else
+ {
+ missingTraces = true;
+ return Enumerable.Empty();
+ }
+ });
+
+ if (error is not null)
+ {
+ return ResultWrapper>.Fail(error.Value);
+ }
+ else if (missingTraces)
+ {
+ // fallback when we miss any traces in db
+ return _traceModule.trace_filter(traceFilterForRpc);
+ }
+ else
+ {
+ TxTraceFilter txTracerFilter = new(traceFilterForRpc.FromAddress, traceFilterForRpc.ToAddress, traceFilterForRpc.After, traceFilterForRpc.Count);
+ return ResultWrapper>.Success(txTracerFilter.FilterTxTraces(txTraces));
+ }
+ }
+
+ public ResultWrapper> trace_block(BlockParameter blockParameter)
+ {
+ SearchResult blockSearch = _blockFinder.SearchForHeader(blockParameter);
+ if (blockSearch.IsError)
+ {
+ return ResultWrapper>.Fail(blockSearch);
+ }
+
+ BlockHeader block = blockSearch.Object!;
+ if (TryGetBlockTraces(block, out List? traces) && traces is not null)
+ {
+ return ResultWrapper>.Success(traces.SelectMany(ParityTxTraceFromStore.FromTxTrace));
+ }
+
+ return _traceModule.trace_block(blockParameter);
+ }
+
+ public ResultWrapper> trace_get(Keccak txHash, long[] positions)
+ {
+ ResultWrapper> traceTransaction = trace_transaction(txHash);
+ List traces = TraceRpcModule.ExtractPositionsFromTxTrace(positions, traceTransaction);
+ return ResultWrapper>.Success(traces);
+ }
+
+ public ResultWrapper> trace_transaction(Keccak txHash) =>
+ TryTraceTransaction(
+ txHash,
+ ParityTraceTypes.Trace,
+ static t => ParityTxTraceFromStore.FromTxTrace(t),
+ out ResultWrapper>? result)
+ && result is not null
+ ? result
+ : _traceModule.trace_transaction(txHash);
+
+ private bool TryTraceTransaction(
+ Keccak txHash,
+ ParityTraceTypes traceTypes,
+ Func map,
+ out ResultWrapper? result)
+ {
+ SearchResult blockHashSearch = _receiptFinder.SearchForReceiptBlockHash(txHash);
+ if (blockHashSearch.IsError)
+ {
+ {
+ result = ResultWrapper.Fail(blockHashSearch);
+ return true;
+ }
+ }
+
+ SearchResult blockSearch = _blockFinder.SearchForBlock(new BlockParameter(blockHashSearch.Object!));
+ if (blockSearch.IsError)
+ {
+ {
+ result = ResultWrapper.Fail(blockSearch);
+ return true;
+ }
+ }
+
+ Block block = blockSearch.Object!;
+
+ if (TryGetBlockTraces(block.Header, out List? traces) && traces is not null)
+ {
+ ParityLikeTxTrace? trace = GetTxTrace(block, txHash, traces);
+ if (trace is not null)
+ {
+ FilterTrace(trace, traceTypes);
+ result = ResultWrapper.Success(map(trace));
+ return true;
+ }
+ }
+
+ result = null;
+ return false;
+ }
+
+ private bool TryGetBlockTraces(BlockHeader block, out List? traces)
+ {
+ Span tracesSerialized = _traceStore.GetSpan(block.Hash!);
+ try
+ {
+ if (!tracesSerialized.IsEmpty)
+ {
+ List? tracesDeserialized = _traceSerializer.Deserialize(tracesSerialized);
+ if (tracesDeserialized is not null)
+ {
+ if (_logger.IsTrace) _logger.Trace($"Found persisted traces for block {block.ToString(BlockHeader.Format.FullHashAndNumber)}");
+ traces = tracesDeserialized;
+ return true;
+ }
+ }
+
+ traces = null;
+ return false;
+ }
+ finally
+ {
+ _traceStore.DangerousReleaseMemory(tracesSerialized);
+ }
+ }
+
+ private ParityLikeTxTrace? GetTxTrace(Block block, Keccak txHash, List traces)
+ {
+ int index = traces.FindIndex(t => t.TransactionHash == txHash);
+ return index != -1 ? traces[index] : null;
+ }
+
+ private void FilterTraces(List traces, ParityTraceTypes traceTypes)
+ {
+ for (int i = 0; i < traces.Count; i++)
+ {
+ ParityLikeTxTrace parityLikeTxTrace = traces[i];
+ FilterTrace(parityLikeTxTrace, traceTypes);
+ }
+
+ if ((traceTypes & ParityTraceTypes.Rewards) == 0)
+ {
+ FilterRewards(traces);
+ }
+ }
+
+ private static void FilterTrace(ParityLikeTxTrace parityLikeTxTrace, ParityTraceTypes traceTypes)
+ {
+ foreach (KeyValuePair> filter in _filters)
+ {
+ if ((traceTypes & filter.Key) == 0)
+ {
+ filter.Value(parityLikeTxTrace);
+ }
+ }
+ }
+
+
+ // VmTrace uses flags IsTracingCode, IsTracingInstructions
+ private static void FilterStateVmTrace(ParityLikeTxTrace trace)
+ {
+ trace.VmTrace = null;
+ }
+
+ // StateDiff uses flags IsTracingState, IsTracingStorage
+ private static void FilterStateDiff(ParityLikeTxTrace trace)
+ {
+ trace.StateChanges = null;
+ if (trace.VmTrace is not null)
+ {
+ for (int i = 0; i < trace.VmTrace.Operations.Length; i++)
+ {
+ trace.VmTrace.Operations[i].Store = null!;
+ }
+ }
+ }
+
+ // Trace uses flags IsTracingActions, IsTracingReceipt
+ private static void FilterTrace(ParityLikeTxTrace trace)
+ {
+ trace.Output = null;
+ // trace action?
+ }
+
+ private static void FilterRewards(List traces)
+ {
+ for (int i = traces.Count - 1; i >= 0; i--)
+ {
+ ParityLikeTxTrace trace = traces[i];
+ if (trace.TransactionHash is null && trace.Action?.Type == "reward")
+ {
+ traces.RemoveAt(i);
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+}
diff --git a/src/Nethermind/Nethermind.JsonRpc/JsonRpcService.cs b/src/Nethermind/Nethermind.JsonRpc/JsonRpcService.cs
index 8b9bc8ddfe2..15a6593d82c 100644
--- a/src/Nethermind/Nethermind.JsonRpc/JsonRpcService.cs
+++ b/src/Nethermind/Nethermind.JsonRpc/JsonRpcService.cs
@@ -197,11 +197,11 @@ private async Task ExecuteAsync(JsonRpcRequest request, string
}
catch (TargetParameterCountException e)
{
- return GetErrorResponse(methodName, ErrorCodes.InvalidParams, e.Message, e.Data, request.Id, returnAction);
+ return GetErrorResponse(methodName, ErrorCodes.InvalidParams, e.Message, e.ToString(), request.Id, returnAction);
}
catch (TargetInvocationException e) when (e.InnerException is JsonException)
{
- return GetErrorResponse(methodName, ErrorCodes.InvalidParams, "Invalid params", null, request.Id, returnAction);
+ return GetErrorResponse(methodName, ErrorCodes.InvalidParams, "Invalid params", e.InnerException?.ToString(), request.Id, returnAction);
}
catch (Exception e) when (e.InnerException is OperationCanceledException)
{
@@ -210,7 +210,7 @@ private async Task ExecuteAsync(JsonRpcRequest request, string
}
catch (Exception e) when (e.InnerException is InsufficientBalanceException)
{
- return GetErrorResponse(methodName, ErrorCodes.InvalidInput, e.InnerException.Message, null, request.Id, returnAction);
+ return GetErrorResponse(methodName, ErrorCodes.InvalidInput, e.InnerException.Message, e.ToString(), request.Id, returnAction);
}
finally
{
@@ -399,7 +399,7 @@ public JsonRpcErrorResponse GetErrorResponse(int errorCode, string errorMessage)
private JsonRpcErrorResponse GetErrorResponse(string? methodName, int errorCode, string? errorMessage, object? errorData, object? id, Action? disposableAction = null)
{
- if (_logger.IsDebug) _logger.Debug($"Sending error response, method: {methodName ?? "none"}, id: {id}, errorType: {errorCode}, message: {errorMessage}");
+ if (_logger.IsDebug) _logger.Debug($"Sending error response, method: {methodName ?? "none"}, id: {id}, errorType: {errorCode}, message: {errorMessage}, errorData: {errorData}");
JsonRpcErrorResponse response = new(disposableAction)
{
Error = new Error
diff --git a/src/Nethermind/Nethermind.JsonRpc/Modules/BoundedModulePool.cs b/src/Nethermind/Nethermind.JsonRpc/Modules/BoundedModulePool.cs
index fd912488f44..0d02062c663 100644
--- a/src/Nethermind/Nethermind.JsonRpc/Modules/BoundedModulePool.cs
+++ b/src/Nethermind/Nethermind.JsonRpc/Modules/BoundedModulePool.cs
@@ -55,6 +55,6 @@ public void ReturnModule(T module)
_semaphore.Release();
}
- public IRpcModuleFactory Factory { get; set; }
+ public IRpcModuleFactory Factory { get; }
}
}
diff --git a/src/Nethermind/Nethermind.JsonRpc/Modules/IRpcModulePool.cs b/src/Nethermind/Nethermind.JsonRpc/Modules/IRpcModulePool.cs
index 914d85074ff..4776aab783c 100644
--- a/src/Nethermind/Nethermind.JsonRpc/Modules/IRpcModulePool.cs
+++ b/src/Nethermind/Nethermind.JsonRpc/Modules/IRpcModulePool.cs
@@ -1,16 +1,21 @@
// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited
// SPDX-License-Identifier: LGPL-3.0-only
+using System.Threading;
using System.Threading.Tasks;
namespace Nethermind.JsonRpc.Modules
{
- public interface IRpcModulePool where T : IRpcModule
+ public interface IRpcModulePool
+ {
+ }
+
+ public interface IRpcModulePool : IRpcModulePool where T : IRpcModule
{
Task GetModule(bool canBeShared);
void ReturnModule(T module);
- IRpcModuleFactory Factory { get; set; }
+ IRpcModuleFactory Factory { get; }
}
}
diff --git a/src/Nethermind/Nethermind.JsonRpc/Modules/IRpcModuleProvider.cs b/src/Nethermind/Nethermind.JsonRpc/Modules/IRpcModuleProvider.cs
index 3980a68b0e5..6fca4c8b045 100644
--- a/src/Nethermind/Nethermind.JsonRpc/Modules/IRpcModuleProvider.cs
+++ b/src/Nethermind/Nethermind.JsonRpc/Modules/IRpcModuleProvider.cs
@@ -28,5 +28,7 @@ public interface IRpcModuleProvider
Task Rent(string methodName, bool canBeShared);
void Return(string methodName, IRpcModule rpcModule);
+
+ IRpcModulePool? GetPool(string moduleType);
}
}
diff --git a/src/Nethermind/Nethermind.JsonRpc/Modules/NullModuleProvider.cs b/src/Nethermind/Nethermind.JsonRpc/Modules/NullModuleProvider.cs
index bc89edd8b61..c0c2b2e05f4 100644
--- a/src/Nethermind/Nethermind.JsonRpc/Modules/NullModuleProvider.cs
+++ b/src/Nethermind/Nethermind.JsonRpc/Modules/NullModuleProvider.cs
@@ -30,23 +30,14 @@ public void Register(IRpcModulePool pool) where T : IRpcModule
public IReadOnlyCollection All => Array.Empty();
- public ModuleResolution Check(string methodName, JsonRpcContext context)
- {
- return ModuleResolution.Unknown;
- }
+ public ModuleResolution Check(string methodName, JsonRpcContext context) => ModuleResolution.Unknown;
- public (MethodInfo, bool) Resolve(string methodName)
- {
- return (null, false);
- }
+ public (MethodInfo, bool) Resolve(string methodName) => (null, false);
- public Task Rent(string methodName, bool canBeShared)
- {
- return Null;
- }
+ public Task Rent(string methodName, bool canBeShared) => Null;
- public void Return(string methodName, IRpcModule rpcModule)
- {
- }
+ public void Return(string methodName, IRpcModule rpcModule) { }
+
+ public IRpcModulePool? GetPool(string moduleType) => null;
}
}
diff --git a/src/Nethermind/Nethermind.JsonRpc/Modules/RpcModuleProvider.cs b/src/Nethermind/Nethermind.JsonRpc/Modules/RpcModuleProvider.cs
index bbee59e9876..3e6e8ff890b 100644
--- a/src/Nethermind/Nethermind.JsonRpc/Modules/RpcModuleProvider.cs
+++ b/src/Nethermind/Nethermind.JsonRpc/Modules/RpcModuleProvider.cs
@@ -18,14 +18,11 @@ public class RpcModuleProvider : IRpcModuleProvider
private readonly ILogger _logger;
private readonly IJsonRpcConfig _jsonRpcConfig;
- private readonly List _modules = new();
- private readonly List _enabledModules = new();
+ private readonly HashSet _modules = new(StringComparer.InvariantCultureIgnoreCase);
+ private readonly HashSet _enabledModules = new(StringComparer.InvariantCultureIgnoreCase);
+ private readonly Dictionary _methods = new(StringComparer.InvariantCulture);
- private readonly Dictionary _methods
- = new(StringComparer.InvariantCulture);
-
- private readonly Dictionary> RentModule, Action ReturnModule)> _pools
- = new();
+ private readonly Dictionary> RentModule, Action ReturnModule, IRpcModulePool ModulePool)> _pools = new();
private readonly IRpcMethodFilter _filter = NullRpcMethodFilter.Instance;
@@ -53,14 +50,13 @@ public void Register(IRpcModulePool pool) where T : IRpcModule
RpcModuleAttribute attribute = typeof(T).GetCustomAttribute();
if (attribute is null)
{
- if (_logger.IsWarn) _logger.Warn(
- $"Cannot register {typeof(T).Name} as a JSON RPC module because it does not have a {nameof(RpcModuleAttribute)} applied.");
+ if (_logger.IsWarn) _logger.Warn($"Cannot register {typeof(T).Name} as a JSON RPC module because it does not have a {nameof(RpcModuleAttribute)} applied.");
return;
}
string moduleType = attribute.ModuleType;
- _pools[moduleType] = (async canBeShared => await pool.GetModule(canBeShared), m => pool.ReturnModule((T)m));
+ _pools[moduleType] = (async canBeShared => await pool.GetModule(canBeShared), m => pool.ReturnModule((T)m), pool);
_modules.Add(moduleType);
IReadOnlyCollection poolConverters = pool.Factory.GetConverters();
@@ -117,6 +113,8 @@ public void Return(string methodName, IRpcModule rpcModule)
_pools[result.ModuleType].ReturnModule(rpcModule);
}
+ public IRpcModulePool? GetPool(string moduleType) => _pools.TryGetValue(moduleType, out var poolInfo) ? poolInfo.ModulePool : null;
+
private IDictionary GetMethodDict(Type type)
{
var methods = type.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
diff --git a/src/Nethermind/Nethermind.JsonRpc/Modules/SingletonModulePool.cs b/src/Nethermind/Nethermind.JsonRpc/Modules/SingletonModulePool.cs
index c4d40ec5349..ddef5fb9248 100644
--- a/src/Nethermind/Nethermind.JsonRpc/Modules/SingletonModulePool.cs
+++ b/src/Nethermind/Nethermind.JsonRpc/Modules/SingletonModulePool.cs
@@ -37,6 +37,6 @@ public void ReturnModule(T module)
{
}
- public IRpcModuleFactory Factory { get; set; }
+ public IRpcModuleFactory Factory { get; }
}
}
diff --git a/src/Nethermind/Nethermind.JsonRpc/Modules/Subscribe/SubscribeRpcModule.cs b/src/Nethermind/Nethermind.JsonRpc/Modules/Subscribe/SubscribeRpcModule.cs
index 98592b4b3fd..87c723e8c01 100644
--- a/src/Nethermind/Nethermind.JsonRpc/Modules/Subscribe/SubscribeRpcModule.cs
+++ b/src/Nethermind/Nethermind.JsonRpc/Modules/Subscribe/SubscribeRpcModule.cs
@@ -1,8 +1,9 @@
// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited
-// SPDX-License-Identifier: LGPL-3.0-only
+// SPDX-License-Identifier: LGPL-3.0-only
using System;
using System.Collections.Generic;
+using Newtonsoft.Json;
namespace Nethermind.JsonRpc.Modules.Subscribe
{
@@ -30,6 +31,10 @@ public ResultWrapper eth_subscribe(string subscriptionName, string? args
{
return ResultWrapper.Fail($"Invalid params", ErrorCodes.InvalidParams, e.Message);
}
+ catch (JsonReaderException)
+ {
+ return ResultWrapper.Fail($"Invalid params", ErrorCodes.InvalidParams);
+ }
}
public ResultWrapper eth_unsubscribe(string subscriptionId)
diff --git a/src/Nethermind/Nethermind.JsonRpc/Modules/Trace/ITraceRpcModule.cs b/src/Nethermind/Nethermind.JsonRpc/Modules/Trace/ITraceRpcModule.cs
index b6b06f3753a..5fafb6b8e91 100644
--- a/src/Nethermind/Nethermind.JsonRpc/Modules/Trace/ITraceRpcModule.cs
+++ b/src/Nethermind/Nethermind.JsonRpc/Modules/Trace/ITraceRpcModule.cs
@@ -31,7 +31,7 @@ public interface ITraceRpcModule : IRpcModule
ResultWrapper trace_replayTransaction([JsonRpcParameter(ExampleValue = "[\"0x203abf19610ce15bc509d4b341e907ff8c5a8287ae61186fd4da82146408c28c\",[\"trace\"]]")] Keccak txHash, string[] traceTypes);
[JsonRpcMethod(Description = "", IsImplemented = true, IsSharable = false, ExampleResponse = "[{\"output\":\"0x0000000000000000000000000000000000000000000000000000000000000001\",\"stateDiff\":null,\"trace\":[{\"action\":{\"callType\":\"call\",\"from\":\"0x37f207b3ebda37de11ad2b6d306464e313c4841a\",\"gas\":\"0x3c36\",\"input\":\"0xa9059cbb000000000000000000000000d20d2f4c0b595abedef821a4157b0b990a37dae60000000000000000000000000000000000000000000000008ac7230489e80000\",\"to\":\"0x59a524d1f5dcbde3224fd42171795283596a8103\",\"value\":\"0x0\"},\"result\":{\"gasUsed\":\"0x3c36\",\"output\":\"0x0000000000000000000000000000000000000000000000000000000000000001\"},\"subtraces\":0,\"traceAddress\":[],\"type\":\"call\"}],\"transactionHash\":\"0x17dc0fef36bb997c79ee2a0a126d059227000a2d47c9bbd1f49b5902a4e7385a\",\"vmTrace\":null}, (...)]")]
- ResultWrapper> trace_replayBlockTransactions([JsonRpcParameter(ExampleValue = "[\"0x88df42\",[\"trace\"]]")] BlockParameter numberOrTag, string[] traceTypes);
+ ResultWrapper> trace_replayBlockTransactions([JsonRpcParameter(ExampleValue = "[\"0x88df42\",[\"trace\"]]")] BlockParameter blockParameter, string[] traceTypes);
[JsonRpcMethod(Description = "", IsImplemented = true, IsSharable = false)]
ResultWrapper> trace_filter(TraceFilterForRpc traceFilterForRpc);
diff --git a/src/Nethermind/Nethermind.JsonRpc/Modules/Trace/ParityTxTraceFromReplay.cs b/src/Nethermind/Nethermind.JsonRpc/Modules/Trace/ParityTxTraceFromReplay.cs
index 5d139219586..efe90ca8b37 100644
--- a/src/Nethermind/Nethermind.JsonRpc/Modules/Trace/ParityTxTraceFromReplay.cs
+++ b/src/Nethermind/Nethermind.JsonRpc/Modules/Trace/ParityTxTraceFromReplay.cs
@@ -33,17 +33,16 @@ public ParityTxTraceFromReplay(IReadOnlyCollection txTraces,
StateChanges = txTrace.StateChanges;
TransactionHash = includeTransactionHash ? txTrace.TransactionHash : null;
}
-
}
- public byte[] Output { get; set; }
+ public byte[]? Output { get; set; }
- public Keccak TransactionHash { get; set; }
+ public Keccak? TransactionHash { get; set; }
- public ParityVmTrace VmTrace { get; set; }
+ public ParityVmTrace? VmTrace { get; set; }
- public ParityTraceAction Action { get; set; }
+ public ParityTraceAction? Action { get; set; }
- public Dictionary StateChanges { get; set; }
+ public Dictionary? StateChanges { get; set; }
}
}
diff --git a/src/Nethermind/Nethermind.JsonRpc/Modules/Trace/ParityTxTraceFromStore.cs b/src/Nethermind/Nethermind.JsonRpc/Modules/Trace/ParityTxTraceFromStore.cs
index c85353106fc..bcdd827a40d 100644
--- a/src/Nethermind/Nethermind.JsonRpc/Modules/Trace/ParityTxTraceFromStore.cs
+++ b/src/Nethermind/Nethermind.JsonRpc/Modules/Trace/ParityTxTraceFromStore.cs
@@ -11,45 +11,50 @@ namespace Nethermind.JsonRpc.Modules.Trace
{
public class ParityTxTraceFromStore
{
- public static ParityTxTraceFromStore[] FromTxTrace(ParityLikeTxTrace txTrace)
+ public static IEnumerable FromTxTrace(ParityLikeTxTrace txTrace)
{
- List results = new();
- AddActionsRecursively(results, txTrace, txTrace.Action);
- return results.ToArray();
+ return ReturnActionsRecursively(txTrace, txTrace.Action);
}
public static IEnumerable FromTxTrace(IReadOnlyCollection txTrace)
{
- List results = new();
foreach (ParityLikeTxTrace tx in txTrace)
{
- AddActionsRecursively(results, tx, tx.Action);
+ foreach (ParityTxTraceFromStore trace in ReturnActionsRecursively(tx, tx.Action))
+ {
+ yield return trace;
+ }
}
-
- return results;
-
}
- private static void AddActionsRecursively(List results, ParityLikeTxTrace txTrace, ParityTraceAction txTraceAction)
+ private static IEnumerable ReturnActionsRecursively(ParityLikeTxTrace txTrace, ParityTraceAction? txTraceAction)
{
- ParityTxTraceFromStore result = new()
- {
- Action = txTraceAction,
- Result = txTraceAction.Result,
- Subtraces = txTraceAction.Subtraces.Count,
- Type = txTraceAction.Type,
- BlockHash = txTrace.BlockHash,
- BlockNumber = txTrace.BlockNumber,
- TransactionHash = txTrace.TransactionHash,
- TransactionPosition = txTrace.TransactionPosition,
- TraceAddress = txTraceAction.TraceAddress,
- Error = txTraceAction.Error
- };
- results.Add(result);
-
- foreach (ParityTraceAction subtrace in txTraceAction.Subtraces)
+ if (txTraceAction is not null)
{
- AddActionsRecursively(results, txTrace, subtrace);
+ ParityTxTraceFromStore result = new()
+ {
+ Action = txTraceAction,
+ Result = txTraceAction.Result,
+ Subtraces = txTraceAction.Subtraces.Count,
+ Type = txTraceAction.Type,
+ BlockHash = txTrace.BlockHash,
+ BlockNumber = txTrace.BlockNumber,
+ TransactionHash = txTrace.TransactionHash,
+ TransactionPosition = txTrace.TransactionPosition,
+ TraceAddress = txTraceAction.TraceAddress,
+ Error = txTraceAction.Error
+ };
+ yield return result;
+
+ for (int index = 0; index < txTraceAction.Subtraces.Count; index++)
+ {
+ ParityTraceAction subtrace = txTraceAction.Subtraces[index];
+ foreach (ParityTxTraceFromStore convertedSubtrace in ReturnActionsRecursively(txTrace, subtrace))
+ {
+ yield return convertedSubtrace;
+ }
+
+ }
}
}
@@ -64,7 +69,6 @@ private ParityTxTraceFromStore()
[JsonConverter(typeof(LongConverter), NumberConversion.Raw)]
public long BlockNumber { get; set; }
- [JsonProperty(NullValueHandling = NullValueHandling.Include)]
public ParityTraceResult Result { get; set; }
public int Subtraces { get; set; }
diff --git a/src/Nethermind/Nethermind.JsonRpc/Modules/Trace/TraceModuleFactory.cs b/src/Nethermind/Nethermind.JsonRpc/Modules/Trace/TraceModuleFactory.cs
index d520ee00632..dea3da6e399 100644
--- a/src/Nethermind/Nethermind.JsonRpc/Modules/Trace/TraceModuleFactory.cs
+++ b/src/Nethermind/Nethermind.JsonRpc/Modules/Trace/TraceModuleFactory.cs
@@ -31,7 +31,6 @@ public class TraceModuleFactory : ModuleFactoryBase
private readonly ILogManager _logManager;
private readonly IBlockPreprocessorStep _recoveryStep;
private readonly IRewardCalculatorSource _rewardCalculatorSource;
- private ILogger _logger;
public TraceModuleFactory(
IDbProvider dbProvider,
@@ -49,12 +48,11 @@ public TraceModuleFactory(
_trieNodeResolver = trieNodeResolver;
_jsonRpcConfig = jsonRpcConfig ?? throw new ArgumentNullException(nameof(jsonRpcConfig));
_recoveryStep = recoveryStep ?? throw new ArgumentNullException(nameof(recoveryStep));
- _rewardCalculatorSource =
- rewardCalculatorSource ?? throw new ArgumentNullException(nameof(rewardCalculatorSource));
+ _rewardCalculatorSource = rewardCalculatorSource ?? throw new ArgumentNullException(nameof(rewardCalculatorSource));
_receiptStorage = receiptFinder ?? throw new ArgumentNullException(nameof(receiptFinder));
_specProvider = specProvider ?? throw new ArgumentNullException(nameof(specProvider));
_logManager = logManager ?? throw new ArgumentNullException(nameof(logManager));
- _logger = logManager.GetClassLogger();
+ logManager.GetClassLogger();
}
public override ITraceRpcModule Create()
diff --git a/src/Nethermind/Nethermind.JsonRpc/Modules/Trace/TraceRpcModule.cs b/src/Nethermind/Nethermind.JsonRpc/Modules/Trace/TraceRpcModule.cs
index c676c6d9fb4..746acac83d2 100644
--- a/src/Nethermind/Nethermind.JsonRpc/Modules/Trace/TraceRpcModule.cs
+++ b/src/Nethermind/Nethermind.JsonRpc/Modules/Trace/TraceRpcModule.cs
@@ -46,10 +46,8 @@ public TraceRpcModule(IReceiptFinder? receiptFinder, ITracer? tracer, IBlockFind
_cancellationTokenTimeout = TimeSpan.FromMilliseconds(_jsonRpcConfig.Timeout);
}
- private static ParityTraceTypes GetParityTypes(string[] types)
- {
- return types.Select(s => FastEnum.Parse(s, true)).Aggregate((t1, t2) => t1 | t2);
- }
+ public static ParityTraceTypes GetParityTypes(string[] types) =>
+ types.Select(s => FastEnum.Parse(s, true)).Aggregate((t1, t2) => t1 | t2);
public ResultWrapper trace_call(TransactionForRpc call, string[] traceTypes, BlockParameter? blockParameter = null)
{
@@ -216,6 +214,12 @@ public ResultWrapper> trace_block(BlockParam
public ResultWrapper> trace_get(Keccak txHash, long[] positions)
{
ResultWrapper> traceTransaction = trace_transaction(txHash);
+ List traces = ExtractPositionsFromTxTrace(positions, traceTransaction);
+ return ResultWrapper>.Success(traces);
+ }
+
+ public static List ExtractPositionsFromTxTrace(long[] positions, ResultWrapper> traceTransaction)
+ {
List traces = new();
ParityTxTraceFromStore[] transactionTraces = traceTransaction.Data.ToArray();
for (int index = 0; index < positions.Length; index++)
@@ -228,7 +232,7 @@ public ResultWrapper> trace_get(Keccak txHas
}
}
- return ResultWrapper>.Success(traces);
+ return traces;
}
public ResultWrapper> trace_transaction(Keccak txHash)
diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V62/Eth62ProtocolHandler.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V62/Eth62ProtocolHandler.cs
index bc30668fc8f..5ccbd06719f 100644
--- a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V62/Eth62ProtocolHandler.cs
+++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V62/Eth62ProtocolHandler.cs
@@ -120,14 +120,11 @@ bool CanAcceptBlockGossip()
int packetType = message.PacketType;
if (!_statusReceived && packetType != Eth62MessageCode.Status)
{
- throw new SubprotocolException(
- $"No {nameof(StatusMessage)} received prior to communication with {Node:c}.");
+ throw new SubprotocolException($"No {nameof(StatusMessage)} received prior to communication with {Node:c}.");
}
int size = message.Content.ReadableBytes;
- if (Logger.IsTrace)
- Logger.Trace(
- $"{Counter:D5} {Eth62MessageCode.GetDescription(packetType)} from {Node:c}");
+ if (Logger.IsTrace) Logger.Trace($"{Counter:D5} {Eth62MessageCode.GetDescription(packetType)} from {Node:c}");
switch (packetType)
{
diff --git a/src/Nethermind/Nethermind.Runner/Nethermind.Runner.csproj b/src/Nethermind/Nethermind.Runner/Nethermind.Runner.csproj
index 2d96158ac92..a6a6e27dacb 100644
--- a/src/Nethermind/Nethermind.Runner/Nethermind.Runner.csproj
+++ b/src/Nethermind/Nethermind.Runner/Nethermind.Runner.csproj
@@ -44,6 +44,7 @@
+
@@ -107,8 +108,8 @@
-
-
+
+
diff --git a/src/Nethermind/Nethermind.Serialization.Json/EthereumJsonSerializer.cs b/src/Nethermind/Nethermind.Serialization.Json/EthereumJsonSerializer.cs
index 7dd04d2696a..6ab7b5ecd2f 100644
--- a/src/Nethermind/Nethermind.Serialization.Json/EthereumJsonSerializer.cs
+++ b/src/Nethermind/Nethermind.Serialization.Json/EthereumJsonSerializer.cs
@@ -7,6 +7,7 @@
using System.IO;
using System.Linq;
using System.Text;
+using Nethermind.Core.Collections;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
@@ -14,15 +15,19 @@ namespace Nethermind.Serialization.Json
{
public class EthereumJsonSerializer : IJsonSerializer
{
+ private readonly int? _maxDepth;
private JsonSerializer _internalSerializer;
private JsonSerializer _internalReadableSerializer;
private JsonSerializerSettings _settings;
private JsonSerializerSettings _readableSettings;
- public EthereumJsonSerializer()
+ public EthereumJsonSerializer(int? maxDepth = null, params JsonConverter[] converters)
{
- RebuildSerializers();
+ _maxDepth = maxDepth;
+ BasicConverters.AddRange(converters);
+ ReadableConverters.AddRange(converters);
+ RebuildSerializers(maxDepth);
}
public static IReadOnlyList CommonConverters { get; } = new ReadOnlyCollection(
@@ -125,17 +130,17 @@ public void RegisterConverter(JsonConverter converter)
BasicConverters.Add(converter);
ReadableConverters.Add(converter);
- RebuildSerializers();
+ RebuildSerializers(_maxDepth);
}
- private void RebuildSerializers()
+ private void RebuildSerializers(int? maxDepth = null)
{
_readableSettings = new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver(),
NullValueHandling = NullValueHandling.Ignore,
Formatting = Formatting.Indented,
- Converters = ReadableConverters
+ Converters = ReadableConverters,
};
_settings = new JsonSerializerSettings
@@ -146,6 +151,11 @@ private void RebuildSerializers()
Converters = BasicConverters,
};
+ if (maxDepth is not null)
+ {
+ _readableSettings.MaxDepth = _settings.MaxDepth = maxDepth.Value;
+ }
+
_internalSerializer = JsonSerializer.Create(_settings);
_internalReadableSerializer = JsonSerializer.Create(_readableSettings);
}
diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/RlpDecoderExtensions.cs b/src/Nethermind/Nethermind.Serialization.Rlp/RlpDecoderExtensions.cs
index 66022ff453c..e0188ced7b5 100644
--- a/src/Nethermind/Nethermind.Serialization.Rlp/RlpDecoderExtensions.cs
+++ b/src/Nethermind/Nethermind.Serialization.Rlp/RlpDecoderExtensions.cs
@@ -1,6 +1,8 @@
// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited
// SPDX-License-Identifier: LGPL-3.0-only
+using System.Collections.Generic;
+
namespace Nethermind.Serialization.Rlp
{
public static class RlpDecoderExtensions
@@ -44,5 +46,23 @@ public static Rlp Encode(this IRlpObjectDecoder decoder, T?[]? items, RlpB
return Rlp.Encode(rlpSequence);
}
+
+ public static Rlp Encode(this IRlpObjectDecoder decoder, IReadOnlyCollection? items, RlpBehaviors behaviors = RlpBehaviors.None)
+ {
+ if (items == null)
+ {
+ return Rlp.OfEmptySequence;
+ }
+
+ Rlp[] rlpSequence = new Rlp[items.Count];
+ int i = 0;
+ foreach (T? item in items)
+ {
+ rlpSequence[i++] = item == null ? Rlp.OfEmptySequence : decoder.Encode(item, behaviors);
+ }
+
+ return Rlp.Encode(rlpSequence);
+ }
+
}
}
diff --git a/src/Nethermind/Nethermind.State/IStateTracer.cs b/src/Nethermind/Nethermind.State/IStateTracer.cs
index eb778c951c4..1d62d72ab72 100644
--- a/src/Nethermind/Nethermind.State/IStateTracer.cs
+++ b/src/Nethermind/Nethermind.State/IStateTracer.cs
@@ -8,10 +8,50 @@ namespace Nethermind.State
{
public interface IStateTracer
{
+ ///
+ ///
+ ///
+ ///
+ /// Controls
+ /// -