Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Fix TraceStore plugin #6609

Merged
merged 2 commits into from
Jan 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,10 @@

namespace Nethermind.Evm.Tracing.ParityStyle
{
[JsonConverter(typeof(ParityTraceActionConverter))]
public class ParityTraceAction
{
public int[]? TraceAddress { get; set; }
public string? CallType { get; set; }

public bool IncludeInTrace { get; set; } = true;
public bool IsPrecompiled { get; set; }
public string? Type { get; set; }
Expand All @@ -26,7 +24,6 @@ public class ParityTraceAction
public byte[]? Input { get; set; }
public ParityTraceResult? Result { get; set; } = new();
public List<ParityTraceAction> Subtraces { get; set; } = new();

public Address? Author { get; set; }
public string? RewardType { get; set; }
public string? Error { get; set; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ namespace Nethermind.Evm.Tracing.ParityStyle
*/
public class ParityTraceActionConverter : JsonConverter<ParityTraceAction>
{
public static readonly ParityTraceActionConverter Instance = new();

public override ParityTraceAction Read(
ref Utf8JsonReader reader,
Type typeToConvert,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,8 @@
// SPDX-License-Identifier: LGPL-3.0-only

using System;
using System.Collections.Generic;
using System.Text.Json.Serialization;

using Nethermind.JsonRpc.Data;
using Nethermind.JsonRpc.Modules.Eth;
using Nethermind.JsonRpc.Modules.Trace;
using Nethermind.Serialization.Json;

using NUnit.Framework;
Expand Down Expand Up @@ -47,32 +44,23 @@ protected void TestRoundtrip<T>(T item, Func<T, T, bool>? equalityComparer, stri
TestRoundtrip(item, equalityComparer, null, description);
}

protected void TestRoundtrip<T>(string json, JsonConverter? converter = null)
protected void TestRoundtrip<T>(string json, params JsonConverter[] converters)
{
IJsonSerializer serializer = BuildSerializer();
IJsonSerializer serializer = BuildSerializer(converters);

T deserialized = serializer.Deserialize<T>(json);
string result = serializer.Serialize(deserialized);
Assert.That(result, Is.EqualTo(json));
}

private void TestToJson<T>(T item, JsonConverter<T>? converter, string expectedResult)
protected void TestToJson<T>(T item, string expectedResult, params JsonConverter[] converters)
{
IJsonSerializer serializer = BuildSerializer();
IJsonSerializer serializer = BuildSerializer(converters);

string result = serializer.Serialize(item);
Assert.That(result, Is.EqualTo(expectedResult.Replace("+", "\\u002B")), result.Replace("\"", "\\\""));
}

protected void TestToJson<T>(T item, string expectedResult)
{
TestToJson(item, null, expectedResult);
}

private static IJsonSerializer BuildSerializer()
{
IJsonSerializer serializer = new EthereumJsonSerializer();
return serializer;
}
private static IJsonSerializer BuildSerializer(params JsonConverter[] converters) => new EthereumJsonSerializer(converters);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,24 +15,26 @@ public class ParityTraceActionSerializationTests : SerializationTestBase
[Test]
public void Can_serialize()
{
ParityTraceAction action = new();
action.From = TestItem.AddressA;
action.Gas = 12345;
action.Input = new byte[] { 6, 7, 8, 9, 0 };
action.To = TestItem.AddressB;
action.Value = 24680;
action.CallType = "call";
action.TraceAddress = new int[] { 1, 3, 5, 7 };
ParityTraceAction action = new()
{
From = TestItem.AddressA,
Gas = 12345,
Input = [6, 7, 8, 9, 0],
To = TestItem.AddressB,
Value = 24680,
CallType = "call",
TraceAddress = [1, 3, 5, 7]
};

TestToJson(action, "{\"callType\":\"call\",\"from\":\"0xb7705ae4c6f81b66cdb323c65f4e8133690fc099\",\"gas\":\"0x3039\",\"input\":\"0x0607080900\",\"to\":\"0x942921b14f1b1c385cd7e0cc2ef7abe5598c8358\",\"value\":\"0x6068\"}");
TestToJson(action, "{\"callType\":\"call\",\"from\":\"0xb7705ae4c6f81b66cdb323c65f4e8133690fc099\",\"gas\":\"0x3039\",\"input\":\"0x0607080900\",\"to\":\"0x942921b14f1b1c385cd7e0cc2ef7abe5598c8358\",\"value\":\"0x6068\"}", ParityTraceActionConverter.Instance);
}

[Test]
public void Can_serialize_nulls()
{
ParityTraceAction action = new();

TestToJson(action, "{\"callType\":null,\"from\":null,\"gas\":\"0x0\",\"input\":null,\"to\":null,\"value\":\"0x0\"}");
TestToJson(action, "{\"callType\":null,\"from\":null,\"gas\":\"0x0\",\"input\":null,\"to\":null,\"value\":\"0x0\"}", ParityTraceActionConverter.Instance);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited
// SPDX-License-Identifier: LGPL-3.0-only

using System;
using System.Collections.Generic;
using System.Linq;
using FluentAssertions;
using Nethermind.Core;
using Nethermind.Core.Crypto;
using Nethermind.Core.Test.Builders;
using Nethermind.Db;
using Nethermind.Evm;
using Nethermind.Evm.Tracing;
using Nethermind.Evm.Tracing.ParityStyle;
using Nethermind.Logging;
using NUnit.Framework;
Expand All @@ -15,24 +20,117 @@ namespace Nethermind.JsonRpc.TraceStore.Tests;
[Parallelizable(ParallelScope.All)]
public class DbPersistingBlockTracerTests
{
private class Test
{
public DbPersistingBlockTracer<ParityLikeTxTrace, ParityLikeTxTracer> DbPersistingTracer { get; }
public ParityLikeTraceSerializer Serializer { get; }
public MemDb Db { get; }

public Test()
{
ParityLikeBlockTracer parityTracer = new(ParityTraceTypes.Trace);
Db = new();
Serializer = new(LimboLogs.Instance);
DbPersistingTracer = new(parityTracer, Db, Serializer, LimboLogs.Instance);
}

public (Hash256 hash, List<ParityLikeTxTrace> traces) Trace(Action<ITxTracer>? customTrace = null)
{
Transaction transaction = Build.A.Transaction.TestObject;
Block block = Build.A.Block.WithTransactions(transaction).TestObject;
DbPersistingTracer.StartNewBlockTrace(block);
ITxTracer txTracer = DbPersistingTracer.StartNewTxTrace(transaction);
customTrace?.Invoke(txTracer);
DbPersistingTracer.EndTxTrace();
DbPersistingTracer.EndBlockTrace();
Hash256 hash = block.Hash!;
return (hash, Serializer.Deserialize(Db.Get(hash))!);
}
}

[Test]
public void saves_traces_to_db()
{
ParityLikeBlockTracer parityTracer = new(ParityTraceTypes.Trace);
MemDb memDb = new();
ParityLikeTraceSerializer serializer = new(LimboLogs.Instance);
DbPersistingBlockTracer<ParityLikeTxTrace, ParityLikeTxTracer> 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<ParityLikeTxTrace>? traces = serializer.Deserialize(memDb.Get(block.Hash!));
traces.Should().BeEquivalentTo(new ParityLikeTxTrace[] { new() { BlockHash = block.Hash, TransactionPosition = 0 } });
Test test = new();
(Hash256 hash, List<ParityLikeTxTrace> traces) = test.Trace(tracer =>
{
tracer.ReportAction(100, 50, TestItem.AddressA, TestItem.AddressB, TestItem.RandomDataA, ExecutionType.CALL);
tracer.ReportAction(80, 20, TestItem.AddressB, TestItem.AddressC, TestItem.RandomDataC, ExecutionType.CREATE);
tracer.ReportActionEnd(60, TestItem.RandomDataD);
tracer.ReportActionEnd(50, TestItem.RandomDataB);
}
);

traces.Should().BeEquivalentTo(new ParityLikeTxTrace[]
{
new()
{
BlockHash = hash,
TransactionPosition = 0,
Action = new ParityTraceAction
{
CallType = "call",
From = TestItem.AddressA,
Gas = 100,
IncludeInTrace = true,
Input = TestItem.RandomDataA,
Result = new ParityTraceResult { GasUsed = 50, Output = TestItem.RandomDataB },
To = TestItem.AddressB,
TraceAddress = Array.Empty<int>(),
Type = "call",
Value = 50,
Subtraces =
[
new()
{
CallType = "create",
From = TestItem.AddressB,
Gas = 80,
IncludeInTrace = true,
Input = TestItem.RandomDataC,
Result = new ParityTraceResult { GasUsed = 20, Output = TestItem.RandomDataD },
Subtraces = new List<ParityTraceAction>(),
To = TestItem.AddressC,
TraceAddress = [0],
CreationMethod = "create",
Type = "create",
Value = 20
}
]
}
}
});
}

[TestCase(510)]
[TestCase(1020)]
[TestCase(1500)]
public void check_depth(int depth)
{
// depth = depth / 2 - 1;
Test test = new();
(_, List<ParityLikeTxTrace> traces) = test.Trace(tracer =>
{
for (int i = 0; i < depth; i++)
{
tracer.ReportAction(100, 50, TestItem.AddressA, TestItem.AddressB, TestItem.RandomDataA, ExecutionType.CALL);
}

for (int i = 0; i < depth; i++)
{
tracer.ReportActionEnd(60, TestItem.RandomDataD);
}
}
);

ParityTraceAction? action = traces.FirstOrDefault()?.Action;
int checkedDepth = 0;
while (action is not null)
{
checkedDepth += 1;
action = action.Subtraces.FirstOrDefault();
}

checkedDepth.Should().Be(depth);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public interface ITraceStoreConfig : IConfig
[ConfigItem(Description = "Whether to verify all serialized elements.", DefaultValue = "false", HiddenFromDocs = true)]
bool VerifySerialized { get; set; }

[ConfigItem(Description = "The max depth allowed when deserializing traces.", DefaultValue = "1024", HiddenFromDocs = true)]
[ConfigItem(Description = "The max depth allowed when deserializing traces.", DefaultValue = "3200", HiddenFromDocs = true)]
int MaxDepth { get; set; }

[ConfigItem(Description = "The max parallelization when deserialization requests the `trace_filter` method. `0` to use the number of logical processors. If you experience a resource shortage, set to a low number.", DefaultValue = "0")]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ namespace Nethermind.JsonRpc.TraceStore;

public class ParityLikeTraceSerializer : ITraceSerializer<ParityLikeTxTrace>
{
public const int DefaultDepth = 3200;
private static readonly byte[] _emptyBytes = { 0 };
private static readonly List<ParityLikeTxTrace> _emptyTraces = new();

Expand All @@ -20,7 +21,7 @@ public class ParityLikeTraceSerializer : ITraceSerializer<ParityLikeTxTrace>
private readonly int _maxDepth;
private readonly bool _verifySerialized;

public ParityLikeTraceSerializer(ILogManager logManager, int maxDepth = 1024, bool verifySerialized = false)
public ParityLikeTraceSerializer(ILogManager logManager, int maxDepth = DefaultDepth, bool verifySerialized = false)
{
_jsonSerializer = new EthereumJsonSerializer(maxDepth);
_maxDepth = maxDepth;
Expand All @@ -30,7 +31,7 @@ public ParityLikeTraceSerializer(ILogManager logManager, int maxDepth = 1024, bo

public unsafe List<ParityLikeTxTrace>? Deserialize(Span<byte> serialized)
{
if (serialized.Length == 1) return _emptyTraces;
if (serialized.Length <= 1) return _emptyTraces;

fixed (byte* pBuffer = &serialized[0])
{
Expand Down Expand Up @@ -102,9 +103,9 @@ private void CheckDepth(ParityTraceAction action, int depth)
throw new ArgumentException("Trace depth is too high");
}

foreach (ParityTraceAction subAction in action.Subtraces)
for (var index = 0; index < action.Subtraces.Count; index++)
{
CheckDepth(subAction, depth);
CheckDepth(action.Subtraces[index], depth);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
// SPDX-License-Identifier: LGPL-3.0-only

using Nethermind.Evm.Tracing.ParityStyle;
using Nethermind.Serialization.Json;
using Newtonsoft.Json;

namespace Nethermind.JsonRpc.TraceStore;

Expand All @@ -11,6 +13,6 @@ public class TraceStoreConfig : ITraceStoreConfig
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;
public int MaxDepth { get; set; } = ParityLikeTraceSerializer.DefaultDepth;
public int DeserializationParallelization { get; set; } = 0;
}
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ public override void Write(
writer.WriteStartObject();

writer.WritePropertyName("action"u8);
JsonSerializer.Serialize(writer, value, options);
ParityTraceActionConverter.Instance.Write(writer, value, options);

if (value.Error is null)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ private ParityTxTraceFromStore()
{
}

[JsonConverter(typeof(ParityTraceActionConverter))]
public ParityTraceAction Action { get; set; }

public Hash256 BlockHash { get; set; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ public ResultWrapper<IEnumerable<ParityTxTraceFromStore>> trace_filter(TraceFilt
return GetStateFailureResult<IEnumerable<ParityTxTraceFromStore>>(block.Header);
}

IReadOnlyCollection<ParityLikeTxTrace> txTracesFromOneBlock = ExecuteBlock(block!, new((ParityTraceTypes)(ParityTraceTypes.Trace | ParityTraceTypes.Rewards)));
IReadOnlyCollection<ParityLikeTxTrace> txTracesFromOneBlock = ExecuteBlock(block!, new(ParityTraceTypes.Trace | ParityTraceTypes.Rewards));
txTraces.AddRange(txTracesFromOneBlock);
}

Expand All @@ -263,7 +263,7 @@ public ResultWrapper<IEnumerable<ParityTxTraceFromStore>> trace_block(BlockParam
return GetStateFailureResult<IEnumerable<ParityTxTraceFromStore>>(block.Header);
}

IReadOnlyCollection<ParityLikeTxTrace> txTraces = ExecuteBlock(block, new((ParityTraceTypes)(ParityTraceTypes.Trace | ParityTraceTypes.Rewards)));
IReadOnlyCollection<ParityLikeTxTrace> txTraces = ExecuteBlock(block, new(ParityTraceTypes.Trace | ParityTraceTypes.Rewards));
return ResultWrapper<IEnumerable<ParityTxTraceFromStore>>.Success(txTraces.SelectMany(ParityTxTraceFromStore.FromTxTrace));
}

Expand Down
Loading