From 0480d7a9fcbe2e002791aebfccedfc34fc599b7a Mon Sep 17 00:00:00 2001 From: Alexey Date: Thu, 20 Jun 2024 16:32:17 +0300 Subject: [PATCH] Add fields to OP rpc; fix Ecotone gas issue; update pivots (#7180) --- src/Nethermind/Chains/base-mainnet.json | 3 +- src/Nethermind/Chains/op-mainnet.json | 3 +- .../Nethermind.Facade/Eth/BlockForRpc.cs | 1 - .../Eth/TransactionForRpc.cs | 7 -- .../Modules/Eth/EthRpcModule.cs | 8 +- .../Nethermind.Optimism.Test/GasCostTests.cs | 2 +- .../Nethermind.Optimism/L1BlockGasInfo.cs | 27 +++-- .../Nethermind.Optimism/OPL1CostHelper.cs | 9 +- .../Rpc/IOptimismEthRpcModule.cs | 24 ++++ .../Rpc/OptimismEthRpcModule.cs | 105 +++++++++++++++++- .../Rpc/OptimismReceiptForRpc.cs | 27 ++++- .../Rpc/OptimismTransactionForRpc.cs | 29 +++++ .../configs/base-mainnet.cfg | 6 +- .../configs/base-sepolia.cfg | 6 +- .../Nethermind.Runner/configs/op-mainnet.cfg | 4 +- .../Nethermind.Runner/configs/op-sepolia.cfg | 4 +- 16 files changed, 218 insertions(+), 47 deletions(-) create mode 100644 src/Nethermind/Nethermind.Optimism/Rpc/OptimismTransactionForRpc.cs diff --git a/src/Nethermind/Chains/base-mainnet.json b/src/Nethermind/Chains/base-mainnet.json index c0853d933aa..23a24b87315 100644 --- a/src/Nethermind/Chains/base-mainnet.json +++ b/src/Nethermind/Chains/base-mainnet.json @@ -9,7 +9,8 @@ "canyonTimestamp": "0x65a01e91", "ecotoneTimestamp": "0x65f23e01", "l1FeeRecipient": "0x420000000000000000000000000000000000001A", - "l1BlockAddress": "0x4200000000000000000000000000000000000015" + "l1BlockAddress": "0x4200000000000000000000000000000000000015", + "canyonBaseFeeChangeDenominator": "250" } } }, diff --git a/src/Nethermind/Chains/op-mainnet.json b/src/Nethermind/Chains/op-mainnet.json index 2c04e2cc3c1..4f7b3dc7232 100644 --- a/src/Nethermind/Chains/op-mainnet.json +++ b/src/Nethermind/Chains/op-mainnet.json @@ -9,7 +9,8 @@ "canyonTimestamp": "0x65a01e91", "ecotoneTimestamp": "0x65f23e01", "l1FeeRecipient": "0x420000000000000000000000000000000000001A", - "l1BlockAddress": "0x4200000000000000000000000000000000000015" + "l1BlockAddress": "0x4200000000000000000000000000000000000015", + "canyonBaseFeeChangeDenominator": "250" } } }, diff --git a/src/Nethermind/Nethermind.Facade/Eth/BlockForRpc.cs b/src/Nethermind/Nethermind.Facade/Eth/BlockForRpc.cs index dde7bdd6e21..dc0925282ad 100644 --- a/src/Nethermind/Nethermind.Facade/Eth/BlockForRpc.cs +++ b/src/Nethermind/Nethermind.Facade/Eth/BlockForRpc.cs @@ -8,7 +8,6 @@ using Nethermind.Core.Crypto; using Nethermind.Core.Specs; using Nethermind.Int256; -using Nethermind.JsonRpc.Data; using Nethermind.Serialization.Json; using Nethermind.Serialization.Rlp; using System.Text.Json.Serialization; diff --git a/src/Nethermind/Nethermind.Facade/Eth/TransactionForRpc.cs b/src/Nethermind/Nethermind.Facade/Eth/TransactionForRpc.cs index ab7a7bbc8ba..d51ed363156 100644 --- a/src/Nethermind/Nethermind.Facade/Eth/TransactionForRpc.cs +++ b/src/Nethermind/Nethermind.Facade/Eth/TransactionForRpc.cs @@ -10,7 +10,6 @@ using Nethermind.Core.Eip2930; using Nethermind.Core.Extensions; using Nethermind.Int256; -using Nethermind.JsonRpc.Data; namespace Nethermind.Facade.Eth; @@ -24,12 +23,6 @@ public TransactionForRpc(Transaction transaction) : this(null, null, null, trans public TransactionForRpc(Hash256? blockHash, long? blockNumber, int? txIndex, Transaction transaction, UInt256? baseFee = null) { - if (transaction.Type == TxType.DepositTx) - { - SourceHash = transaction.SourceHash; - Mint = transaction.Mint; - IsSystemTx = transaction.IsOPSystemTransaction; - } Hash = transaction.Hash; Nonce = transaction.Nonce; BlockHash = blockHash; diff --git a/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/EthRpcModule.cs b/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/EthRpcModule.cs index 6abec26637d..386e980968f 100644 --- a/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/EthRpcModule.cs +++ b/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/EthRpcModule.cs @@ -348,7 +348,7 @@ public ResultWrapper eth_getBlockByNumber(BlockParameter blockParam return GetBlock(blockParameter, returnFullTransactionObjects); } - private ResultWrapper GetBlock(BlockParameter blockParameter, bool returnFullTransactionObjects) + protected virtual ResultWrapper GetBlock(BlockParameter blockParameter, bool returnFullTransactionObjects) { SearchResult searchResult = _blockFinder.SearchForBlock(blockParameter, true); if (searchResult.IsError) @@ -362,7 +362,7 @@ private ResultWrapper GetBlock(BlockParameter blockParameter, bool _blockchainBridge.RecoverTxSenders(block); } - return ResultWrapper.Success(block is null + return ResultWrapper.Success(block is null ? null : new BlockForRpc(block, returnFullTransactionObjects, _specProvider)); } @@ -680,7 +680,7 @@ public ResultWrapper eth_chainId() } } - private void RecoverTxSenderIfNeeded(Transaction transaction) + protected void RecoverTxSenderIfNeeded(Transaction transaction) { transaction.SenderAddress ??= _blockchainBridge.RecoverTxSender(transaction); } @@ -713,7 +713,7 @@ private static IEnumerable GetLogs(IEnumerable logs, Cance : null); } - private static ResultWrapper GetFailureResult(SearchResult searchResult, bool isTemporary) where TSearch : class => + protected static ResultWrapper GetFailureResult(SearchResult searchResult, bool isTemporary) where TSearch : class => ResultWrapper.Fail(searchResult, isTemporary && searchResult.ErrorCode == ErrorCodes.ResourceNotFound); private static ResultWrapper GetFailureResult(ResourceNotFoundException exception, bool isTemporary) => diff --git a/src/Nethermind/Nethermind.Optimism.Test/GasCostTests.cs b/src/Nethermind/Nethermind.Optimism.Test/GasCostTests.cs index 677bebec6b8..2ba9f8160ba 100644 --- a/src/Nethermind/Nethermind.Optimism.Test/GasCostTests.cs +++ b/src/Nethermind/Nethermind.Optimism.Test/GasCostTests.cs @@ -11,7 +11,7 @@ public class GasCostTests { [TestCaseSource(nameof(FjordL1CostCalculationTestCases))] public UInt256 Fjord_l1cost_should_match(UInt256 fastLzSize, UInt256 l1BaseFee, UInt256 blobBaseFee, UInt256 l1BaseFeeScalar, UInt256 l1BlobBaseFeeScalar) => - OPL1CostHelper.ComputeL1CostFjord(fastLzSize, l1BaseFee, blobBaseFee, l1BaseFeeScalar, l1BlobBaseFeeScalar); + OPL1CostHelper.ComputeL1CostFjord(fastLzSize, l1BaseFee, blobBaseFee, l1BaseFeeScalar, l1BlobBaseFeeScalar, out _); public static IEnumerable FjordL1CostCalculationTestCases { diff --git a/src/Nethermind/Nethermind.Optimism/L1BlockGasInfo.cs b/src/Nethermind/Nethermind.Optimism/L1BlockGasInfo.cs index e27a2f6efaf..0df4477eb40 100644 --- a/src/Nethermind/Nethermind.Optimism/L1BlockGasInfo.cs +++ b/src/Nethermind/Nethermind.Optimism/L1BlockGasInfo.cs @@ -8,27 +8,31 @@ namespace Nethermind.Optimism; -public readonly struct L1TxGasInfo(UInt256? l1Fee, UInt256? l1GasPrice, UInt256? l1GasUsed, string? l1FeeScalar) +public readonly struct L1TxGasInfo(UInt256? l1Fee, UInt256? l1GasPrice, UInt256? l1GasUsed, string? l1FeeScalar, UInt256? l1BaseFeeScalar = null, UInt256? l1BlobBaseFee = null, UInt256? l1BlobBaseFeeScalar = null) { public UInt256? L1Fee { get; } = l1Fee; public UInt256? L1GasPrice { get; } = l1GasPrice; public UInt256? L1GasUsed { get; } = l1GasUsed; public string? L1FeeScalar { get; } = l1FeeScalar; + + public UInt256? L1BaseFeeScalar { get; } = l1BaseFeeScalar; + public UInt256? L1BlobBaseFee { get; } = l1BlobBaseFee; + public UInt256? L1BlobBaseFeeScalar { get; } = l1BlobBaseFeeScalar; } public readonly struct L1BlockGasInfo { private readonly UInt256? _l1GasPrice; - private readonly UInt256 _l1BlobBaseFee; - private readonly UInt256 _l1BaseFeeScalar; - private readonly UInt256 _l1BlobBaseFeeScalar; + private readonly UInt256? _l1BlobBaseFee; + private readonly UInt256? _l1BaseFeeScalar; + private readonly UInt256? _l1BlobBaseFeeScalar; private readonly UInt256 _l1BaseFee; private readonly UInt256 _overhead; private readonly UInt256 _feeScalar; private readonly string? _feeScalarDecimal; private readonly bool _isFjord; private readonly bool _isEcotone; - private readonly bool _isRegolith; + private readonly bool _isPostRegolith; private static readonly byte[] BedrockL1AttributesSelector = [0x01, 0x5d, 0x8e, 0xb9]; private readonly IOptimismSpecHelper _specHelper; @@ -48,6 +52,7 @@ public L1BlockGasInfo(Block block, IOptimismSpecHelper specHelper) Memory data = depositTx.Data.Value; _isFjord = _specHelper.IsFjord(block.Header); + _isPostRegolith = _specHelper.IsRegolith(block.Header); if (_isFjord || (_isEcotone = (_specHelper.IsEcotone(block.Header) && !data[0..4].Span.SequenceEqual(BedrockL1AttributesSelector)))) { @@ -63,7 +68,6 @@ public L1BlockGasInfo(Block block, IOptimismSpecHelper specHelper) } else { - _isRegolith = true; if (data.Length < 4 + 32 * 8) { return; @@ -88,20 +92,21 @@ public readonly L1TxGasInfo GetTxGasInfo(Transaction tx) if (_isFjord) { UInt256 fastLzSize = OPL1CostHelper.ComputeFlzCompressLen(tx); - l1Fee = OPL1CostHelper.ComputeL1CostFjord(fastLzSize, _l1GasPrice.Value, _l1BlobBaseFee, _l1BaseFeeScalar, _l1BlobBaseFeeScalar); + l1Fee = OPL1CostHelper.ComputeL1CostFjord(fastLzSize, _l1GasPrice.Value, _l1BlobBaseFee!.Value, _l1BaseFeeScalar!.Value, _l1BlobBaseFeeScalar!.Value, out UInt256 estimatedSize); + l1GasUsed = OPL1CostHelper.ComputeGasUsedFjord(estimatedSize); } else if (_isEcotone) { - l1GasUsed = OPL1CostHelper.ComputeDataGas(tx, _isRegolith); - l1Fee = OPL1CostHelper.ComputeL1CostEcotone(l1GasUsed.Value, _l1GasPrice.Value, _l1BlobBaseFee, _l1BaseFeeScalar, _l1BlobBaseFeeScalar); + l1GasUsed = OPL1CostHelper.ComputeDataGas(tx, _isPostRegolith); + l1Fee = OPL1CostHelper.ComputeL1CostEcotone(l1GasUsed.Value, _l1GasPrice.Value, _l1BlobBaseFee!.Value, _l1BaseFeeScalar!.Value, _l1BlobBaseFeeScalar!.Value); } else { - l1GasUsed = OPL1CostHelper.ComputeDataGas(tx, _isRegolith) + _overhead; + l1GasUsed = OPL1CostHelper.ComputeDataGas(tx, _isPostRegolith) + _overhead; l1Fee = OPL1CostHelper.ComputeL1CostPreEcotone(l1GasUsed.Value, _l1BaseFee, _feeScalar); } } - return new L1TxGasInfo(l1Fee, _l1GasPrice, l1GasUsed, _feeScalarDecimal); + return new L1TxGasInfo(l1Fee, _l1GasPrice, l1GasUsed, _feeScalarDecimal, _l1BaseFeeScalar, _l1BlobBaseFee, _l1BlobBaseFeeScalar); } } diff --git a/src/Nethermind/Nethermind.Optimism/OPL1CostHelper.cs b/src/Nethermind/Nethermind.Optimism/OPL1CostHelper.cs index ebaf73014fd..1cf69cf5ee9 100644 --- a/src/Nethermind/Nethermind.Optimism/OPL1CostHelper.cs +++ b/src/Nethermind/Nethermind.Optimism/OPL1CostHelper.cs @@ -2,7 +2,6 @@ // SPDX-License-Identifier: LGPL-3.0-only using System; -using System.Buffers; using System.Linq; using System.Runtime.CompilerServices; using Nethermind.Core; @@ -62,7 +61,7 @@ public UInt256 ComputeL1Cost(Transaction tx, BlockHeader header, IWorldState wor uint fastLzSize = ComputeFlzCompressLen(tx); - return ComputeL1CostFjord(fastLzSize, l1BaseFee, blobBaseFee, l1BaseFeeScalar, l1BlobBaseFeeScalar); + return ComputeL1CostFjord(fastLzSize, l1BaseFee, blobBaseFee, l1BaseFeeScalar, l1BlobBaseFeeScalar, out _); } UInt256 dataGas = ComputeDataGas(tx, _opSpecHelper.IsRegolith(header)); @@ -112,7 +111,7 @@ public static UInt256 ComputeDataGas(Transaction tx, bool isRegolith) // l1FeeScaled = baseFeeScalar * l1BaseFee * 16 + blobFeeScalar * l1BlobBaseFee // estimatedSize = max(minTransactionSize, intercept + fastlzCoef * fastlzSize) // l1Cost = estimatedSize * l1FeeScaled / 1e12 - public static UInt256 ComputeL1CostFjord(UInt256 fastLzSize, UInt256 l1BaseFee, UInt256 blobBaseFee, UInt256 l1BaseFeeScalar, UInt256 l1BlobBaseFeeScalar) + public static UInt256 ComputeL1CostFjord(UInt256 fastLzSize, UInt256 l1BaseFee, UInt256 blobBaseFee, UInt256 l1BaseFeeScalar, UInt256 l1BlobBaseFeeScalar, out UInt256 estimatedSize) { UInt256 l1FeeScaled = l1BaseFeeScalar * l1BaseFee * PrecisionMultiplier + l1BlobBaseFeeScalar * blobBaseFee; UInt256 fastLzCost = L1CostFastlzCoef * fastLzSize; @@ -126,7 +125,7 @@ public static UInt256 ComputeL1CostFjord(UInt256 fastLzSize, UInt256 l1BaseFee, fastLzCost -= L1CostInterceptNeg; } - var estimatedSize = UInt256.Max(MinTransactionSizeScaled, fastLzCost); + estimatedSize = UInt256.Max(MinTransactionSizeScaled, fastLzCost); return estimatedSize * l1FeeScaled / FjordDivisor; } @@ -242,4 +241,6 @@ uint setNextHash(uint ip, ref Span ht) } return FlzCompressLen(encoded); } + + internal static UInt256 ComputeGasUsedFjord(UInt256 estimatedSize) => estimatedSize * GasCostOf.TxDataNonZeroEip2028 / BasicDivisor; } diff --git a/src/Nethermind/Nethermind.Optimism/Rpc/IOptimismEthRpcModule.cs b/src/Nethermind/Nethermind.Optimism/Rpc/IOptimismEthRpcModule.cs index 963fbe27a4b..e01358a2ae2 100644 --- a/src/Nethermind/Nethermind.Optimism/Rpc/IOptimismEthRpcModule.cs +++ b/src/Nethermind/Nethermind.Optimism/Rpc/IOptimismEthRpcModule.cs @@ -6,6 +6,9 @@ using Nethermind.Core.Crypto; using Nethermind.JsonRpc; using Nethermind.Blockchain.Find; +using Nethermind.Int256; +using System.Threading.Tasks; +using Nethermind.Facade.Eth; namespace Nethermind.Optimism.Rpc; @@ -23,4 +26,25 @@ public interface IOptimismEthRpcModule : IEthRpcModule 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 Task> 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 27154fdf0e1..e013b3e7031 100644 --- a/src/Nethermind/Nethermind.Optimism/Rpc/OptimismEthRpcModule.cs +++ b/src/Nethermind/Nethermind.Optimism/Rpc/OptimismEthRpcModule.cs @@ -12,9 +12,9 @@ using Nethermind.Evm; using Nethermind.Facade; using Nethermind.Facade.Eth; +using Nethermind.Int256; using Nethermind.JsonRpc; using Nethermind.JsonRpc.Client; -using Nethermind.JsonRpc.Data; using Nethermind.JsonRpc.Modules; using Nethermind.JsonRpc.Modules.Eth; using Nethermind.JsonRpc.Modules.Eth.FeeHistory; @@ -22,6 +22,7 @@ using Nethermind.Logging; using Nethermind.Serialization.Rlp; using Nethermind.State; +using Nethermind.Synchronization.ParallelSync; using Nethermind.TxPool; using Nethermind.Wallet; @@ -159,4 +160,106 @@ public override async Task> eth_sendRawTransaction(byte[] return ResultWrapper.Success( new(txHash, (OptimismTxReceipt)receipt, gasInfo.Value, l1GasInfo.GetTxGasInfo(block.Transactions.First(tx => tx.Hash == txHash)), logIndexStart)); } + + public new Task> eth_getTransactionByHash(Hash256 transactionHash) + { + UInt256? baseFee = null; + _txPoolBridge.TryGetPendingTransaction(transactionHash, out Transaction? transaction); + TxReceipt? receipt = null; // note that if transaction is pending then for sure no receipt is known + if (transaction is null) + { + (receipt, transaction, baseFee) = _blockchainBridge.GetTransaction(transactionHash, checkTxnPool: false); + if (transaction is null) + { + return Task.FromResult(ResultWrapper.Success(null!)); + } + } + + RecoverTxSenderIfNeeded(transaction); + OptimismTransactionForRpc transactionModel = new(receipt?.BlockHash, receipt as OptimismTxReceipt, transaction, baseFee); + if (_logger.IsTrace) + _logger.Trace($"eth_getTransactionByHash request {transactionHash}, result: {transactionModel.Hash}"); + return Task.FromResult(ResultWrapper.Success(transactionModel)); + } + + public new 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()); + } + + Block block = searchResult.Object; + if (positionIndex < 0 || positionIndex > block!.Transactions.Length - 1) + { + 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(block.Hash, receipts.FirstOrDefault(r => r.TxHash == transaction.Hash), transaction, block.BaseFeePerGas); + + return ResultWrapper.Success(transactionModel); + } + + public new 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); + } + + OptimismTxReceipt[] receipts = _receiptFinder.Get(block).Cast().ToArray(); + + Transaction transaction = block.Transactions[(int)positionIndex]; + RecoverTxSenderIfNeeded(transaction); + + OptimismTransactionForRpc transactionModel = new(block.Hash, receipts.FirstOrDefault(r => r.TxHash == transaction.Hash), transaction, block.BaseFeePerGas); + + 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); + if (searchResult.IsError) + { + return GetFailureResult(searchResult, _ethSyncingInfo.SyncMode.HaveNotSyncedBodiesYet()); + } + + Block? block = searchResult.Object; + + if (block is null) + { + return ResultWrapper.Success(null); + } + + BlockForRpc result = new BlockForRpc(block, false, _specProvider); + + OptimismTxReceipt[] receipts = _receiptFinder.Get(block).Cast().ToArray(); + + if (returnFullTransactionObjects) + { + _blockchainBridge.RecoverTxSenders(block); + result.Transactions = result.Transactions.Select((hash, index) => new OptimismTransactionForRpc(block.Hash, receipts.FirstOrDefault(r => r.TxHash?.Equals(hash) ?? false), block.Transactions[index], block.BaseFeePerGas)); + } + + return ResultWrapper.Success(result); + } } diff --git a/src/Nethermind/Nethermind.Optimism/Rpc/OptimismReceiptForRpc.cs b/src/Nethermind/Nethermind.Optimism/Rpc/OptimismReceiptForRpc.cs index d902059872b..edaa0374325 100644 --- a/src/Nethermind/Nethermind.Optimism/Rpc/OptimismReceiptForRpc.cs +++ b/src/Nethermind/Nethermind.Optimism/Rpc/OptimismReceiptForRpc.cs @@ -25,27 +25,42 @@ public OptimismReceiptForRpc(Hash256 txHash, OptimismTxReceipt receipt, TxGasInf L1GasUsed = l1GasInfo.L1GasUsed; L1GasPrice = l1GasInfo.L1GasPrice; L1FeeScalar = l1GasInfo.L1FeeScalar; + + L1BaseFeeScalar = l1GasInfo.L1BaseFeeScalar; + L1BlobBaseFee = l1GasInfo.L1BlobBaseFee; + L1BlobBaseFeeScalar = l1GasInfo.L1BlobBaseFeeScalar; } } // DepositTx related fields [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public UInt256? DepositNonce; + public UInt256? DepositNonce { get; set; } [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public UInt256? DepositReceiptVersion; + public UInt256? DepositReceiptVersion { get; set; } + // Regular tx fields [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public UInt256? L1Fee; + public UInt256? L1Fee { get; set; } [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public UInt256? L1GasPrice; + public UInt256? L1GasPrice { get; set; } [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public UInt256? L1GasUsed; + public UInt256? L1GasUsed { get; set; } // Pre-ecotone field of a regular tx fields [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public string? L1FeeScalar; + public string? L1FeeScalar { get; set; } + + // Fjord fields + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public UInt256? L1BaseFeeScalar { get; set; } + + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public UInt256? L1BlobBaseFee { get; set; } + + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public UInt256? L1BlobBaseFeeScalar { get; set; } } diff --git a/src/Nethermind/Nethermind.Optimism/Rpc/OptimismTransactionForRpc.cs b/src/Nethermind/Nethermind.Optimism/Rpc/OptimismTransactionForRpc.cs new file mode 100644 index 00000000000..cb28429f3f6 --- /dev/null +++ b/src/Nethermind/Nethermind.Optimism/Rpc/OptimismTransactionForRpc.cs @@ -0,0 +1,29 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using Nethermind.Core.Crypto; +using Nethermind.Core; +using Nethermind.Facade.Eth; +using Nethermind.Int256; +using System.Text.Json.Serialization; + +namespace Nethermind.Optimism.Rpc; + +public class OptimismTransactionForRpc : TransactionForRpc +{ + public OptimismTransactionForRpc(Hash256? blockHash, OptimismTxReceipt? receipt, Transaction transaction, UInt256? baseFee = null) + : base(blockHash, receipt?.BlockNumber, receipt?.Index, transaction, baseFee) + { + if (transaction.Type == TxType.DepositTx) + { + SourceHash = transaction.SourceHash; + Mint = transaction.Mint; + IsSystemTx = transaction.IsOPSystemTransaction ? true : null; + Nonce = receipt?.DepositNonce; + DepositReceiptVersion = receipt?.DepositReceiptVersion; + } + } + + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public UInt256? DepositReceiptVersion { get; set; } +} diff --git a/src/Nethermind/Nethermind.Runner/configs/base-mainnet.cfg b/src/Nethermind/Nethermind.Runner/configs/base-mainnet.cfg index 359c438be29..522ba88f40c 100644 --- a/src/Nethermind/Nethermind.Runner/configs/base-mainnet.cfg +++ b/src/Nethermind/Nethermind.Runner/configs/base-mainnet.cfg @@ -15,8 +15,8 @@ "AncientBodiesBarrier": 105235063, "AncientReceiptsBarrier": 105235063, "FastSyncCatchUpHeightDelta": "10000000000", - "PivotNumber": 14239812, - "PivotHash": "0x335a694a721f223125c0f494f44c7525ef1503a664b227a7b3478fbf8c4175b7", + "PivotNumber": 15745886, + "PivotHash": "0xf1065a11719698d3e668984e6b2f63b728546e7cadbcec67448e2deafd8b27b5", "PivotTotalDifficulty": "0", "MaxAttemptsToUpdatePivot": 0 }, @@ -33,7 +33,7 @@ }, "Blocks": { "SecondsPerSlot": 2, - "TargetBlockGasLimit": 60000000 + "TargetBlockGasLimit": 97500000 }, "Merge": { "Enabled": true diff --git a/src/Nethermind/Nethermind.Runner/configs/base-sepolia.cfg b/src/Nethermind/Nethermind.Runner/configs/base-sepolia.cfg index c20d5897040..bcd4a299b91 100644 --- a/src/Nethermind/Nethermind.Runner/configs/base-sepolia.cfg +++ b/src/Nethermind/Nethermind.Runner/configs/base-sepolia.cfg @@ -13,8 +13,8 @@ "FastSync": true, "SnapSync": true, "FastSyncCatchUpHeightDelta": "10000000000", - "PivotNumber": 9750377, - "PivotHash": "0x71ce74cb650b24f7fc473934e97c41f3cabe6b094ac368d9d7a733f0cb514599", + "PivotNumber": 11256406, + "PivotHash": "0x236cbe4bead9ce29d4a6bfb3c198837c20d1c38bf4a9cda1fc6b6e9ce926a924", "PivotTotalDifficulty": "0", "MaxAttemptsToUpdatePivot": 0 }, @@ -31,7 +31,7 @@ }, "Blocks": { "SecondsPerSlot": 2, - "TargetBlockGasLimit": 45000000 + "TargetBlockGasLimit": 97500000 }, "Merge": { "Enabled": true diff --git a/src/Nethermind/Nethermind.Runner/configs/op-mainnet.cfg b/src/Nethermind/Nethermind.Runner/configs/op-mainnet.cfg index d8f2a8fcdae..135513deb32 100644 --- a/src/Nethermind/Nethermind.Runner/configs/op-mainnet.cfg +++ b/src/Nethermind/Nethermind.Runner/configs/op-mainnet.cfg @@ -16,8 +16,8 @@ "AncientBodiesBarrier": 105235063, "AncientReceiptsBarrier": 105235063, "FastSyncCatchUpHeightDelta": "10000000000", - "PivotNumber": 119834660, - "PivotHash": "0xcdab6080b3846cf67b50935604deccbdf0e27434fa7b454ccf2195051ecd7a10", + "PivotNumber": 121341196, + "PivotHash": "0x31564a3dab8729a5bbd478dec3a4be5530250f0d4c87d08ca86d0634c5aac424", "PivotTotalDifficulty": "0", "MaxAttemptsToUpdatePivot": 0 }, diff --git a/src/Nethermind/Nethermind.Runner/configs/op-sepolia.cfg b/src/Nethermind/Nethermind.Runner/configs/op-sepolia.cfg index e2fc13f67b8..f5020b2253e 100644 --- a/src/Nethermind/Nethermind.Runner/configs/op-sepolia.cfg +++ b/src/Nethermind/Nethermind.Runner/configs/op-sepolia.cfg @@ -13,8 +13,8 @@ "FastSync": true, "SnapSync": true, "FastSyncCatchUpHeightDelta": "10000000000", - "PivotNumber": 11338054, - "PivotHash": "0xf4307e8fd758db460d57b87bd910fa932feb928932c99faa85edf5a588ede049", + "PivotNumber": 13239302, + "PivotHash": "0x386a03acc090f04528947dc896262a1ecb695a580301d94ea97f5b6633e7e661", "PivotTotalDifficulty": "0", "MaxAttemptsToUpdatePivot": 0 },