From e10894264a47323b2de0e51fda4b8ec58ac4d098 Mon Sep 17 00:00:00 2001 From: Lautaro Emanuel Date: Fri, 31 Jan 2025 17:14:26 -0300 Subject: [PATCH 01/16] Use `TransactionForRpc` - Rename `OptimismTransactionForRpc` to `DepositTransactionForRpc` - Do not map everything to `DepositTransactionForRpc` - Remove `new` methods on `IOptimismEthRpcModule` --- .../Modules/Eth/EthRpcModule.cs | 6 +- ...ts.cs => DepositTransactionForRpcTests.cs} | 22 +++--- .../InitializeBlockchainOptimism.cs | 2 +- .../Nethermind.Optimism/OptimismPlugin.cs | 2 +- ...nForRpc.cs => DepositTransactionForRpc.cs} | 8 +-- .../Rpc/IOptimismEthRpcModule.cs | 23 ------ .../Rpc/OptimismEthRpcModule.cs | 70 ++++++++++++------- 7 files changed, 63 insertions(+), 70 deletions(-) rename src/Nethermind/Nethermind.Optimism.Test/Rpc/{OptimismTransactionForRpcTests.cs => DepositTransactionForRpcTests.cs} (56%) rename src/Nethermind/Nethermind.Optimism/Rpc/{OptimismTransactionForRpc.cs => DepositTransactionForRpc.cs} (87%) diff --git a/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/EthRpcModule.cs b/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/EthRpcModule.cs index 4a929e9060b..f0a0e2eedd6 100644 --- a/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/EthRpcModule.cs +++ b/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/EthRpcModule.cs @@ -384,7 +384,7 @@ public ResultWrapper eth_getBlockByNumber(BlockParameter blockParam : new BlockForRpc(block, returnFullTransactionObjects, _specProvider)); } - public ResultWrapper eth_getTransactionByHash(Hash256 transactionHash) + public virtual ResultWrapper eth_getTransactionByHash(Hash256 transactionHash) { (TxReceipt? receipt, Transaction? transaction, UInt256? baseFee) = _blockchainBridge.GetTransaction(transactionHash, checkTxnPool: true); if (transaction is null) @@ -428,7 +428,7 @@ public ResultWrapper eth_pendingTransactions() return ResultWrapper.Success(transactionsModels); } - public ResultWrapper eth_getTransactionByBlockHashAndIndex(Hash256 blockHash, + public virtual ResultWrapper eth_getTransactionByBlockHashAndIndex(Hash256 blockHash, UInt256 positionIndex) { SearchResult searchResult = _blockFinder.SearchForBlock(new BlockParameter(blockHash)); @@ -451,7 +451,7 @@ public ResultWrapper eth_getTransactionByBlockHashAndIndex(Ha return ResultWrapper.Success(transactionModel); } - public ResultWrapper eth_getTransactionByBlockNumberAndIndex(BlockParameter blockParameter, + public virtual ResultWrapper eth_getTransactionByBlockNumberAndIndex(BlockParameter blockParameter, UInt256 positionIndex) { SearchResult searchResult = _blockFinder.SearchForBlock(blockParameter); diff --git a/src/Nethermind/Nethermind.Optimism.Test/Rpc/OptimismTransactionForRpcTests.cs b/src/Nethermind/Nethermind.Optimism.Test/Rpc/DepositTransactionForRpcTests.cs similarity index 56% rename from src/Nethermind/Nethermind.Optimism.Test/Rpc/OptimismTransactionForRpcTests.cs rename to src/Nethermind/Nethermind.Optimism.Test/Rpc/DepositTransactionForRpcTests.cs index a0fa69393e8..6f199a5f6ba 100644 --- a/src/Nethermind/Nethermind.Optimism.Test/Rpc/OptimismTransactionForRpcTests.cs +++ b/src/Nethermind/Nethermind.Optimism.Test/Rpc/DepositTransactionForRpcTests.cs @@ -15,7 +15,7 @@ namespace Nethermind.Optimism.Test.Rpc; -public class OptimismTransactionForRpcTests +public class DepositTransactionForRpcTests { private readonly IJsonSerializer serializer = new EthereumJsonSerializer(); @@ -39,7 +39,7 @@ public class OptimismTransactionForRpcTests [SetUp] public void SetUp() { - TransactionForRpc.RegisterTransactionType(); + TransactionForRpc.RegisterTransactionType(); } [TestCaseSource(nameof(Transactions))] @@ -75,17 +75,17 @@ 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(testCase.json); + var rpcTx = serializer.Deserialize(testCase.json); rpcTx.Should().NotBeNull(); var toTransaction = rpcTx.ToTransaction; @@ -93,14 +93,14 @@ public void Rejects_malformed_transaction_missing_field((string missingField, st } 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(testCase.json); + var rpcTx = serializer.Deserialize(testCase.json); rpcTx.Should().NotBeNull(); var toTransaction = rpcTx.ToTransaction; diff --git a/src/Nethermind/Nethermind.Optimism/InitializeBlockchainOptimism.cs b/src/Nethermind/Nethermind.Optimism/InitializeBlockchainOptimism.cs index ee2def2ac81..bd350b494b7 100644 --- a/src/Nethermind/Nethermind.Optimism/InitializeBlockchainOptimism.cs +++ b/src/Nethermind/Nethermind.Optimism/InitializeBlockchainOptimism.cs @@ -38,7 +38,7 @@ protected override async Task InitBlockchain() await base.InitBlockchain(); - api.RegisterTxType(new OptimismTxDecoder(), Always.Valid); + api.RegisterTxType(new OptimismTxDecoder(), Always.Valid); api.RegisterTxType(new OptimismLegacyTxDecoder(), new OptimismLegacyTxValidator(api.SpecProvider!.ChainId)); } diff --git a/src/Nethermind/Nethermind.Optimism/OptimismPlugin.cs b/src/Nethermind/Nethermind.Optimism/OptimismPlugin.cs index b0a87e678b6..3ebf564efe4 100644 --- a/src/Nethermind/Nethermind.Optimism/OptimismPlugin.cs +++ b/src/Nethermind/Nethermind.Optimism/OptimismPlugin.cs @@ -90,7 +90,7 @@ public void InitTxTypesAndRlpDecoders(INethermindApi api) { if (ShouldRunSteps(api)) { - api.RegisterTxType(new OptimismTxDecoder(), Always.Valid); + api.RegisterTxType(new OptimismTxDecoder(), Always.Valid); api.RegisterTxType(new OptimismLegacyTxDecoder(), new OptimismLegacyTxValidator(api.SpecProvider!.ChainId)); Rlp.RegisterDecoders(typeof(OptimismReceiptMessageDecoder).Assembly, true); } diff --git a/src/Nethermind/Nethermind.Optimism/Rpc/OptimismTransactionForRpc.cs b/src/Nethermind/Nethermind.Optimism/Rpc/DepositTransactionForRpc.cs similarity index 87% rename from src/Nethermind/Nethermind.Optimism/Rpc/OptimismTransactionForRpc.cs rename to src/Nethermind/Nethermind.Optimism/Rpc/DepositTransactionForRpc.cs index fba5f35ba18..fcc4309bb31 100644 --- a/src/Nethermind/Nethermind.Optimism/Rpc/OptimismTransactionForRpc.cs +++ b/src/Nethermind/Nethermind.Optimism/Rpc/DepositTransactionForRpc.cs @@ -16,7 +16,7 @@ namespace Nethermind.Optimism.Rpc; /// - https://github.com/ethereum-optimism/op-geth/blob/8af19cf20261c0b62f98cc27da3a268f542822ee/core/types/deposit_tx.go#L29-L46 /// - https://specs.optimism.io/protocol/deposits.html#the-deposited-transaction-type /// -public class OptimismTransactionForRpc : TransactionForRpc, IFromTransaction +public class DepositTransactionForRpc : TransactionForRpc, IFromTransaction { public static TxType TxType => TxType.DepositTx; @@ -47,9 +47,9 @@ public class OptimismTransactionForRpc : TransactionForRpc, IFromTransaction false; - public static OptimismTransactionForRpc FromTransaction(Transaction tx, TransactionConverterExtraData extraData) + public static DepositTransactionForRpc FromTransaction(Transaction tx, TransactionConverterExtraData extraData) => new(tx, txIndex: extraData.TxIndex, blockHash: extraData.BlockHash, blockNumber: extraData.BlockNumber, receipt: extraData.Receipt as OptimismTxReceipt); } diff --git a/src/Nethermind/Nethermind.Optimism/Rpc/IOptimismEthRpcModule.cs b/src/Nethermind/Nethermind.Optimism/Rpc/IOptimismEthRpcModule.cs index 7ceb0bad4d1..74fcab0ebf8 100644 --- a/src/Nethermind/Nethermind.Optimism/Rpc/IOptimismEthRpcModule.cs +++ b/src/Nethermind/Nethermind.Optimism/Rpc/IOptimismEthRpcModule.cs @@ -6,7 +6,6 @@ using Nethermind.Core.Crypto; using Nethermind.JsonRpc; using Nethermind.Blockchain.Find; -using Nethermind.Int256; namespace Nethermind.Optimism.Rpc; @@ -18,31 +17,9 @@ public interface IOptimismEthRpcModule : IEthRpcModule ExampleResponse = "{\"jsonrpc\":\"2.0\",\"result\":[{\"transactionHash\":\"0x681c2b6f99e37fd6fe6046db8b51ec3460d699cacd6a376143fd5842ac50621f\",\"transactionIndex\":\"0x0\",\"blockHash\":\"0x29f141925d2d8e357ae5b6040c97aa12d7ac6dfcbe2b20e7b616d8907ac8e1f3\",\"blockNumber\":\"0x3\",\"cumulativeGasUsed\":\"0x5208\",\"gasUsed\":\"0x5208\",\"effectiveGasPrice\":\"0x1\",\"from\":\"0xb7705ae4c6f81b66cdb323c65f4e8133690fc099\",\"to\":\"0x942921b14f1b1c385cd7e0cc2ef7abe5598c8358\",\"contractAddress\":null,\"logs\":[],\"logsBloom\":\"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\"status\":\"0x1\",\"type\":\"0x0\"},{\"transactionHash\":\"0x7126cf20a0ad8bd51634837d9049615c34c1bff5e1a54e5663f7e23109bff48b\",\"transactionIndex\":\"0x1\",\"blockHash\":\"0x29f141925d2d8e357ae5b6040c97aa12d7ac6dfcbe2b20e7b616d8907ac8e1f3\",\"blockNumber\":\"0x3\",\"cumulativeGasUsed\":\"0xa410\",\"gasUsed\":\"0x5208\",\"effectiveGasPrice\":\"0x1\",\"from\":\"0xb7705ae4c6f81b66cdb323c65f4e8133690fc099\",\"to\":\"0x942921b14f1b1c385cd7e0cc2ef7abe5598c8358\",\"contractAddress\":null,\"logs\":[],\"logsBloom\":\"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\"status\":\"0x1\",\"type\":\"0x0\"}],\"id\":67}")] new ResultWrapper eth_getBlockReceipts([JsonRpcParameter(ExampleValue = "latest")] BlockParameter blockParameter); - [JsonRpcMethod(IsImplemented = true, Description = "Retrieves a transaction receipt by tx hash", IsSharable = true, ExampleResponse = "{\"transactionHash\":\"0x80757153e93d1b475e203406727b62a501187f63e23b8fa999279e219ee3be71\",\"transactionIndex\":\"0x7\",\"blockHash\":\"0x42def051b21038905cd2a2bc28d460a94df2249466847f0e1bcb4be4eb21891a\",\"blockNumber\":\"0x4e3f39\",\"cumulativeGasUsed\":\"0x62c9d\",\"gasUsed\":\"0xe384\",\"effectiveGasPrice\":\"0x12a05f200\",\"from\":\"0x0afe0a94415e8974052e7e6cfab19ee1c2ef4f69\",\"to\":\"0x19e8c84d4943e58b035626b064cfc76ee13ee6cb\",\"contractAddress\":null,\"logs\":[{\"removed\":false,\"logIndex\":\"0x0\",\"transactionIndex\":\"0x7\",\"transactionHash\":\"0x80757153e93d1b475e203406727b62a501187f63e23b8fa999279e219ee3be71\",\"blockHash\":\"0x42def051b21038905cd2a2bc28d460a94df2249466847f0e1bcb4be4eb21891a\",\"blockNumber\":\"0x4e3f39\",\"address\":\"0x2ac3c1d3e24b45c6c310534bc2dd84b5ed576335\",\"data\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"topics\":[\"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef\",\"0x00000000000000000000000019e8c84d4943e58b035626b064cfc76ee13ee6cb\",\"0x00000000000000000000000028078300a459a9e136f872285654cdc74463041e\"]},{\"removed\":false,\"logIndex\":\"0x1\",\"transactionIndex\":\"0x7\",\"transactionHash\":\"0x80757153e93d1b475e203406727b62a501187f63e23b8fa999279e219ee3be71\",\"blockHash\":\"0x42def051b21038905cd2a2bc28d460a94df2249466847f0e1bcb4be4eb21891a\",\"blockNumber\":\"0x4e3f39\",\"address\":\"0x19e8c84d4943e58b035626b064cfc76ee13ee6cb\",\"data\":\"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007735940000000000000000000000000000000000000000000000000000000000000000000\",\"topics\":[\"0x950494fc3642fae5221b6c32e0e45765c95ebb382a04a71b160db0843e74c99f\",\"0x0000000000000000000000000afe0a94415e8974052e7e6cfab19ee1c2ef4f69\",\"0x00000000000000000000000028078300a459a9e136f872285654cdc74463041e\",\"0x0000000000000000000000000afe0a94415e8974052e7e6cfab19ee1c2ef4f69\"]}],\"logsBloom\":\"0x00000000000000000000000000000000000000000000000020000000000000800000000000000000000400000000000000000000000000000000000000002000000000000000000000000008000000000000000000000000000000000000000000000002002000000000000000000000000000000000000000000812000000000000000000000000000001000000000000000000000008000400008000000000000000000000000000000000000000000000000000000000800000000000000000000002000000000000000000000000000000000000100000000000000000002000000000000000000000000010000000000000000000000400000000020000\",\"status\":\"0x1\",\"type\":\"0x0\"}")] new ResultWrapper eth_getTransactionReceipt([JsonRpcParameter(ExampleValue = "[\"0x80757153e93d1b475e203406727b62a501187f63e23b8fa999279e219ee3be71\"]")] Hash256 txHashData); - - [JsonRpcMethod(IsImplemented = true, - Description = "Retrieves a transaction by hash", - IsSharable = true, - ExampleResponse = "{\"hash\":\"0xabca23910646013d608ec671de099447ab60b2b7159ad8319c3c088e8d9ea0fa\",\"nonce\":\"0x1a\",\"blockHash\":\"0xcb6756f69e0469acd5e5bb77966be580786ec2c11de85c9ddfd75257010e34f8\",\"blockNumber\":\"0x4dfbc7\",\"transactionIndex\":\"0xb\",\"from\":\"0xe1e7ab1c643dbe5b24739fdf2a5c7c193b54dd99\",\"to\":\"0x0b10e304088b2ba2b2acfd2f72573faad31a13a5\",\"value\":\"0x0\",\"gasPrice\":\"0x2540be400\",\"gas\":\"0xb4a4\",\"data\":\"0x095ea7b300000000000000000000000092c1576845703089cf6c0788379ed81f75f45dd500000000000000000000000000000000000000000000000000000002540be400\",\"input\":\"0x095ea7b300000000000000000000000092c1576845703089cf6c0788379ed81f75f45dd500000000000000000000000000000000000000000000000000000002540be400\",\"type\":\"0x0\",\"v\":\"0x2d\",\"s\":\"0x496d72d435ead8a8a9a865b14d6a102c1a9f848681d050dbbf11c522c612235\",\"r\":\"0xc8350e831203fecc8bff41f5cf858ac1d121e4b4d9e59c1137cc9440516ca9fd\"}")] - new ResultWrapper eth_getTransactionByHash( - [JsonRpcParameter(ExampleValue = "\"0xabca23910646013d608ec671de099447ab60b2b7159ad8319c3c088e8d9ea0fa\"")] Hash256 transactionHash); - - [JsonRpcMethod(IsImplemented = true, - Description = "Retrieves a transaction by block hash and index", - IsSharable = true, - ExampleResponse = "{\"hash\":\"0xb87ec4c8cb36a06f49cdd93c2e9f63e0b7db9af07a605c8bcf1fbe705162344e\",\"nonce\":\"0x5d\",\"blockHash\":\"0xfe47fb3539ccce9d19a032473effdd6ce19e3c921bbae2746152ccf82ceef48e\",\"blockNumber\":\"0x4dfc90\",\"transactionIndex\":\"0x2\",\"from\":\"0xaa9a0f962e433755c843175488fe088fccf8526f\",\"to\":\"0x074b24cef703f17fe123fa1b82081055775b7004\",\"value\":\"0x0\",\"gasPrice\":\"0x2540be401\",\"gas\":\"0x130ab\",\"data\":\"0x428dc451000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000030000000000000000000000005d3c0f4ca5ee99f8e8f59ff9a5fab04f6a7e007f0000000000000000000000009d233a907e065855d2a9c7d4b552ea27fb2e5a36000000000000000000000000cbe56b00d173a26a5978ce90db2e33622fd95a28\",\"input\":\"0x428dc451000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000030000000000000000000000005d3c0f4ca5ee99f8e8f59ff9a5fab04f6a7e007f0000000000000000000000009d233a907e065855d2a9c7d4b552ea27fb2e5a36000000000000000000000000cbe56b00d173a26a5978ce90db2e33622fd95a28\",\"type\":\"0x0\",\"v\":\"0x2e\",\"s\":\"0x696f6db060a6dd30435a7f592506ba3213f81cf4704e211a1a45a99f8984189a\",\"r\":\"0x7e07076186e38b68cb7e4f68a04258a5744c5a2ad1a7153456ee662a07902954\"}")] - new ResultWrapper eth_getTransactionByBlockHashAndIndex( - [JsonRpcParameter(ExampleValue = "[\"0xfe47fb3539ccce9d19a032473effdd6ce19e3c921bbae2746152ccf82ceef48e\",\"0x2\"]")] Hash256 blockHash, UInt256 positionIndex); - - [JsonRpcMethod(IsImplemented = true, - Description = "Retrieves a transaction by block number and index", - IsSharable = true, - ExampleResponse = "{\"hash\":\"0xfd320a4949990929f64b52041c58a74c8ce13289b3d6853bd8073b0580aa031a\",\"nonce\":\"0x5b\",\"blockHash\":\"0xd779e1a5ce8f34544d66d219bb3e5331a7b280fae89a36d7d52813a23e1ca1e3\",\"blockNumber\":\"0x4dfdd8\",\"transactionIndex\":\"0x8\",\"from\":\"0xadb540569e2db497bd973c141b0b63be98461e40\",\"to\":\"0x074b24cef703f17fe123fa1b82081055775b7004\",\"value\":\"0x0\",\"gasPrice\":\"0x12a05f200\",\"gas\":\"0x927c0\",\"data\":\"0x428dc451000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000030000000000000000000000005d3c0f4ca5ee99f8e8f59ff9a5fab04f6a7e007f0000000000000000000000009d233a907e065855d2a9c7d4b552ea27fb2e5a36000000000000000000000000cbe56b00d173a26a5978ce90db2e33622fd95a28\",\"input\":\"0x428dc451000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000030000000000000000000000005d3c0f4ca5ee99f8e8f59ff9a5fab04f6a7e007f0000000000000000000000009d233a907e065855d2a9c7d4b552ea27fb2e5a36000000000000000000000000cbe56b00d173a26a5978ce90db2e33622fd95a28\",\"type\":\"0x0\",\"v\":\"0x2e\",\"s\":\"0x37b90a929884787df717c87258f0434e2f115ce2fbb4bfc230322112fa9d5bbc\",\"r\":\"0x5222eff9e16b5c3e9e8901d9c45fc8e0f9cf774e8a56546a504025ef67ceefec\"}")] - new ResultWrapper eth_getTransactionByBlockNumberAndIndex( - [JsonRpcParameter(ExampleValue = "[\"5111256\",\"0x8\"]")] BlockParameter blockParameter, UInt256 positionIndex); } diff --git a/src/Nethermind/Nethermind.Optimism/Rpc/OptimismEthRpcModule.cs b/src/Nethermind/Nethermind.Optimism/Rpc/OptimismEthRpcModule.cs index de2fa1d4540..4b4f93dac44 100644 --- a/src/Nethermind/Nethermind.Optimism/Rpc/OptimismEthRpcModule.cs +++ b/src/Nethermind/Nethermind.Optimism/Rpc/OptimismEthRpcModule.cs @@ -160,60 +160,65 @@ public override async Task> eth_sendRawTransaction(byte[] new(txHash, (OptimismTxReceipt)receipt, gasInfo.Value, l1GasInfo.GetTxGasInfo(block.Transactions.First(tx => tx.Hash == txHash)), logIndexStart)); } - public new ResultWrapper eth_getTransactionByHash(Hash256 transactionHash) + public override ResultWrapper eth_getTransactionByHash(Hash256 transactionHash) { (TxReceipt? receipt, Transaction? transaction, _) = _blockchainBridge.GetTransaction(transactionHash, checkTxnPool: true); if (transaction is null) { - return ResultWrapper.Success(null); + return ResultWrapper.Success(null); } RecoverTxSenderIfNeeded(transaction); - OptimismTransactionForRpc transactionModel = new OptimismTransactionForRpc(transaction, blockHash: receipt?.BlockHash, receipt: receipt as OptimismTxReceipt); + var transactionModel = TransactionForRpc.FromTransaction(transaction, blockHash: receipt?.BlockHash); + if (transactionModel is DepositTransactionForRpc depositTx) + { + depositTx.DepositReceiptVersion = (receipt as OptimismTxReceipt)?.DepositReceiptVersion; + } if (_logger.IsTrace) _logger.Trace($"eth_getTransactionByHash request {transactionHash}, result: {transactionModel.Hash}"); - return ResultWrapper.Success(transactionModel); + return ResultWrapper.Success(transactionModel); } - public new ResultWrapper eth_getTransactionByBlockHashAndIndex(Hash256 blockHash, UInt256 positionIndex) + public override ResultWrapper eth_getTransactionByBlockHashAndIndex(Hash256 blockHash, UInt256 positionIndex) { SearchResult searchResult = _blockFinder.SearchForBlock(new BlockParameter(blockHash)); if (searchResult.IsError || searchResult.Object is null) { - return GetFailureResult(searchResult, _ethSyncingInfo.SyncMode.HaveNotSyncedBodiesYet()); + return GetFailureResult(searchResult, _ethSyncingInfo.SyncMode.HaveNotSyncedBodiesYet()); } Block block = searchResult.Object; if (positionIndex < 0 || positionIndex > block!.Transactions.Length - 1) { - return ResultWrapper.Fail("Position Index is incorrect", ErrorCodes.InvalidParams); + return ResultWrapper.Fail("Position Index is incorrect", ErrorCodes.InvalidParams); } OptimismTxReceipt[] receipts = _receiptFinder.Get(block).Cast().ToArray(); Transaction transaction = block.Transactions[(int)positionIndex]; RecoverTxSenderIfNeeded(transaction); - OptimismTransactionForRpc transactionModel = new OptimismTransactionForRpc( - transaction, - blockHash: block.Hash, - receipt: receipts.FirstOrDefault(r => r.TxHash == transaction.Hash)); + var transactionModel = TransactionForRpc.FromTransaction(transaction, blockHash: block.Hash); + if (transactionModel is DepositTransactionForRpc depositTx) + { + OptimismTxReceipt? receipt = receipts.FirstOrDefault(r => r.TxHash == transaction.Hash); + depositTx.DepositReceiptVersion = receipt?.DepositReceiptVersion; + } - return ResultWrapper.Success(transactionModel); + return ResultWrapper.Success(transactionModel); } - public new ResultWrapper eth_getTransactionByBlockNumberAndIndex(BlockParameter blockParameter, - UInt256 positionIndex) + public override ResultWrapper eth_getTransactionByBlockNumberAndIndex(BlockParameter blockParameter, UInt256 positionIndex) { SearchResult searchResult = _blockFinder.SearchForBlock(blockParameter); if (searchResult.IsError) { - return GetFailureResult(searchResult, _ethSyncingInfo.SyncMode.HaveNotSyncedBodiesYet()); + return GetFailureResult(searchResult, _ethSyncingInfo.SyncMode.HaveNotSyncedBodiesYet()); } Block? block = searchResult.Object; if (positionIndex < 0 || positionIndex > block!.Transactions.Length - 1) { - return ResultWrapper.Fail("Position Index is incorrect", ErrorCodes.InvalidParams); + return ResultWrapper.Fail("Position Index is incorrect", ErrorCodes.InvalidParams); } OptimismTxReceipt[] receipts = _receiptFinder.Get(block).Cast().ToArray(); @@ -221,15 +226,17 @@ public override async Task> eth_sendRawTransaction(byte[] Transaction transaction = block.Transactions[(int)positionIndex]; RecoverTxSenderIfNeeded(transaction); - OptimismTransactionForRpc transactionModel = new OptimismTransactionForRpc( - transaction, - blockHash: block.Hash, - receipt: receipts.FirstOrDefault(r => r.TxHash == transaction.Hash)); + var transactionModel = TransactionForRpc.FromTransaction(transaction, blockHash: block.Hash); + if (transactionModel is DepositTransactionForRpc depositTx) + { + OptimismTxReceipt? receipt = receipts.FirstOrDefault(r => r.TxHash == transaction.Hash); + depositTx.DepositReceiptVersion = receipt?.DepositReceiptVersion; + } if (_logger.IsDebug) _logger.Debug( $"eth_getTransactionByBlockNumberAndIndex request {blockParameter}, index: {positionIndex}, result: {transactionModel.Hash}"); - return ResultWrapper.Success(transactionModel); + return ResultWrapper.Success(transactionModel); } protected override ResultWrapper GetBlock(BlockParameter blockParameter, bool returnFullTransactionObjects) @@ -254,12 +261,21 @@ public override async Task> eth_sendRawTransaction(byte[] if (returnFullTransactionObjects) { _blockchainBridge.RecoverTxSenders(block); - result.Transactions = result.Transactions.Select((hash, index) => new OptimismTransactionForRpc( - transaction: block.Transactions[index], - blockHash: block.Hash, - blockNumber: block.Number, - txIndex: index, - receipt: receipts.FirstOrDefault(r => r.TxHash?.Equals(hash) ?? false))); + result.Transactions = result.Transactions.Select((hash, index) => + { + var transactionModel = TransactionForRpc.FromTransaction( + transaction: block.Transactions[index], + blockHash: block.Hash, + blockNumber: block.Number, + txIndex: index); + if (transactionModel is DepositTransactionForRpc depositTx) + { + var receipt = receipts.FirstOrDefault(r => r.TxHash?.Equals(hash) ?? false); + depositTx.DepositReceiptVersion = receipt?.DepositReceiptVersion; + } + + return transactionModel; + }); } return ResultWrapper.Success(result); From 3f31a866f93f3f5400bc8f9fcbba1996ccc81e6e Mon Sep 17 00:00:00 2001 From: Lautaro Emanuel Date: Mon, 3 Feb 2025 11:45:17 -0300 Subject: [PATCH 02/16] Use `FluentAssertions` - Remove unused `using`s --- .../Nethermind.Optimism.Test/Rpc/OptimismEthRpcModuleTest.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Nethermind/Nethermind.Optimism.Test/Rpc/OptimismEthRpcModuleTest.cs b/src/Nethermind/Nethermind.Optimism.Test/Rpc/OptimismEthRpcModuleTest.cs index e25b2f77874..6d25d39950d 100644 --- a/src/Nethermind/Nethermind.Optimism.Test/Rpc/OptimismEthRpcModuleTest.cs +++ b/src/Nethermind/Nethermind.Optimism.Test/Rpc/OptimismEthRpcModuleTest.cs @@ -2,7 +2,7 @@ // SPDX-License-Identifier: LGPL-3.0-only using System.Threading.Tasks; -using Nethermind.Blockchain.Blocks; +using FluentAssertions; using Nethermind.Blockchain.Synchronization; using Nethermind.Config; using Nethermind.Core; @@ -18,7 +18,6 @@ using Nethermind.Optimism.Rpc; using Nethermind.Serialization.Rlp; using Nethermind.Synchronization; -using Nethermind.Synchronization.FastBlocks; using Nethermind.Synchronization.ParallelSync; using Nethermind.TxPool; using NSubstitute; @@ -55,7 +54,7 @@ public async Task Sequencer_send_transaction_with_signature_will_not_try_to_sign string serialized = await rpcBlockchain.TestEthRpc("eth_sendRawTransaction", Rlp.Encode(item: tx, behaviors: RlpBehaviors.None).Bytes.ToHexString()); await txSender.Received().SendTransaction(tx: Arg.Any(), txHandlingOptions: TxHandlingOptions.PersistentBroadcast); - Assert.That(actual: serialized, expression: Is.EqualTo(expected: $$"""{"jsonrpc":"2.0","result":"{{TestItem.KeccakA.Bytes.ToHexString(withZeroX: true)}}","id":67}""")); + serialized.Should().BeEquivalentTo($$"""{"jsonrpc":"2.0","result":"{{TestItem.KeccakA.Bytes.ToHexString(withZeroX: true)}}","id":67}"""); } } From dff88774306743e78aedbfcc03d9a93326c591ad Mon Sep 17 00:00:00 2001 From: Lautaro Emanuel Date: Mon, 3 Feb 2025 12:32:08 -0300 Subject: [PATCH 03/16] Test `GetTransactionByHash_IncludesDepositReceiptVersion` --- .../Rpc/OptimismEthRpcModuleTest.cs | 68 +++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/src/Nethermind/Nethermind.Optimism.Test/Rpc/OptimismEthRpcModuleTest.cs b/src/Nethermind/Nethermind.Optimism.Test/Rpc/OptimismEthRpcModuleTest.cs index 6d25d39950d..139dcee1988 100644 --- a/src/Nethermind/Nethermind.Optimism.Test/Rpc/OptimismEthRpcModuleTest.cs +++ b/src/Nethermind/Nethermind.Optimism.Test/Rpc/OptimismEthRpcModuleTest.cs @@ -3,6 +3,7 @@ using System.Threading.Tasks; using FluentAssertions; +using FluentAssertions.Json; using Nethermind.Blockchain.Synchronization; using Nethermind.Config; using Nethermind.Core; @@ -11,6 +12,8 @@ using Nethermind.Crypto; using Nethermind.Facade; using Nethermind.Facade.Eth; +using Nethermind.Facade.Eth.RpcTransaction; +using Nethermind.Int256; using Nethermind.JsonRpc.Client; using Nethermind.JsonRpc.Modules.Eth.FeeHistory; using Nethermind.JsonRpc.Test.Modules; @@ -20,6 +23,7 @@ using Nethermind.Synchronization; using Nethermind.Synchronization.ParallelSync; using Nethermind.TxPool; +using Newtonsoft.Json.Linq; using NSubstitute; using NUnit.Framework; @@ -27,6 +31,14 @@ namespace Nethermind.Optimism.Test.Rpc; public class OptimismEthRpcModuleTest { + [SetUp] + public void Setup() + { + TransactionForRpc.RegisterTransactionType(); + TxDecoder.Instance.RegisterDecoder(new OptimismTxDecoder()); + TxDecoder.Instance.RegisterDecoder(new OptimismLegacyTxDecoder()); + } + [Test] public async Task Sequencer_send_transaction_with_signature_will_not_try_to_sign() { @@ -56,6 +68,62 @@ public async Task Sequencer_send_transaction_with_signature_will_not_try_to_sign await txSender.Received().SendTransaction(tx: Arg.Any(), txHandlingOptions: TxHandlingOptions.PersistentBroadcast); serialized.Should().BeEquivalentTo($$"""{"jsonrpc":"2.0","result":"{{TestItem.KeccakA.Bytes.ToHexString(withZeroX: true)}}","id":67}"""); } + + [Test] + public async Task GetTransactionByHash_IncludesDepositReceiptVersion() + { + Transaction tx = Build.A.Transaction + .WithType(TxType.DepositTx) + .WithHash(TestItem.KeccakA) + .WithSenderAddress(TestItem.AddressA) + .TestObject; + OptimismTxReceipt receipt = new() + { + BlockHash = TestItem.KeccakB, + DepositReceiptVersion = 0x20, + }; + + IBlockchainBridge bridge = Substitute.For(); + bridge.GetTransaction(TestItem.KeccakA, checkTxnPool: true).Returns((receipt, tx, (UInt256?)0)); + + TestRpcBlockchain rpcBlockchain = await TestRpcBlockchain + .ForTest(sealEngineType: SealEngineType.Optimism) + .WithBlockchainBridge(bridge) + .WithOptimismEthRpcModule( + sequencerRpcClient: Substitute.For(), + accountStateProvider: Substitute.For(), + ecdsa: Substitute.For(), + sealer: Substitute.For(), + opSpecHelper: Substitute.For()) + .Build(); + + + string serialized = await rpcBlockchain.TestEthRpc("eth_getTransactionByHash", TestItem.KeccakA); + var expected = $$""" + { + "jsonrpc":"2.0", + "result": { + "type": "0x7e", + "sourceHash":"0x0000000000000000000000000000000000000000000000000000000000000000", + "from": "{{TestItem.AddressA.Bytes.ToHexString(withZeroX: true)}}", + "to": "0x0000000000000000000000000000000000000000", + "mint": "0x0", + "value": "0x1", + "gas": "0x5208", + "isSystemTx": false, + "input": "0x", + "nonce": "0x0", + "depositReceiptVersion": "0x20", + "hash": "{{TestItem.KeccakA.Bytes.ToHexString(withZeroX: true)}}", + "blockHash": "{{TestItem.KeccakB.Bytes.ToHexString(withZeroX: true)}}", + "transactionIndex": null, + "blockNumber": null + }, + "id":67 + } + """; + JToken.Parse(serialized).Should().BeEquivalentTo(expected); + } } internal static class TestRpcBlockchainExt From 10c6338c783c994bef27c944cbee90b31816e074 Mon Sep 17 00:00:00 2001 From: Lautaro Emanuel Date: Mon, 3 Feb 2025 12:33:43 -0300 Subject: [PATCH 04/16] Formatting --- .../Rpc/OptimismEthRpcModuleTest.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Nethermind/Nethermind.Optimism.Test/Rpc/OptimismEthRpcModuleTest.cs b/src/Nethermind/Nethermind.Optimism.Test/Rpc/OptimismEthRpcModuleTest.cs index 139dcee1988..1375708f108 100644 --- a/src/Nethermind/Nethermind.Optimism.Test/Rpc/OptimismEthRpcModuleTest.cs +++ b/src/Nethermind/Nethermind.Optimism.Test/Rpc/OptimismEthRpcModuleTest.cs @@ -103,7 +103,7 @@ public async Task GetTransactionByHash_IncludesDepositReceiptVersion() { "jsonrpc":"2.0", "result": { - "type": "0x7e", + "type": "0x7e", "sourceHash":"0x0000000000000000000000000000000000000000000000000000000000000000", "from": "{{TestItem.AddressA.Bytes.ToHexString(withZeroX: true)}}", "to": "0x0000000000000000000000000000000000000000", @@ -116,8 +116,8 @@ public async Task GetTransactionByHash_IncludesDepositReceiptVersion() "depositReceiptVersion": "0x20", "hash": "{{TestItem.KeccakA.Bytes.ToHexString(withZeroX: true)}}", "blockHash": "{{TestItem.KeccakB.Bytes.ToHexString(withZeroX: true)}}", - "transactionIndex": null, - "blockNumber": null + "blockNumber": null, + "transactionIndex": null }, "id":67 } From 9bc162e32d1f9bdb85a20c8bb03d4a25cd425afe Mon Sep 17 00:00:00 2001 From: Lautaro Emanuel Date: Mon, 3 Feb 2025 12:38:22 -0300 Subject: [PATCH 05/16] Test `GetTransactionByHash_ReturnsCorrectTransactionType` --- .../Rpc/OptimismEthRpcModuleTest.cs | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/src/Nethermind/Nethermind.Optimism.Test/Rpc/OptimismEthRpcModuleTest.cs b/src/Nethermind/Nethermind.Optimism.Test/Rpc/OptimismEthRpcModuleTest.cs index 1375708f108..cf64d2f74cd 100644 --- a/src/Nethermind/Nethermind.Optimism.Test/Rpc/OptimismEthRpcModuleTest.cs +++ b/src/Nethermind/Nethermind.Optimism.Test/Rpc/OptimismEthRpcModuleTest.cs @@ -69,6 +69,62 @@ public async Task Sequencer_send_transaction_with_signature_will_not_try_to_sign serialized.Should().BeEquivalentTo($$"""{"jsonrpc":"2.0","result":"{{TestItem.KeccakA.Bytes.ToHexString(withZeroX: true)}}","id":67}"""); } + + [Test] + public async Task GetTransactionByHash_ReturnsCorrectTransactionType() + { + Transaction tx = Build.A.Transaction + .WithType(TxType.Legacy) + .WithHash(TestItem.KeccakA) + .WithSenderAddress(TestItem.AddressA) + .TestObject; + TxReceipt receipt = new() + { + BlockHash = TestItem.KeccakB, + }; + + IBlockchainBridge bridge = Substitute.For(); + bridge.GetTransaction(TestItem.KeccakA, checkTxnPool: true).Returns((receipt, tx, (UInt256?)0)); + + TestRpcBlockchain rpcBlockchain = await TestRpcBlockchain + .ForTest(sealEngineType: SealEngineType.Optimism) + .WithBlockchainBridge(bridge) + .WithOptimismEthRpcModule( + sequencerRpcClient: Substitute.For(), + accountStateProvider: Substitute.For(), + ecdsa: Substitute.For(), + sealer: Substitute.For(), + opSpecHelper: Substitute.For()) + .Build(); + + + string serialized = await rpcBlockchain.TestEthRpc("eth_getTransactionByHash", TestItem.KeccakA); + var expected = $$""" + { + "jsonrpc":"2.0", + "result": { + "type": "0x0", + "from": "{{TestItem.AddressA.Bytes.ToHexString(withZeroX: true)}}", + "to": "0x0000000000000000000000000000000000000000", + "value": "0x1", + "gas": "0x5208", + "gasPrice": "0x1", + "input": "0x", + "nonce": "0x0", + "v": "0x0", + "r": "0x0", + "s": "0x0", + "hash": "{{TestItem.KeccakA.Bytes.ToHexString(withZeroX: true)}}", + "blockHash": "{{TestItem.KeccakB.Bytes.ToHexString(withZeroX: true)}}", + "blockNumber": null, + "transactionIndex": null + }, + "id":67 + } + """; + JToken.Parse(serialized).Should().BeEquivalentTo(expected); + } + [Test] public async Task GetTransactionByHash_IncludesDepositReceiptVersion() { From 7cd27053bba360cb5c5285eca8b382ba3c3c4ea1 Mon Sep 17 00:00:00 2001 From: Lautaro Emanuel Date: Mon, 3 Feb 2025 12:58:41 -0300 Subject: [PATCH 06/16] Test `GetTransactionByBlockHashAndIndex_IncludesDepositReceiptVersion` --- .../Rpc/OptimismEthRpcModuleTest.cs | 70 ++++++++++++++++++- 1 file changed, 69 insertions(+), 1 deletion(-) diff --git a/src/Nethermind/Nethermind.Optimism.Test/Rpc/OptimismEthRpcModuleTest.cs b/src/Nethermind/Nethermind.Optimism.Test/Rpc/OptimismEthRpcModuleTest.cs index cf64d2f74cd..7a720ceb7c9 100644 --- a/src/Nethermind/Nethermind.Optimism.Test/Rpc/OptimismEthRpcModuleTest.cs +++ b/src/Nethermind/Nethermind.Optimism.Test/Rpc/OptimismEthRpcModuleTest.cs @@ -4,6 +4,8 @@ using System.Threading.Tasks; using FluentAssertions; using FluentAssertions.Json; +using Nethermind.Blockchain.Find; +using Nethermind.Blockchain.Receipts; using Nethermind.Blockchain.Synchronization; using Nethermind.Config; using Nethermind.Core; @@ -69,7 +71,6 @@ public async Task Sequencer_send_transaction_with_signature_will_not_try_to_sign serialized.Should().BeEquivalentTo($$"""{"jsonrpc":"2.0","result":"{{TestItem.KeccakA.Bytes.ToHexString(withZeroX: true)}}","id":67}"""); } - [Test] public async Task GetTransactionByHash_ReturnsCorrectTransactionType() { @@ -180,6 +181,73 @@ public async Task GetTransactionByHash_IncludesDepositReceiptVersion() """; JToken.Parse(serialized).Should().BeEquivalentTo(expected); } + + [Test] + public async Task GetTransactionByBlockHashAndIndex_IncludesDepositReceiptVersion() + { + Transaction tx = Build.A.Transaction + .WithType(TxType.DepositTx) + .WithHash(TestItem.KeccakA) + .WithSenderAddress(TestItem.AddressA) + .TestObject; + OptimismTxReceipt receipt = new() + { + TxHash = tx.Hash!, + BlockHash = TestItem.KeccakB, + DepositReceiptVersion = 0x20, + }; + Block block = Build.A.Block + .WithHeader(Build.A.BlockHeader + .WithHash(TestItem.KeccakC) + .TestObject) + .WithTransactions(tx) + .TestObject; + + IBlockFinder blockFinder = Substitute.For(); + blockFinder.FindBlock(new BlockParameter(block.Hash!)).Returns(block); + + IReceiptFinder receiptFinder = Substitute.For(); + receiptFinder.Get(block).Returns([receipt]); + + TestRpcBlockchain rpcBlockchain = await TestRpcBlockchain + .ForTest(sealEngineType: SealEngineType.Optimism) + .WithBlockFinder(blockFinder) + .WithReceiptFinder(receiptFinder) + .WithOptimismEthRpcModule( + sequencerRpcClient: Substitute.For(), + accountStateProvider: Substitute.For(), + ecdsa: Substitute.For(), + sealer: Substitute.For(), + opSpecHelper: Substitute.For()) + .Build(); + + + string serialized = await rpcBlockchain.TestEthRpc("eth_getTransactionByBlockHashAndIndex", block.Hash, 0); + var expected = $$""" + { + "jsonrpc":"2.0", + "result": { + "type": "0x7e", + "sourceHash":"0x0000000000000000000000000000000000000000000000000000000000000000", + "from": "{{tx.SenderAddress!.Bytes.ToHexString(withZeroX: true)}}", + "to": "0x0000000000000000000000000000000000000000", + "mint": "0x0", + "value": "0x1", + "gas": "0x5208", + "isSystemTx": false, + "input": "0x", + "nonce": "0x0", + "depositReceiptVersion": "0x20", + "hash": "{{tx.Hash!.Bytes.ToHexString(withZeroX: true)}}", + "blockHash": "{{block.Hash!.Bytes.ToHexString(withZeroX: true)}}", + "blockNumber": null, + "transactionIndex": null + }, + "id":67 + } + """; + JToken.Parse(serialized).Should().BeEquivalentTo(expected); + } } internal static class TestRpcBlockchainExt From 73f14c9d17d71ecd3f82f25450c8768e7159606d Mon Sep 17 00:00:00 2001 From: Lautaro Emanuel Date: Mon, 3 Feb 2025 13:10:43 -0300 Subject: [PATCH 07/16] Test also for `BlockNumber` parameter --- .../Rpc/OptimismEthRpcModuleTest.cs | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/Nethermind/Nethermind.Optimism.Test/Rpc/OptimismEthRpcModuleTest.cs b/src/Nethermind/Nethermind.Optimism.Test/Rpc/OptimismEthRpcModuleTest.cs index 7a720ceb7c9..107e6c5e2a3 100644 --- a/src/Nethermind/Nethermind.Optimism.Test/Rpc/OptimismEthRpcModuleTest.cs +++ b/src/Nethermind/Nethermind.Optimism.Test/Rpc/OptimismEthRpcModuleTest.cs @@ -183,7 +183,7 @@ public async Task GetTransactionByHash_IncludesDepositReceiptVersion() } [Test] - public async Task GetTransactionByBlockHashAndIndex_IncludesDepositReceiptVersion() + public async Task GetTransactionByBlockAndIndex_IncludesDepositReceiptVersion() { Transaction tx = Build.A.Transaction .WithType(TxType.DepositTx) @@ -199,12 +199,14 @@ public async Task GetTransactionByBlockHashAndIndex_IncludesDepositReceiptVersio Block block = Build.A.Block .WithHeader(Build.A.BlockHeader .WithHash(TestItem.KeccakC) + .WithNumber(123) .TestObject) .WithTransactions(tx) .TestObject; IBlockFinder blockFinder = Substitute.For(); blockFinder.FindBlock(new BlockParameter(block.Hash!)).Returns(block); + blockFinder.FindBlock(new BlockParameter(block.Number)).Returns(block); IReceiptFinder receiptFinder = Substitute.For(); receiptFinder.Get(block).Returns([receipt]); @@ -221,8 +223,6 @@ public async Task GetTransactionByBlockHashAndIndex_IncludesDepositReceiptVersio opSpecHelper: Substitute.For()) .Build(); - - string serialized = await rpcBlockchain.TestEthRpc("eth_getTransactionByBlockHashAndIndex", block.Hash, 0); var expected = $$""" { "jsonrpc":"2.0", @@ -246,7 +246,16 @@ public async Task GetTransactionByBlockHashAndIndex_IncludesDepositReceiptVersio "id":67 } """; - JToken.Parse(serialized).Should().BeEquivalentTo(expected); + { + // By block hash + string serialized = await rpcBlockchain.TestEthRpc("eth_getTransactionByBlockHashAndIndex", block.Hash, 0); + JToken.Parse(serialized).Should().BeEquivalentTo(expected); + } + { + // By block number + string serialized = await rpcBlockchain.TestEthRpc("eth_getTransactionByBlockNumberAndIndex", block.Number, 0); + JToken.Parse(serialized).Should().BeEquivalentTo(expected); + } } } From 546f597cc7a7997555f5b764adbdceb18288d6a6 Mon Sep 17 00:00:00 2001 From: Lautaro Emanuel Date: Mon, 3 Feb 2025 13:12:23 -0300 Subject: [PATCH 08/16] Remove unused fields --- .../Nethermind.Optimism.Test/Rpc/OptimismEthRpcModuleTest.cs | 2 +- .../Nethermind.Optimism/Rpc/OptimismEthModuleFactory.cs | 1 - src/Nethermind/Nethermind.Optimism/Rpc/OptimismEthRpcModule.cs | 3 --- 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/Nethermind/Nethermind.Optimism.Test/Rpc/OptimismEthRpcModuleTest.cs b/src/Nethermind/Nethermind.Optimism.Test/Rpc/OptimismEthRpcModuleTest.cs index 107e6c5e2a3..08009defac7 100644 --- a/src/Nethermind/Nethermind.Optimism.Test/Rpc/OptimismEthRpcModuleTest.cs +++ b/src/Nethermind/Nethermind.Optimism.Test/Rpc/OptimismEthRpcModuleTest.cs @@ -287,7 +287,7 @@ public static TestRpcBlockchain.Builder WithOptimismEthRpcMod new FeeHistoryOracle(blockchain.BlockTree, blockchain.ReceiptStorage, blockchain.SpecProvider), new BlocksConfig().SecondsPerSlot, - sequencerRpcClient, accountStateProvider, ecdsa, sealer, opSpecHelper + sequencerRpcClient, ecdsa, sealer, opSpecHelper )); } } diff --git a/src/Nethermind/Nethermind.Optimism/Rpc/OptimismEthModuleFactory.cs b/src/Nethermind/Nethermind.Optimism/Rpc/OptimismEthModuleFactory.cs index 6d575a75d0c..a024cbee99c 100644 --- a/src/Nethermind/Nethermind.Optimism/Rpc/OptimismEthModuleFactory.cs +++ b/src/Nethermind/Nethermind.Optimism/Rpc/OptimismEthModuleFactory.cs @@ -82,7 +82,6 @@ public override IOptimismEthRpcModule Create() secondsPerSlot, sequencerRpcClient, - _accountStateProvider, _ecdsa, _sealer, _opSpecHelper diff --git a/src/Nethermind/Nethermind.Optimism/Rpc/OptimismEthRpcModule.cs b/src/Nethermind/Nethermind.Optimism/Rpc/OptimismEthRpcModule.cs index 4b4f93dac44..d50aa3657d6 100644 --- a/src/Nethermind/Nethermind.Optimism/Rpc/OptimismEthRpcModule.cs +++ b/src/Nethermind/Nethermind.Optimism/Rpc/OptimismEthRpcModule.cs @@ -32,7 +32,6 @@ namespace Nethermind.Optimism.Rpc; public class OptimismEthRpcModule : EthRpcModule, IOptimismEthRpcModule { private readonly IJsonRpcClient? _sequencerRpcClient; - private readonly IAccountStateProvider _accountStateProvider; private readonly IEthereumEcdsa _ecdsa; private readonly ITxSealer _sealer; private readonly IOptimismSpecHelper _opSpecHelper; @@ -54,7 +53,6 @@ public OptimismEthRpcModule( ulong? secondsPerSlot, IJsonRpcClient? sequencerRpcClient, - IAccountStateProvider accountStateProvider, IEthereumEcdsa ecdsa, ITxSealer sealer, IOptimismSpecHelper opSpecHelper) : base( @@ -74,7 +72,6 @@ public OptimismEthRpcModule( secondsPerSlot) { _sequencerRpcClient = sequencerRpcClient; - _accountStateProvider = accountStateProvider; _ecdsa = ecdsa; _sealer = sealer; _opSpecHelper = opSpecHelper; From 66e330d456395e9137a3fae98968fd6bc188631f Mon Sep 17 00:00:00 2001 From: Lautaro Emanuel Date: Mon, 3 Feb 2025 13:40:33 -0300 Subject: [PATCH 09/16] Test `GetTransactionByBlockAndIndex_ReturnsCorrectTransactionType` --- .../Rpc/OptimismEthRpcModuleTest.cs | 75 +++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/src/Nethermind/Nethermind.Optimism.Test/Rpc/OptimismEthRpcModuleTest.cs b/src/Nethermind/Nethermind.Optimism.Test/Rpc/OptimismEthRpcModuleTest.cs index 08009defac7..2ff41666af6 100644 --- a/src/Nethermind/Nethermind.Optimism.Test/Rpc/OptimismEthRpcModuleTest.cs +++ b/src/Nethermind/Nethermind.Optimism.Test/Rpc/OptimismEthRpcModuleTest.cs @@ -182,6 +182,81 @@ public async Task GetTransactionByHash_IncludesDepositReceiptVersion() JToken.Parse(serialized).Should().BeEquivalentTo(expected); } + [Test] + public async Task GetTransactionByBlockAndIndex_ReturnsCorrectTransactionType() + { + Transaction tx = Build.A.Transaction + .WithType(TxType.Legacy) + .WithHash(TestItem.KeccakA) + .WithSenderAddress(TestItem.AddressA) + .TestObject; + OptimismTxReceipt receipt = new() + { + TxHash = tx.Hash!, + BlockHash = TestItem.KeccakB, + }; + Block block = Build.A.Block + .WithHeader(Build.A.BlockHeader + .WithHash(TestItem.KeccakC) + .WithNumber(123) + .TestObject) + .WithTransactions(tx) + .TestObject; + + IBlockFinder blockFinder = Substitute.For(); + blockFinder.FindBlock(new BlockParameter(block.Hash!)).Returns(block); + blockFinder.FindBlock(new BlockParameter(block.Number)).Returns(block); + + IReceiptFinder receiptFinder = Substitute.For(); + receiptFinder.Get(block).Returns([receipt]); + + TestRpcBlockchain rpcBlockchain = await TestRpcBlockchain + .ForTest(sealEngineType: SealEngineType.Optimism) + .WithBlockFinder(blockFinder) + .WithReceiptFinder(receiptFinder) + .WithOptimismEthRpcModule( + sequencerRpcClient: Substitute.For(), + accountStateProvider: Substitute.For(), + ecdsa: Substitute.For(), + sealer: Substitute.For(), + opSpecHelper: Substitute.For()) + .Build(); + + var expected = $$""" + { + "jsonrpc":"2.0", + "result": { + "type": "0x0", + "from": "{{tx.SenderAddress!.Bytes.ToHexString(withZeroX: true)}}", + "to": "0x0000000000000000000000000000000000000000", + "value": "0x1", + "gas": "0x5208", + "gasPrice": "0x1", + "input": "0x", + "nonce": "0x0", + "v": "0x0", + "r": "0x0", + "s": "0x0", + "hash": "{{tx.Hash!.Bytes.ToHexString(withZeroX: true)}}", + "blockHash": "{{block.Hash!.Bytes.ToHexString(withZeroX: true)}}", + "blockNumber": null, + "transactionIndex": null + }, + "id":67 + } + """; + { + // By block hash + string serialized = await rpcBlockchain.TestEthRpc("eth_getTransactionByBlockHashAndIndex", block.Hash, 0); + JToken.Parse(serialized).Should().BeEquivalentTo(expected); + } + { + // By block number + string serialized = await rpcBlockchain.TestEthRpc("eth_getTransactionByBlockNumberAndIndex", block.Number, 0); + JToken.Parse(serialized).Should().BeEquivalentTo(expected); + } + } + [Test] public async Task GetTransactionByBlockAndIndex_IncludesDepositReceiptVersion() { From 3749306517d2075acbb4fa1c2fd6f882ab445116 Mon Sep 17 00:00:00 2001 From: Lautaro Emanuel Date: Mon, 3 Feb 2025 13:40:58 -0300 Subject: [PATCH 10/16] Lazily fetch receipts - Only for `Deposit` transactions - Remove intermediate `ToArray` --- .../Rpc/OptimismEthRpcModule.cs | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/Nethermind/Nethermind.Optimism/Rpc/OptimismEthRpcModule.cs b/src/Nethermind/Nethermind.Optimism/Rpc/OptimismEthRpcModule.cs index d50aa3657d6..25309c5f336 100644 --- a/src/Nethermind/Nethermind.Optimism/Rpc/OptimismEthRpcModule.cs +++ b/src/Nethermind/Nethermind.Optimism/Rpc/OptimismEthRpcModule.cs @@ -189,14 +189,16 @@ public override ResultWrapper eth_getTransactionByBlockHashAn return ResultWrapper.Fail("Position Index is incorrect", ErrorCodes.InvalidParams); } - OptimismTxReceipt[] receipts = _receiptFinder.Get(block).Cast().ToArray(); Transaction transaction = block.Transactions[(int)positionIndex]; RecoverTxSenderIfNeeded(transaction); var transactionModel = TransactionForRpc.FromTransaction(transaction, blockHash: block.Hash); if (transactionModel is DepositTransactionForRpc depositTx) { - OptimismTxReceipt? receipt = receipts.FirstOrDefault(r => r.TxHash == transaction.Hash); + OptimismTxReceipt? receipt = _receiptFinder + .Get(block) + .Cast() + .FirstOrDefault(r => r.TxHash == transaction.Hash); depositTx.DepositReceiptVersion = receipt?.DepositReceiptVersion; } @@ -218,15 +220,16 @@ public override ResultWrapper eth_getTransactionByBlockNumber return ResultWrapper.Fail("Position Index is incorrect", ErrorCodes.InvalidParams); } - OptimismTxReceipt[] receipts = _receiptFinder.Get(block).Cast().ToArray(); - Transaction transaction = block.Transactions[(int)positionIndex]; RecoverTxSenderIfNeeded(transaction); var transactionModel = TransactionForRpc.FromTransaction(transaction, blockHash: block.Hash); if (transactionModel is DepositTransactionForRpc depositTx) { - OptimismTxReceipt? receipt = receipts.FirstOrDefault(r => r.TxHash == transaction.Hash); + OptimismTxReceipt? receipt = _receiptFinder + .Get(block) + .Cast() + .FirstOrDefault(r => r.TxHash == transaction.Hash); depositTx.DepositReceiptVersion = receipt?.DepositReceiptVersion; } @@ -253,8 +256,6 @@ public override ResultWrapper eth_getTransactionByBlockNumber BlockForRpc result = new BlockForRpc(block, false, _specProvider); - OptimismTxReceipt[] receipts = _receiptFinder.Get(block).Cast().ToArray(); - if (returnFullTransactionObjects) { _blockchainBridge.RecoverTxSenders(block); @@ -267,7 +268,10 @@ public override ResultWrapper eth_getTransactionByBlockNumber txIndex: index); if (transactionModel is DepositTransactionForRpc depositTx) { - var receipt = receipts.FirstOrDefault(r => r.TxHash?.Equals(hash) ?? false); + var receipt = _receiptFinder + .Get(block) + .Cast() + .FirstOrDefault(r => r.TxHash?.Equals(hash) ?? false); depositTx.DepositReceiptVersion = receipt?.DepositReceiptVersion; } From 4bca4c9e6810c8a7ee1b50fd68e0b8a9e9b2274a Mon Sep 17 00:00:00 2001 From: Lautaro Emanuel Date: Tue, 4 Feb 2025 08:53:25 -0300 Subject: [PATCH 11/16] Avoid repeated receipt fetching --- .../Nethermind.Optimism/Rpc/OptimismEthRpcModule.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Nethermind/Nethermind.Optimism/Rpc/OptimismEthRpcModule.cs b/src/Nethermind/Nethermind.Optimism/Rpc/OptimismEthRpcModule.cs index 25309c5f336..d0fa466ed7e 100644 --- a/src/Nethermind/Nethermind.Optimism/Rpc/OptimismEthRpcModule.cs +++ b/src/Nethermind/Nethermind.Optimism/Rpc/OptimismEthRpcModule.cs @@ -259,6 +259,7 @@ public override ResultWrapper eth_getTransactionByBlockNumber if (returnFullTransactionObjects) { _blockchainBridge.RecoverTxSenders(block); + OptimismTxReceipt[] receipts = _receiptFinder.Get(block).Cast().ToArray(); result.Transactions = result.Transactions.Select((hash, index) => { var transactionModel = TransactionForRpc.FromTransaction( @@ -268,10 +269,7 @@ public override ResultWrapper eth_getTransactionByBlockNumber txIndex: index); if (transactionModel is DepositTransactionForRpc depositTx) { - var receipt = _receiptFinder - .Get(block) - .Cast() - .FirstOrDefault(r => r.TxHash?.Equals(hash) ?? false); + OptimismTxReceipt? receipt = receipts.FirstOrDefault(r => r.TxHash?.Equals(hash) ?? false); depositTx.DepositReceiptVersion = receipt?.DepositReceiptVersion; } From fa32837eeccb90536020b8b2955005d55c08b97a Mon Sep 17 00:00:00 2001 From: Lautaro Emanuel Date: Tue, 4 Feb 2025 09:15:17 -0300 Subject: [PATCH 12/16] Merge `GetTransactionByBlockAndIndex` - Remove duplication - Rollback virtual modifiers - Log on `Success` and `Trace` only --- .../Modules/Eth/EthRpcModule.cs | 39 +++++++++---------- .../Rpc/OptimismEthRpcModule.cs | 38 +----------------- 2 files changed, 20 insertions(+), 57 deletions(-) diff --git a/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/EthRpcModule.cs b/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/EthRpcModule.cs index f0a0e2eedd6..346ab69f32f 100644 --- a/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/EthRpcModule.cs +++ b/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/EthRpcModule.cs @@ -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; @@ -428,31 +429,31 @@ public ResultWrapper eth_pendingTransactions() return ResultWrapper.Success(transactionsModels); } - public virtual ResultWrapper eth_getTransactionByBlockHashAndIndex(Hash256 blockHash, - UInt256 positionIndex) + public ResultWrapper eth_getTransactionByBlockHashAndIndex(Hash256 blockHash, UInt256 positionIndex) { - SearchResult searchResult = _blockFinder.SearchForBlock(new BlockParameter(blockHash)); - if (searchResult.IsError) + ResultWrapper result = GetTransactionByBlockAndIndex(new BlockParameter(blockHash), positionIndex); + if (result.Result.ResultType == ResultType.Success) { - return GetFailureResult(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 eth_getTransactionByBlockNumberAndIndex(BlockParameter blockParameter, UInt256 positionIndex) + { + ResultWrapper result = GetTransactionByBlockAndIndex(blockParameter, positionIndex); + if (result.Result.ResultType == ResultType.Success) { - return ResultWrapper.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.Success(transactionModel); + return result; } - public virtual ResultWrapper eth_getTransactionByBlockNumberAndIndex(BlockParameter blockParameter, - UInt256 positionIndex) + protected virtual ResultWrapper GetTransactionByBlockAndIndex(BlockParameter blockParameter, UInt256 positionIndex) { SearchResult searchResult = _blockFinder.SearchForBlock(blockParameter); if (searchResult.IsError) @@ -470,10 +471,6 @@ public virtual ResultWrapper eth_getTransactionByBlockNumberA 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}"); return ResultWrapper.Success(transactionModel); } diff --git a/src/Nethermind/Nethermind.Optimism/Rpc/OptimismEthRpcModule.cs b/src/Nethermind/Nethermind.Optimism/Rpc/OptimismEthRpcModule.cs index d0fa466ed7e..1aa8a85c9ac 100644 --- a/src/Nethermind/Nethermind.Optimism/Rpc/OptimismEthRpcModule.cs +++ b/src/Nethermind/Nethermind.Optimism/Rpc/OptimismEthRpcModule.cs @@ -175,9 +175,9 @@ public override async Task> eth_sendRawTransaction(byte[] return ResultWrapper.Success(transactionModel); } - public override ResultWrapper eth_getTransactionByBlockHashAndIndex(Hash256 blockHash, UInt256 positionIndex) + protected override ResultWrapper GetTransactionByBlockAndIndex(BlockParameter blockParameter, UInt256 positionIndex) { - SearchResult searchResult = _blockFinder.SearchForBlock(new BlockParameter(blockHash)); + SearchResult searchResult = _blockFinder.SearchForBlock(blockParameter); if (searchResult.IsError || searchResult.Object is null) { return GetFailureResult(searchResult, _ethSyncingInfo.SyncMode.HaveNotSyncedBodiesYet()); @@ -205,40 +205,6 @@ public override ResultWrapper eth_getTransactionByBlockHashAn return ResultWrapper.Success(transactionModel); } - public override ResultWrapper eth_getTransactionByBlockNumberAndIndex(BlockParameter blockParameter, UInt256 positionIndex) - { - SearchResult searchResult = _blockFinder.SearchForBlock(blockParameter); - - if (searchResult.IsError) - { - return GetFailureResult(searchResult, _ethSyncingInfo.SyncMode.HaveNotSyncedBodiesYet()); - } - - Block? block = searchResult.Object; - if (positionIndex < 0 || positionIndex > block!.Transactions.Length - 1) - { - return ResultWrapper.Fail("Position Index is incorrect", ErrorCodes.InvalidParams); - } - - Transaction transaction = block.Transactions[(int)positionIndex]; - RecoverTxSenderIfNeeded(transaction); - - var transactionModel = TransactionForRpc.FromTransaction(transaction, blockHash: block.Hash); - if (transactionModel is DepositTransactionForRpc depositTx) - { - OptimismTxReceipt? receipt = _receiptFinder - .Get(block) - .Cast() - .FirstOrDefault(r => r.TxHash == transaction.Hash); - depositTx.DepositReceiptVersion = receipt?.DepositReceiptVersion; - } - - if (_logger.IsDebug) - _logger.Debug( - $"eth_getTransactionByBlockNumberAndIndex request {blockParameter}, index: {positionIndex}, result: {transactionModel.Hash}"); - return ResultWrapper.Success(transactionModel); - } - protected override ResultWrapper GetBlock(BlockParameter blockParameter, bool returnFullTransactionObjects) { SearchResult searchResult = _blockFinder.SearchForBlock(blockParameter, true); From d1b0a8c14a8364f70ffacde956fded10de388d39 Mon Sep 17 00:00:00 2001 From: Lautaro Emanuel Date: Tue, 4 Feb 2025 10:00:35 -0300 Subject: [PATCH 13/16] Do not capture constructor param --- .../Nethermind.JsonRpc/Modules/Eth/EthRpcModule.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/EthRpcModule.cs b/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/EthRpcModule.cs index cf2207cbbb3..13eb7787980 100644 --- a/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/EthRpcModule.cs +++ b/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/EthRpcModule.cs @@ -394,7 +394,7 @@ public ResultWrapper 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.Success(transactionModel); } @@ -421,7 +421,7 @@ public ResultWrapper 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; } @@ -470,7 +470,7 @@ protected virtual ResultWrapper GetTransactionByBlockAndIndex Transaction transaction = block.Transactions[(int)positionIndex]; RecoverTxSenderIfNeeded(transaction); - TransactionForRpc transactionModel = TransactionForRpc.FromTransaction(transaction, block.Hash, block.Number, (int)positionIndex, block.BaseFeePerGas, specProvider.ChainId); + TransactionForRpc transactionModel = TransactionForRpc.FromTransaction(transaction, block.Hash, block.Number, (int)positionIndex, block.BaseFeePerGas, _specProvider.ChainId); return ResultWrapper.Success(transactionModel); } From 85125fb0d1ba88238fd3579260df81b73581c44a Mon Sep 17 00:00:00 2001 From: Lautaro Emanuel Date: Tue, 4 Feb 2025 10:01:02 -0300 Subject: [PATCH 14/16] Use all parameters in `FromTransaction` - Same behavior as base class --- .../Rpc/OptimismEthRpcModuleTest.cs | 16 ++++++++++------ .../Rpc/OptimismEthRpcModule.cs | 4 ++-- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/Nethermind/Nethermind.Optimism.Test/Rpc/OptimismEthRpcModuleTest.cs b/src/Nethermind/Nethermind.Optimism.Test/Rpc/OptimismEthRpcModuleTest.cs index 2ff41666af6..194b9d4329e 100644 --- a/src/Nethermind/Nethermind.Optimism.Test/Rpc/OptimismEthRpcModuleTest.cs +++ b/src/Nethermind/Nethermind.Optimism.Test/Rpc/OptimismEthRpcModuleTest.cs @@ -82,6 +82,8 @@ public async Task GetTransactionByHash_ReturnsCorrectTransactionType() TxReceipt receipt = new() { BlockHash = TestItem.KeccakB, + BlockNumber = 0x10, + Index = 0x20 }; IBlockchainBridge bridge = Substitute.For(); @@ -117,8 +119,8 @@ public async Task GetTransactionByHash_ReturnsCorrectTransactionType() "s": "0x0", "hash": "{{TestItem.KeccakA.Bytes.ToHexString(withZeroX: true)}}", "blockHash": "{{TestItem.KeccakB.Bytes.ToHexString(withZeroX: true)}}", - "blockNumber": null, - "transactionIndex": null + "blockNumber": "0x10", + "transactionIndex": "0x20" }, "id":67 } @@ -137,7 +139,9 @@ public async Task GetTransactionByHash_IncludesDepositReceiptVersion() OptimismTxReceipt receipt = new() { BlockHash = TestItem.KeccakB, - DepositReceiptVersion = 0x20, + BlockNumber = 0x10, + Index = 0x20, + DepositReceiptVersion = 0x30, }; IBlockchainBridge bridge = Substitute.For(); @@ -170,11 +174,11 @@ public async Task GetTransactionByHash_IncludesDepositReceiptVersion() "isSystemTx": false, "input": "0x", "nonce": "0x0", - "depositReceiptVersion": "0x20", + "depositReceiptVersion": "0x30", "hash": "{{TestItem.KeccakA.Bytes.ToHexString(withZeroX: true)}}", "blockHash": "{{TestItem.KeccakB.Bytes.ToHexString(withZeroX: true)}}", - "blockNumber": null, - "transactionIndex": null + "blockNumber": "0x10", + "transactionIndex": "0x20" }, "id":67 } diff --git a/src/Nethermind/Nethermind.Optimism/Rpc/OptimismEthRpcModule.cs b/src/Nethermind/Nethermind.Optimism/Rpc/OptimismEthRpcModule.cs index 1aa8a85c9ac..a87387141dc 100644 --- a/src/Nethermind/Nethermind.Optimism/Rpc/OptimismEthRpcModule.cs +++ b/src/Nethermind/Nethermind.Optimism/Rpc/OptimismEthRpcModule.cs @@ -159,14 +159,14 @@ public override async Task> eth_sendRawTransaction(byte[] public override ResultWrapper eth_getTransactionByHash(Hash256 transactionHash) { - (TxReceipt? receipt, Transaction? transaction, _) = _blockchainBridge.GetTransaction(transactionHash, checkTxnPool: true); + (TxReceipt? receipt, Transaction? transaction, UInt256? baseFee) = _blockchainBridge.GetTransaction(transactionHash, checkTxnPool: true); if (transaction is null) { return ResultWrapper.Success(null); } RecoverTxSenderIfNeeded(transaction); - var transactionModel = TransactionForRpc.FromTransaction(transaction, blockHash: receipt?.BlockHash); + TransactionForRpc transactionModel = TransactionForRpc.FromTransaction(transaction: transaction, blockHash: receipt?.BlockHash, blockNumber: receipt?.BlockNumber, txIndex: receipt?.Index, baseFee: baseFee, chainId: _specProvider.ChainId); if (transactionModel is DepositTransactionForRpc depositTx) { depositTx.DepositReceiptVersion = (receipt as OptimismTxReceipt)?.DepositReceiptVersion; From 94112e1ca25a09cf2f88a14dd0ded6b06e9ff8af Mon Sep 17 00:00:00 2001 From: Lautaro Emanuel Date: Tue, 4 Feb 2025 10:01:02 -0300 Subject: [PATCH 15/16] Use all parameters in `FromTransaction` - Same behavior as base class --- .../Rpc/OptimismEthRpcModuleTest.cs | 37 +++++++++++-------- .../Rpc/OptimismEthRpcModule.cs | 16 ++++---- 2 files changed, 29 insertions(+), 24 deletions(-) diff --git a/src/Nethermind/Nethermind.Optimism.Test/Rpc/OptimismEthRpcModuleTest.cs b/src/Nethermind/Nethermind.Optimism.Test/Rpc/OptimismEthRpcModuleTest.cs index 2ff41666af6..a56a99d181b 100644 --- a/src/Nethermind/Nethermind.Optimism.Test/Rpc/OptimismEthRpcModuleTest.cs +++ b/src/Nethermind/Nethermind.Optimism.Test/Rpc/OptimismEthRpcModuleTest.cs @@ -82,6 +82,8 @@ public async Task GetTransactionByHash_ReturnsCorrectTransactionType() TxReceipt receipt = new() { BlockHash = TestItem.KeccakB, + BlockNumber = 0x10, + Index = 0x20 }; IBlockchainBridge bridge = Substitute.For(); @@ -117,8 +119,8 @@ public async Task GetTransactionByHash_ReturnsCorrectTransactionType() "s": "0x0", "hash": "{{TestItem.KeccakA.Bytes.ToHexString(withZeroX: true)}}", "blockHash": "{{TestItem.KeccakB.Bytes.ToHexString(withZeroX: true)}}", - "blockNumber": null, - "transactionIndex": null + "blockNumber": "0x10", + "transactionIndex": "0x20" }, "id":67 } @@ -137,7 +139,9 @@ public async Task GetTransactionByHash_IncludesDepositReceiptVersion() OptimismTxReceipt receipt = new() { BlockHash = TestItem.KeccakB, - DepositReceiptVersion = 0x20, + BlockNumber = 0x10, + Index = 0x20, + DepositReceiptVersion = 0x30, }; IBlockchainBridge bridge = Substitute.For(); @@ -170,11 +174,11 @@ public async Task GetTransactionByHash_IncludesDepositReceiptVersion() "isSystemTx": false, "input": "0x", "nonce": "0x0", - "depositReceiptVersion": "0x20", + "depositReceiptVersion": "0x30", "hash": "{{TestItem.KeccakA.Bytes.ToHexString(withZeroX: true)}}", "blockHash": "{{TestItem.KeccakB.Bytes.ToHexString(withZeroX: true)}}", - "blockNumber": null, - "transactionIndex": null + "blockNumber": "0x10", + "transactionIndex": "0x20" }, "id":67 } @@ -265,19 +269,20 @@ public async Task GetTransactionByBlockAndIndex_IncludesDepositReceiptVersion() .WithHash(TestItem.KeccakA) .WithSenderAddress(TestItem.AddressA) .TestObject; - OptimismTxReceipt receipt = new() - { - TxHash = tx.Hash!, - BlockHash = TestItem.KeccakB, - DepositReceiptVersion = 0x20, - }; Block block = Build.A.Block .WithHeader(Build.A.BlockHeader - .WithHash(TestItem.KeccakC) .WithNumber(123) .TestObject) .WithTransactions(tx) .TestObject; + OptimismTxReceipt receipt = new() + { + TxHash = tx.Hash!, + BlockHash = block.Hash!, + BlockNumber = 0x10, + Index = 0x20, + DepositReceiptVersion = 0x30, + }; IBlockFinder blockFinder = Substitute.For(); blockFinder.FindBlock(new BlockParameter(block.Hash!)).Returns(block); @@ -312,11 +317,11 @@ public async Task GetTransactionByBlockAndIndex_IncludesDepositReceiptVersion() "isSystemTx": false, "input": "0x", "nonce": "0x0", - "depositReceiptVersion": "0x20", + "depositReceiptVersion": "0x30", "hash": "{{tx.Hash!.Bytes.ToHexString(withZeroX: true)}}", "blockHash": "{{block.Hash!.Bytes.ToHexString(withZeroX: true)}}", - "blockNumber": null, - "transactionIndex": null + "blockNumber": "0x10", + "transactionIndex": "0x20" }, "id":67 } diff --git a/src/Nethermind/Nethermind.Optimism/Rpc/OptimismEthRpcModule.cs b/src/Nethermind/Nethermind.Optimism/Rpc/OptimismEthRpcModule.cs index 1aa8a85c9ac..7aa5a821a53 100644 --- a/src/Nethermind/Nethermind.Optimism/Rpc/OptimismEthRpcModule.cs +++ b/src/Nethermind/Nethermind.Optimism/Rpc/OptimismEthRpcModule.cs @@ -159,14 +159,14 @@ public override async Task> eth_sendRawTransaction(byte[] public override ResultWrapper eth_getTransactionByHash(Hash256 transactionHash) { - (TxReceipt? receipt, Transaction? transaction, _) = _blockchainBridge.GetTransaction(transactionHash, checkTxnPool: true); + (TxReceipt? receipt, Transaction? transaction, UInt256? baseFee) = _blockchainBridge.GetTransaction(transactionHash, checkTxnPool: true); if (transaction is null) { return ResultWrapper.Success(null); } RecoverTxSenderIfNeeded(transaction); - var transactionModel = TransactionForRpc.FromTransaction(transaction, blockHash: receipt?.BlockHash); + TransactionForRpc transactionModel = TransactionForRpc.FromTransaction(transaction: transaction, blockHash: receipt?.BlockHash, blockNumber: receipt?.BlockNumber, txIndex: receipt?.Index, baseFee: baseFee, chainId: _specProvider.ChainId); if (transactionModel is DepositTransactionForRpc depositTx) { depositTx.DepositReceiptVersion = (receipt as OptimismTxReceipt)?.DepositReceiptVersion; @@ -192,14 +192,14 @@ protected override ResultWrapper GetTransactionByBlockAndInde Transaction transaction = block.Transactions[(int)positionIndex]; RecoverTxSenderIfNeeded(transaction); - var transactionModel = TransactionForRpc.FromTransaction(transaction, blockHash: block.Hash); + var receipt = _receiptFinder + .Get(block) + .FirstOrDefault(r => r.TxHash == transaction.Hash); + + TransactionForRpc transactionModel = TransactionForRpc.FromTransaction(transaction: transaction, blockHash: receipt?.BlockHash, blockNumber: receipt?.BlockNumber, txIndex: receipt?.Index, baseFee: block.BaseFeePerGas, chainId: _specProvider.ChainId); if (transactionModel is DepositTransactionForRpc depositTx) { - OptimismTxReceipt? receipt = _receiptFinder - .Get(block) - .Cast() - .FirstOrDefault(r => r.TxHash == transaction.Hash); - depositTx.DepositReceiptVersion = receipt?.DepositReceiptVersion; + depositTx.DepositReceiptVersion = (receipt as OptimismTxReceipt)?.DepositReceiptVersion; } return ResultWrapper.Success(transactionModel); From 4cc3a9a6d47238a1ff7ee7ed6b6e1fce5ea04cb9 Mon Sep 17 00:00:00 2001 From: Lautaro Emanuel Date: Tue, 4 Feb 2025 11:03:04 -0300 Subject: [PATCH 16/16] Cleanup tests --- .../Rpc/OptimismEthRpcModuleTest.cs | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/Nethermind/Nethermind.Optimism.Test/Rpc/OptimismEthRpcModuleTest.cs b/src/Nethermind/Nethermind.Optimism.Test/Rpc/OptimismEthRpcModuleTest.cs index a56a99d181b..002852e5886 100644 --- a/src/Nethermind/Nethermind.Optimism.Test/Rpc/OptimismEthRpcModuleTest.cs +++ b/src/Nethermind/Nethermind.Optimism.Test/Rpc/OptimismEthRpcModuleTest.cs @@ -194,18 +194,20 @@ public async Task GetTransactionByBlockAndIndex_ReturnsCorrectTransactionType() .WithHash(TestItem.KeccakA) .WithSenderAddress(TestItem.AddressA) .TestObject; - OptimismTxReceipt receipt = new() - { - TxHash = tx.Hash!, - BlockHash = TestItem.KeccakB, - }; Block block = Build.A.Block .WithHeader(Build.A.BlockHeader - .WithHash(TestItem.KeccakC) - .WithNumber(123) + .WithNumber(0x10) .TestObject) .WithTransactions(tx) .TestObject; + OptimismTxReceipt receipt = new() + { + TxHash = tx.Hash!, + BlockHash = block.Hash!, + BlockNumber = block.Number, + Index = 0x20, + DepositReceiptVersion = 0x30, + }; IBlockFinder blockFinder = Substitute.For(); blockFinder.FindBlock(new BlockParameter(block.Hash!)).Returns(block); @@ -243,8 +245,8 @@ public async Task GetTransactionByBlockAndIndex_ReturnsCorrectTransactionType() "s": "0x0", "hash": "{{tx.Hash!.Bytes.ToHexString(withZeroX: true)}}", "blockHash": "{{block.Hash!.Bytes.ToHexString(withZeroX: true)}}", - "blockNumber": null, - "transactionIndex": null + "blockNumber": "0x10", + "transactionIndex": "0x20" }, "id":67 } @@ -271,7 +273,7 @@ public async Task GetTransactionByBlockAndIndex_IncludesDepositReceiptVersion() .TestObject; Block block = Build.A.Block .WithHeader(Build.A.BlockHeader - .WithNumber(123) + .WithNumber(0x10) .TestObject) .WithTransactions(tx) .TestObject; @@ -279,7 +281,7 @@ public async Task GetTransactionByBlockAndIndex_IncludesDepositReceiptVersion() { TxHash = tx.Hash!, BlockHash = block.Hash!, - BlockNumber = 0x10, + BlockNumber = block.Number, Index = 0x20, DepositReceiptVersion = 0x30, };