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

Proper Transaction type for eth_* calls when running Optimism #8157

Open
wants to merge 19 commits into
base: master
Choose a base branch
from
Open
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
47 changes: 22 additions & 25 deletions src/Nethermind/Nethermind.JsonRpc/Modules/Eth/EthRpcModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
using Nethermind.Wallet;
using Block = Nethermind.Core.Block;
using BlockHeader = Nethermind.Core.BlockHeader;
using ResultType = Nethermind.Core.ResultType;
using Signature = Nethermind.Core.Crypto.Signature;
using Transaction = Nethermind.Core.Transaction;

Expand Down Expand Up @@ -384,7 +385,7 @@ public ResultWrapper<BlockForRpc> eth_getBlockByNumber(BlockParameter blockParam
: new BlockForRpc(block, returnFullTransactionObjects, _specProvider));
}

public ResultWrapper<TransactionForRpc?> eth_getTransactionByHash(Hash256 transactionHash)
public virtual ResultWrapper<TransactionForRpc?> eth_getTransactionByHash(Hash256 transactionHash)
{
(TxReceipt? receipt, Transaction? transaction, UInt256? baseFee) = _blockchainBridge.GetTransaction(transactionHash, checkTxnPool: true);
if (transaction is null)
Expand All @@ -393,7 +394,7 @@ public ResultWrapper<BlockForRpc> eth_getBlockByNumber(BlockParameter blockParam
}

RecoverTxSenderIfNeeded(transaction);
TransactionForRpc transactionModel = TransactionForRpc.FromTransaction(transaction, receipt?.BlockHash, receipt?.BlockNumber, receipt?.Index, baseFee, specProvider.ChainId);
TransactionForRpc transactionModel = TransactionForRpc.FromTransaction(transaction, receipt?.BlockHash, receipt?.BlockNumber, receipt?.Index, baseFee, _specProvider.ChainId);
if (_logger.IsTrace) _logger.Trace($"eth_getTransactionByHash request {transactionHash}, result: {transactionModel.Hash}");
return ResultWrapper<TransactionForRpc?>.Success(transactionModel);
}
Expand All @@ -420,39 +421,39 @@ public ResultWrapper<TransactionForRpc[]> eth_pendingTransactions()
{
Transaction transaction = transactions[i];
RecoverTxSenderIfNeeded(transaction);
transactionsModels[i] = TransactionForRpc.FromTransaction(transaction, chainId: specProvider.ChainId);
transactionsModels[i] = TransactionForRpc.FromTransaction(transaction, chainId: _specProvider.ChainId);
transactionsModels[i].BlockHash = Keccak.Zero;
}

if (_logger.IsTrace) _logger.Trace($"eth_pendingTransactions request, result: {transactionsModels.Length}");
return ResultWrapper<TransactionForRpc[]>.Success(transactionsModels);
}

public ResultWrapper<TransactionForRpc> eth_getTransactionByBlockHashAndIndex(Hash256 blockHash,
UInt256 positionIndex)
public ResultWrapper<TransactionForRpc> eth_getTransactionByBlockHashAndIndex(Hash256 blockHash, UInt256 positionIndex)
{
SearchResult<Block> searchResult = _blockFinder.SearchForBlock(new BlockParameter(blockHash));
if (searchResult.IsError)
ResultWrapper<TransactionForRpc> result = GetTransactionByBlockAndIndex(new BlockParameter(blockHash), positionIndex);
if (result.Result.ResultType == ResultType.Success)
{
return GetFailureResult<TransactionForRpc, Block>(searchResult, _ethSyncingInfo.SyncMode.HaveNotSyncedBodiesYet());
if (_logger.IsTrace)
_logger.Trace(
$"eth_getTransactionByBlockHashAndIndex request {blockHash}, index: {positionIndex}, result: {result.Data.Hash}");
}
return result;
}

