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

Implementation of trace_call and trace_callMany #3571

Merged
merged 15 commits into from
Nov 4, 2021
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,18 @@ public class BlockValidationTransactionsExecutor : IBlockProcessor.IBlockTransac
{
private readonly ITransactionProcessorAdapter _transactionProcessor;
private readonly IStateProvider _stateProvider;

public BlockValidationTransactionsExecutor(ITransactionProcessor transactionProcessor, IStateProvider stateProvider)
: this(new ExecuteTransactionProcessorAdapter(transactionProcessor), stateProvider)
{
_transactionProcessor = new ExecuteTransactionProcessorAdapter(transactionProcessor);
}

protected BlockValidationTransactionsExecutor(ITransactionProcessorAdapter transactionProcessor, IStateProvider stateProvider)
{
_transactionProcessor = transactionProcessor;
_stateProvider = stateProvider;
}

public event EventHandler<TxProcessedEventArgs>? TransactionProcessed;

public TxReceipt[] ProcessTransactions(Block block, ProcessingOptions processingOptions, BlockReceiptsTracer receiptsTracer, IReleaseSpec spec)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,19 @@ public ReadOnlyChainProcessingEnv(
IReceiptStorage receiptStorage,
IReadOnlyDbProvider dbProvider,
ISpecProvider specProvider,
ILogManager logManager)
ILogManager logManager,
IBlockProcessor.IBlockTransactionsExecutor? blockTransactionsExecutor = null)
{
_txEnv = txEnv;

IBlockProcessor.IBlockTransactionsExecutor transactionsExecutor =
blockTransactionsExecutor ?? new BlockProcessor.BlockValidationTransactionsExecutor(_txEnv.TransactionProcessor, StateProvider);

BlockProcessor = new BlockProcessor(
specProvider,
blockValidator,
rewardCalculator,
new BlockProcessor.BlockValidationTransactionsExecutor(_txEnv.TransactionProcessor, StateProvider),
transactionsExecutor,
StateProvider,
_txEnv.StorageProvider,
receiptStorage,
Expand Down
1 change: 1 addition & 0 deletions src/Nethermind/Nethermind.Cli/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ private static void RegisterConverters()
Serializer.RegisterConverter(new ParityTraceResultConverter());
Serializer.RegisterConverter(new ParityVmOperationTraceConverter());
Serializer.RegisterConverter(new ParityVmTraceConverter());
Serializer.RegisterConverter(new TransactionForRpcWithTraceTypesConverter());
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// 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 <http://www.gnu.org/licenses/>.
//
//
using Nethermind.Core;
using Nethermind.Evm.Tracing;

namespace Nethermind.Evm.TransactionProcessing
{
public class CallAndRestoreTransactionProcessorAdapter : ITransactionProcessorAdapter
{
private readonly ITransactionProcessor _transactionProcessor;

public CallAndRestoreTransactionProcessorAdapter(ITransactionProcessor transactionProcessor)
{
_transactionProcessor = transactionProcessor;
}

public void Execute(Transaction transaction, BlockHeader block, ITxTracer txTracer) =>
_transactionProcessor.CallAndRestore(transaction, block, txTracer);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ internal class TestRpcModuleProvider<T> : IRpcModuleProvider where T : class, IR
{
private readonly JsonRpcConfig _jsonRpcConfig;
private readonly RpcModuleProvider _provider;


public TestRpcModuleProvider(T module)
{
Expand Down
232 changes: 160 additions & 72 deletions src/Nethermind/Nethermind.JsonRpc.Test/Modules/TraceRpcModuleTests.cs

Large diffs are not rendered by default.

24 changes: 20 additions & 4 deletions src/Nethermind/Nethermind.JsonRpc.Test/RpcTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
// You should have received a copy of the GNU Lesser General Public License
// along with the Nethermind. If not, see <http://www.gnu.org/licenses/>.

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
Expand All @@ -38,7 +39,7 @@ public static JsonRpcResponse TestRequest<T>(T module, string method, params str

public static string TestSerializedRequest<T>(IReadOnlyCollection<JsonConverter> converters, T module, string method, params string[] parameters) where T : class, IRpcModule
{
IJsonRpcService service = BuildRpcService(module);
IJsonRpcService service = BuildRpcService(module, converters);
JsonRpcRequest request = GetJsonRequest(method, parameters);

JsonRpcContext context = JsonRpcContext.Http;
Expand Down Expand Up @@ -77,10 +78,11 @@ public static string TestSerializedRequest<T>(T module, string method, params st
return TestSerializedRequest(new JsonConverter[0], module, method, parameters);
}

public static IJsonRpcService BuildRpcService<T>(T module) where T : class, IRpcModule
public static IJsonRpcService BuildRpcService<T>(T module, IReadOnlyCollection<JsonConverter>? converters = null) where T : class, IRpcModule
{
var moduleProvider = new TestRpcModuleProvider<T>(module);
moduleProvider.Register(new SingletonModulePool<T>(new SingletonFactory<T>(module), true));

moduleProvider.Register(new SingletonModulePool<T>(new TestSingletonFactory<T>(module, converters), true));
IJsonRpcService service = new JsonRpcService(moduleProvider, LimboLogs.Instance);
return service;
}
Expand All @@ -91,11 +93,25 @@ public static JsonRpcRequest GetJsonRequest(string method, params string[] param
{
JsonRpc = "2.0",
Method = method,
Params = parameters?.ToArray() ?? new string[0],
Params = parameters?.ToArray() ?? Array.Empty<string>(),
Id = 67
};

return request;
}

private class TestSingletonFactory<T> : SingletonFactory<T> where T : IRpcModule
{
private readonly IReadOnlyCollection<JsonConverter>? _converters;

public TestSingletonFactory(T module, IReadOnlyCollection<JsonConverter>? converters) : base(module)
{
_converters = converters;
}

public override IReadOnlyCollection<JsonConverter> GetConverters() => _converters ?? base.GetConverters();
}
}


}
15 changes: 15 additions & 0 deletions src/Nethermind/Nethermind.JsonRpc/Data/TransactionForRpc.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
// You should have received a copy of the GNU Lesser General Public License
// along with the Nethermind. If not, see <http://www.gnu.org/licenses/>.

using System;
using System.Collections.Generic;
using System.Linq;
using MathGmp.Native;
Expand Down Expand Up @@ -168,5 +169,19 @@ public TransactionForRpc()
Type != TxType.AccessList || AccessList == null
? null
: AccessListItemForRpc.ToAccessList(AccessList);

public void EnsureDefaults(long? gasCap)
{
if (Gas == null || Gas == 0)
{
Gas = gasCap ?? long.MaxValue;
}
else
{
Gas = Math.Min(gasCap ?? long.MaxValue, Gas.Value);
}

From ??= Address.SystemUser;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// 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 <http://www.gnu.org/licenses/>.
//

using System;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

namespace Nethermind.JsonRpc.Data
{
public class TransactionForRpcWithTraceTypes
{
public TransactionForRpc Transaction { get; set; }
public string[] TraceTypes { get; set; }
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public ResultWrapper<TResult> ExecuteTx(
ErrorCodes.ResourceUnavailable);
}

FixCallTx(transactionCall);
transactionCall.EnsureDefaults(_rpcConfig.GasCap);

using CancellationTokenSource cancellationTokenSource = new(_rpcConfig.Timeout);
Transaction tx = transactionCall.ToTransaction(_blockchainBridge.GetChainId());
Expand All @@ -72,20 +72,6 @@ public ResultWrapper<TResult> ExecuteTx(

protected ResultWrapper<TResult> GetInputError(BlockchainBridge.CallOutput result) =>
ResultWrapper<TResult>.Fail(result.Error, ErrorCodes.InvalidInput);

private void FixCallTx(TransactionForRpc transactionCall)
{
if (transactionCall.Gas == null || transactionCall.Gas == 0)
{
transactionCall.Gas = _rpcConfig.GasCap ?? long.MaxValue;
}
else
{
transactionCall.Gas = Math.Min(_rpcConfig.GasCap ?? long.MaxValue, transactionCall.Gas.Value);
}

transactionCall.From ??= Address.SystemUser;
}
}

private class CallTxExecutor : TxExecutor<string>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// 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 <http://www.gnu.org/licenses/>.
//

using Nethermind.Blockchain.Processing;
using Nethermind.Evm.TransactionProcessing;
using Nethermind.State;

namespace Nethermind.JsonRpc.Modules
{
public class RpcBlockTransactionsExecutor : BlockProcessor.BlockValidationTransactionsExecutor
{
public RpcBlockTransactionsExecutor(ITransactionProcessor transactionProcessor, IStateProvider stateProvider)
: base(new CallAndRestoreTransactionProcessorAdapter(transactionProcessor), stateProvider)
{
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,8 @@ public void Register<T>(IRpcModulePool<T> pool) where T : IRpcModule
_pools[moduleType] = (async canBeShared => await pool.GetModule(canBeShared), m => pool.ReturnModule((T) m));
_modules.Add(moduleType);

((List<JsonConverter>) Converters).AddRange(pool.Factory.GetConverters());
IReadOnlyCollection<JsonConverter> poolConverters = pool.Factory.GetConverters();
((List<JsonConverter>) Converters).AddRange(poolConverters);

foreach ((string name, (MethodInfo info, bool readOnly, RpcEndpoint availability)) in GetMethodDict(typeof(T)))
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
// You should have received a copy of the GNU Lesser General Public License
// along with the Nethermind. If not, see <http://www.gnu.org/licenses/>.

using System;
using Nethermind.Blockchain.Find;
using Nethermind.Core.Crypto;
using Nethermind.JsonRpc.Data;
Expand All @@ -24,10 +25,10 @@ namespace Nethermind.JsonRpc.Modules.Trace
public interface ITraceRpcModule : IRpcModule
{
[JsonRpcMethod(Description = "", IsImplemented = true, IsSharable = false)]
ResultWrapper<ParityTxTraceFromReplay> trace_call(TransactionForRpc message, string[] traceTypes, BlockParameter blockParameter);
ResultWrapper<ParityTxTraceFromReplay> trace_call(TransactionForRpc call, string[] traceTypes, BlockParameter? blockParameter = null);

[JsonRpcMethod(Description = "", IsImplemented = false, IsSharable = false)]
ResultWrapper<ParityTxTraceFromReplay[]> trace_callMany((TransactionForRpc message, string[] traceTypes, BlockParameter numberOrTag)[] calls);
ResultWrapper<ParityTxTraceFromReplay[]> trace_callMany(TransactionForRpcWithTraceTypes[] calls, BlockParameter? blockParameter = null);

[JsonRpcMethod(Description = "Traces a call to eth_sendRawTransaction without making the call, returning the traces",
IsImplemented = true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
using Nethermind.Blockchain.Validators;
using Nethermind.Core.Specs;
using Nethermind.Db;
using Nethermind.Evm.TransactionProcessing;
using Nethermind.JsonRpc.Data;
using Nethermind.Logging;
using Nethermind.Trie.Pruning;
using Newtonsoft.Json;
Expand Down Expand Up @@ -73,6 +75,8 @@ public override ITraceRpcModule Create()
new(_dbProvider, _trieNodeResolver, _blockTree, _specProvider, _logManager);

IRewardCalculator rewardCalculator = _rewardCalculatorSource.Get(txProcessingEnv.TransactionProcessor);

RpcBlockTransactionsExecutor rpcBlockTransactionsExecutor = new(txProcessingEnv.TransactionProcessor, txProcessingEnv.StateProvider);

ReadOnlyChainProcessingEnv chainProcessingEnv = new(
txProcessingEnv,
Expand All @@ -82,7 +86,8 @@ public override ITraceRpcModule Create()
_receiptStorage,
_dbProvider,
_specProvider,
_logManager);
_logManager,
rpcBlockTransactionsExecutor);

Tracer tracer = new(chainProcessingEnv.StateProvider, chainProcessingEnv.ChainProcessor);

Expand All @@ -96,7 +101,8 @@ public override ITraceRpcModule Create()
new ParityTraceActionConverter(),
new ParityTraceResultConverter(),
new ParityVmOperationTraceConverter(),
new ParityVmTraceConverter()
new ParityVmTraceConverter(),
new TransactionForRpcWithTraceTypesConverter()
};

public override IReadOnlyCollection<JsonConverter> GetConverters() => Converters;
Expand Down
23 changes: 18 additions & 5 deletions src/Nethermind/Nethermind.JsonRpc/Modules/Trace/TraceRpcModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,15 +63,28 @@ private static ParityTraceTypes GetParityTypes(string[] types)
return types.Select(s => (ParityTraceTypes) Enum.Parse(typeof(ParityTraceTypes), s, true)).Aggregate((t1, t2) => t1 | t2);
}

public ResultWrapper<ParityTxTraceFromReplay> trace_call(TransactionForRpc message, string[] traceTypes, BlockParameter blockParameter)
public ResultWrapper<ParityTxTraceFromReplay> trace_call(TransactionForRpc call, string[] traceTypes, BlockParameter? blockParameter = null)
{
Transaction tx = message.ToTransaction();
blockParameter ??= BlockParameter.Latest;
call.EnsureDefaults(_jsonRpcConfig.GasCap);

Transaction tx = call.ToTransaction();

return TraceTx(tx, traceTypes, blockParameter);
}

public ResultWrapper<ParityTxTraceFromReplay[]> trace_callMany((TransactionForRpc message, string[] traceTypes, BlockParameter numberOrTag)[] a)
public ResultWrapper<ParityTxTraceFromReplay[]> trace_callMany(TransactionForRpcWithTraceTypes[] calls, BlockParameter? blockParameter = null)
{
throw new NotImplementedException();
blockParameter ??= BlockParameter.Latest;
List<ParityTxTraceFromReplay> traces = new();
for (var index = 0; index < calls.Length; index++)
{
TransactionForRpcWithTraceTypes call = calls[index];
ResultWrapper<ParityTxTraceFromReplay> trace = trace_call(call.Transaction, call.TraceTypes, blockParameter);
traces.Add(trace.Data);
}

return ResultWrapper<ParityTxTraceFromReplay[]>.Success(traces.ToArray());
}

public ResultWrapper<ParityTxTraceFromReplay> trace_rawTransaction(byte[] data, string[] traceTypes)
Expand Down Expand Up @@ -226,7 +239,7 @@ public ResultWrapper<ParityTxTraceFromStore[]> trace_transaction(Keccak txHash)
return ResultWrapper<ParityTxTraceFromStore[]>.Success(ParityTxTraceFromStore.FromTxTrace(txTrace));
}

private IReadOnlyCollection<ParityLikeTxTrace> TraceBlock(Block block, ParityTraceTypes traceTypes, TxTraceFilter txTraceFilter = null)
private IReadOnlyCollection<ParityLikeTxTrace> TraceBlock(Block block, ParityTraceTypes traceTypes, TxTraceFilter? txTraceFilter = null)
{
using CancellationTokenSource cancellationTokenSource = new(_cancellationTokenTimeout);
CancellationToken cancellationToken = cancellationTokenSource.Token;
Expand Down
Loading