Block block = searchResult.Object;
if (positionIndex < 0 || positionIndex > block!.Transactions.Length - 1)
public ResultWrapper<TransactionForRpc> eth_getTransactionByBlockNumberAndIndex(BlockParameter blockParameter, UInt256 positionIndex)
{
ResultWrapper<TransactionForRpc> result = GetTransactionByBlockAndIndex(blockParameter, positionIndex);
if (result.Result.ResultType == ResultType.Success)
{
return ResultWrapper<TransactionForRpc>.Fail("Position Index is incorrect", ErrorCodes.InvalidParams);
if (_logger.IsTrace)
_logger.Trace(
$"eth_getTransactionByBlockNumberAndIndex request {blockParameter}, index: {positionIndex}, result: {result.Data.Hash}");
}

Transaction transaction = block.Transactions[(int)positionIndex];
RecoverTxSenderIfNeeded(transaction);

TransactionForRpc transactionModel = TransactionForRpc.FromTransaction(transaction, block.Hash, block.Number, (int)positionIndex, block.BaseFeePerGas, specProvider.ChainId);

return ResultWrapper<TransactionForRpc>.Success(transactionModel);
return result;
}

public ResultWrapper<TransactionForRpc> eth_getTransactionByBlockNumberAndIndex(BlockParameter blockParameter,
UInt256 positionIndex)
protected virtual ResultWrapper<TransactionForRpc> GetTransactionByBlockAndIndex(BlockParameter blockParameter, UInt256 positionIndex)
{
SearchResult<Block> searchResult = _blockFinder.SearchForBlock(blockParameter);
if (searchResult.IsError)
Expand All @@ -469,11 +470,7 @@ public ResultWrapper<TransactionForRpc> eth_getTransactionByBlockNumberAndIndex(
Transaction transaction = block.Transactions[(int)positionIndex];
RecoverTxSenderIfNeeded(transaction);

TransactionForRpc transactionModel = TransactionForRpc.FromTransaction(transaction, block.Hash, block.Number, (int)positionIndex, block.BaseFeePerGas, specProvider.ChainId);

if (_logger.IsDebug)
_logger.Debug(
$"eth_getTransactionByBlockNumberAndIndex request {blockParameter}, index: {positionIndex}, result: {transactionModel.Hash}");
TransactionForRpc transactionModel = TransactionForRpc.FromTransaction(transaction, block.Hash, block.Number, (int)positionIndex, block.BaseFeePerGas, _specProvider.ChainId);
return ResultWrapper<TransactionForRpc>.Success(transactionModel);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

namespace Nethermind.Optimism.Test.Rpc;

public class OptimismTransactionForRpcTests
public class DepositTransactionForRpcTests
{
private readonly IJsonSerializer serializer = new EthereumJsonSerializer();

Expand All @@ -39,7 +39,7 @@ public class OptimismTransactionForRpcTests
[SetUp]
public void SetUp()
{
TransactionForRpc.RegisterTransactionType<OptimismTransactionForRpc>();
TransactionForRpc.RegisterTransactionType<DepositTransactionForRpc>();
}

[TestCaseSource(nameof(Transactions))]
Expand Down Expand Up @@ -75,32 +75,32 @@ private static void ValidateSchema(JsonElement json)
}

private static readonly IEnumerable<(string, string)> MalformedJsonTransactions = [
(nameof(OptimismTransactionForRpc.Gas), """{"type":"0x7e","nonce":null,"gasPrice":null,"maxPriorityFeePerGas":null,"maxFeePerGas":null,"value":"0x1","input":"0x616263646566","v":null,"r":null,"s":null,"to":null,"sourceHash":"0x0000000000000000000000000000000000000000000000000000000000000000","from":"0x0000000000000000000000000000000000000001","isSystemTx":false,"hash":"0xa4341f3db4363b7ca269a8538bd027b2f8784f84454ca917668642d5f6dffdf9"}"""),
(nameof(OptimismTransactionForRpc.Value), """{"type":"0x7e","nonce":null,"gas": "0x1234", "gasPrice":null,"maxPriorityFeePerGas":null,"maxFeePerGas":null,"input":"0x616263646566","v":null,"r":null,"s":null,"to":null,"sourceHash":"0x0000000000000000000000000000000000000000000000000000000000000000","from":"0x0000000000000000000000000000000000000001","isSystemTx":false,"hash":"0xa4341f3db4363b7ca269a8538bd027b2f8784f84454ca917668642d5f6dffdf9"}"""),
(nameof(OptimismTransactionForRpc.Input), """{"type":"0x7e","nonce":null,"gas": "0x1234", "gasPrice":null,"maxPriorityFeePerGas":null,"maxFeePerGas":null,"value":"0x1","v":null,"r":null,"s":null,"to":null,"sourceHash":"0x0000000000000000000000000000000000000000000000000000000000000000","from":"0x0000000000000000000000000000000000000001","isSystemTx":false,"hash":"0xa4341f3db4363b7ca269a8538bd027b2f8784f84454ca917668642d5f6dffdf9"}"""),
(nameof(OptimismTransactionForRpc.From), """{"type":"0x7e","nonce":null,"gas": "0x1234", "gasPrice":null,"maxPriorityFeePerGas":null,"maxFeePerGas":null,"value":"0x1","input":"0x616263646566","v":null,"r":null,"s":null,"to":null,"sourceHash":"0x0000000000000000000000000000000000000000000000000000000000000000","isSystemTx":false,"hash":"0xa4341f3db4363b7ca269a8538bd027b2f8784f84454ca917668642d5f6dffdf9"}"""),
(nameof(OptimismTransactionForRpc.SourceHash), """{"type":"0x7e","nonce":null,"gas": "0x1234", "gasPrice":null,"maxPriorityFeePerGas":null,"maxFeePerGas":null,"value":"0x1","input":"0x616263646566","v":null,"r":null,"s":null,"to":null,"from":"0x0000000000000000000000000000000000000001","isSystemTx":false,"hash":"0xa4341f3db4363b7ca269a8538bd027b2f8784f84454ca917668642d5f6dffdf9"}"""),
(nameof(DepositTransactionForRpc.Gas), """{"type":"0x7e","nonce":null,"gasPrice":null,"maxPriorityFeePerGas":null,"maxFeePerGas":null,"value":"0x1","input":"0x616263646566","v":null,"r":null,"s":null,"to":null,"sourceHash":"0x0000000000000000000000000000000000000000000000000000000000000000","from":"0x0000000000000000000000000000000000000001","isSystemTx":false,"hash":"0xa4341f3db4363b7ca269a8538bd027b2f8784f84454ca917668642d5f6dffdf9"}"""),
(nameof(DepositTransactionForRpc.Value), """{"type":"0x7e","nonce":null,"gas": "0x1234", "gasPrice":null,"maxPriorityFeePerGas":null,"maxFeePerGas":null,"input":"0x616263646566","v":null,"r":null,"s":null,"to":null,"sourceHash":"0x0000000000000000000000000000000000000000000000000000000000000000","from":"0x0000000000000000000000000000000000000001","isSystemTx":false,"hash":"0xa4341f3db4363b7ca269a8538bd027b2f8784f84454ca917668642d5f6dffdf9"}"""),
(nameof(DepositTransactionForRpc.Input), """{"type":"0x7e","nonce":null,"gas": "0x1234", "gasPrice":null,"maxPriorityFeePerGas":null,"maxFeePerGas":null,"value":"0x1","v":null,"r":null,"s":null,"to":null,"sourceHash":"0x0000000000000000000000000000000000000000000000000000000000000000","from":"0x0000000000000000000000000000000000000001","isSystemTx":false,"hash":"0xa4341f3db4363b7ca269a8538bd027b2f8784f84454ca917668642d5f6dffdf9"}"""),
(nameof(DepositTransactionForRpc.From), """{"type":"0x7e","nonce":null,"gas": "0x1234", "gasPrice":null,"maxPriorityFeePerGas":null,"maxFeePerGas":null,"value":"0x1","input":"0x616263646566","v":null,"r":null,"s":null,"to":null,"sourceHash":"0x0000000000000000000000000000000000000000000000000000000000000000","isSystemTx":false,"hash":"0xa4341f3db4363b7ca269a8538bd027b2f8784f84454ca917668642d5f6dffdf9"}"""),
(nameof(DepositTransactionForRpc.SourceHash), """{"type":"0x7e","nonce":null,"gas": "0x1234", "gasPrice":null,"maxPriorityFeePerGas":null,"maxFeePerGas":null,"value":"0x1","input":"0x616263646566","v":null,"r":null,"s":null,"to":null,"from":"0x0000000000000000000000000000000000000001","isSystemTx":false,"hash":"0xa4341f3db4363b7ca269a8538bd027b2f8784f84454ca917668642d5f6dffdf9"}"""),
];

[TestCaseSource(nameof(MalformedJsonTransactions))]
public void Rejects_malformed_transaction_missing_field((string missingField, string json) testCase)
{
var rpcTx = serializer.Deserialize<OptimismTransactionForRpc>(testCase.json);
var rpcTx = serializer.Deserialize<DepositTransactionForRpc>(testCase.json);
rpcTx.Should().NotBeNull();

var toTransaction = rpcTx.ToTransaction;
toTransaction.Should().Throw<ArgumentNullException>().WithParameterName(testCase.missingField);
}

private static readonly IEnumerable<(string, string)> ValidJsonTransactions = [
(nameof(OptimismTransactionForRpc.Mint), """{"type":"0x7e","nonce":null,"gas": "0x1234", "gasPrice":null,"maxPriorityFeePerGas":null,"maxFeePerGas":null,"value":"0x1","input":"0x616263646566","v":null,"r":null,"s":null,"to":null,"sourceHash":"0x0000000000000000000000000000000000000000000000000000000000000000","from":"0x0000000000000000000000000000000000000001","isSystemTx":false,"hash":"0xa4341f3db4363b7ca269a8538bd027b2f8784f84454ca917668642d5f6dffdf9"}"""),
(nameof(OptimismTransactionForRpc.IsSystemTx), """{"type":"0x7e","nonce":null,"gas": "0x1234", "gasPrice":null,"maxPriorityFeePerGas":null,"maxFeePerGas":null,"value":"0x1","input":"0x616263646566","v":null,"r":null,"s":null,"to":null,"sourceHash":"0x0000000000000000000000000000000000000000000000000000000000000000","from":"0x0000000000000000000000000000000000000001","hash":"0xa4341f3db4363b7ca269a8538bd027b2f8784f84454ca917668642d5f6dffdf9"}"""),
(nameof(DepositTransactionForRpc.Mint), """{"type":"0x7e","nonce":null,"gas": "0x1234", "gasPrice":null,"maxPriorityFeePerGas":null,"maxFeePerGas":null,"value":"0x1","input":"0x616263646566","v":null,"r":null,"s":null,"to":null,"sourceHash":"0x0000000000000000000000000000000000000000000000000000000000000000","from":"0x0000000000000000000000000000000000000001","isSystemTx":false,"hash":"0xa4341f3db4363b7ca269a8538bd027b2f8784f84454ca917668642d5f6dffdf9"}"""),
(nameof(DepositTransactionForRpc.IsSystemTx), """{"type":"0x7e","nonce":null,"gas": "0x1234", "gasPrice":null,"maxPriorityFeePerGas":null,"maxFeePerGas":null,"value":"0x1","input":"0x616263646566","v":null,"r":null,"s":null,"to":null,"sourceHash":"0x0000000000000000000000000000000000000000000000000000000000000000","from":"0x0000000000000000000000000000000000000001","hash":"0xa4341f3db4363b7ca269a8538bd027b2f8784f84454ca917668642d5f6dffdf9"}"""),
];

[TestCaseSource(nameof(ValidJsonTransactions))]
public void Accepts_valid_transaction_missing_field((string missingField, string json) testCase)
{
var rpcTx = serializer.Deserialize<OptimismTransactionForRpc>(testCase.json);
var rpcTx = serializer.Deserialize<DepositTransactionForRpc>(testCase.json);
rpcTx.Should().NotBeNull();

var toTransaction = rpcTx.ToTransaction;
Expand Down
Loading