diff --git a/src/Nethermind/Chains/op-sepolia.json b/src/Nethermind/Chains/op-sepolia.json index a19af8769503..f90ba4e5a259 100644 --- a/src/Nethermind/Chains/op-sepolia.json +++ b/src/Nethermind/Chains/op-sepolia.json @@ -8,6 +8,7 @@ "bedrockBlockNumber": "0x0", "canyonTimestamp": "0x6553a790", "ecotoneTimestamp": "0x65D62C10", + "fjordTimestamp": "0x66575100", "l1FeeRecipient": "0x420000000000000000000000000000000000001A", "l1BlockAddress": "0x4200000000000000000000000000000000000015", "canyonBaseFeeChangeDenominator": "250", @@ -60,6 +61,7 @@ "eip4844TransitionTimestamp": "0x65D62C10", "eip5656TransitionTimestamp": "0x65D62C10", "eip6780TransitionTimestamp": "0x65D62C10", + "eip7212TransitionTimestamp": "0x66575100", "terminalTotalDifficulty": "0" }, "genesis": { diff --git a/src/Nethermind/Nethermind.AuRa.Test/Contract/AuRaContractGasLimitOverrideTests.cs b/src/Nethermind/Nethermind.AuRa.Test/Contract/AuRaContractGasLimitOverrideTests.cs index 2fc2439574ba..7df3df7dcca5 100644 --- a/src/Nethermind/Nethermind.AuRa.Test/Contract/AuRaContractGasLimitOverrideTests.cs +++ b/src/Nethermind/Nethermind.AuRa.Test/Contract/AuRaContractGasLimitOverrideTests.cs @@ -7,6 +7,7 @@ using System.Threading.Tasks; using FluentAssertions; using Nethermind.Abi; +using Nethermind.Blockchain; using Nethermind.Consensus; using Nethermind.Consensus.AuRa; using Nethermind.Consensus.AuRa.Contracts; @@ -85,7 +86,7 @@ protected override BlockProcessor CreateBlockProcessor() BlockGasLimitContract gasLimitContract = new(AbiEncoder.Instance, blockGasLimitContractTransition.Value, blockGasLimitContractTransition.Key, new ReadOnlyTxProcessingEnv( WorldStateManager, - BlockTree, SpecProvider, LimboLogs.Instance)); + BlockTree.AsReadOnly(), SpecProvider, LimboLogs.Instance)); GasLimitOverrideCache = new AuRaContractGasLimitOverride.Cache(); GasLimitCalculator = new AuRaContractGasLimitOverride(new[] { gasLimitContract }, GasLimitOverrideCache, false, new FollowOtherMiners(SpecProvider), LimboLogs.Instance); diff --git a/src/Nethermind/Nethermind.AuRa.Test/Contract/TxPriorityContractTests.cs b/src/Nethermind/Nethermind.AuRa.Test/Contract/TxPriorityContractTests.cs index 276671dab2aa..1caa20bf3a90 100644 --- a/src/Nethermind/Nethermind.AuRa.Test/Contract/TxPriorityContractTests.cs +++ b/src/Nethermind/Nethermind.AuRa.Test/Contract/TxPriorityContractTests.cs @@ -10,6 +10,7 @@ using System.Threading.Tasks; using FluentAssertions; using Nethermind.Abi; +using Nethermind.Blockchain; using Nethermind.Blockchain.Data; using Nethermind.Consensus.AuRa.Contracts; using Nethermind.Consensus.AuRa.Contracts.DataStore; @@ -254,7 +255,7 @@ protected override TxPoolTxSource CreateTxPoolTxSource() TxPoolTxSource txPoolTxSource = base.CreateTxPoolTxSource(); TxPriorityContract = new TxPriorityContract(AbiEncoder.Instance, TestItem.AddressA, - new ReadOnlyTxProcessingEnv(WorldStateManager, BlockTree, SpecProvider, LimboLogs.Instance)); + new ReadOnlyTxProcessingEnv(WorldStateManager, BlockTree.AsReadOnly(), SpecProvider, LimboLogs.Instance)); Priorities = new DictionaryContractDataStore( new TxPriorityContract.DestinationSortedListContractDataStoreCollection(), diff --git a/src/Nethermind/Nethermind.AuRa.Test/Transactions/TxCertifierFilterTests.cs b/src/Nethermind/Nethermind.AuRa.Test/Transactions/TxCertifierFilterTests.cs index 594d365cb23d..00a2894d175e 100644 --- a/src/Nethermind/Nethermind.AuRa.Test/Transactions/TxCertifierFilterTests.cs +++ b/src/Nethermind/Nethermind.AuRa.Test/Transactions/TxCertifierFilterTests.cs @@ -6,6 +6,7 @@ using FluentAssertions; using Nethermind.Abi; using Nethermind.AuRa.Test.Contract; +using Nethermind.Blockchain; using Nethermind.Consensus.AuRa; using Nethermind.Consensus.AuRa.Contracts; using Nethermind.Consensus.AuRa.Transactions; @@ -138,7 +139,7 @@ protected override BlockProcessor CreateBlockProcessor() AbiEncoder abiEncoder = AbiEncoder.Instance; ReadOnlyTransactionProcessorSource = new ReadOnlyTxProcessingEnv( WorldStateManager, - BlockTree, SpecProvider, + BlockTree.AsReadOnly(), SpecProvider, LimboLogs.Instance); RegisterContract = new RegisterContract(abiEncoder, ChainSpec.Parameters.Registrar, ReadOnlyTransactionProcessorSource); CertifierContract = new CertifierContract( diff --git a/src/Nethermind/Nethermind.AuRa.Test/Transactions/TxPermissionFilterTest.cs b/src/Nethermind/Nethermind.AuRa.Test/Transactions/TxPermissionFilterTest.cs index 2a43f1bd7ab7..e18f723dbf94 100644 --- a/src/Nethermind/Nethermind.AuRa.Test/Transactions/TxPermissionFilterTest.cs +++ b/src/Nethermind/Nethermind.AuRa.Test/Transactions/TxPermissionFilterTest.cs @@ -8,6 +8,7 @@ using FluentAssertions; using Nethermind.Abi; using Nethermind.AuRa.Test.Contract; +using Nethermind.Blockchain; using Nethermind.Consensus.AuRa; using Nethermind.Consensus.AuRa.Contracts; using Nethermind.Consensus.AuRa.Transactions; @@ -277,12 +278,12 @@ protected override BlockProcessor CreateBlockProcessor() IReadOnlyTrieStore trieStore = new TrieStore(DbProvider.StateDb, LimboLogs.Instance).AsReadOnly(); IReadOnlyTxProcessorSource txProcessorSource = new ReadOnlyTxProcessingEnv( WorldStateManager, - BlockTree, + BlockTree.AsReadOnly(), SpecProvider, LimboLogs.Instance); VersionedTransactionPermissionContract transactionPermissionContract = new(AbiEncoder.Instance, _contractAddress, 1, - new ReadOnlyTxProcessingEnv(WorldStateManager, BlockTree, SpecProvider, LimboLogs.Instance), TransactionPermissionContractVersions, LimboLogs.Instance, SpecProvider); + new ReadOnlyTxProcessingEnv(WorldStateManager, BlockTree.AsReadOnly(), SpecProvider, LimboLogs.Instance), TransactionPermissionContractVersions, LimboLogs.Instance, SpecProvider); TxPermissionFilterCache = new PermissionBasedTxFilter.Cache(); PermissionBasedTxFilter = new PermissionBasedTxFilter(transactionPermissionContract, TxPermissionFilterCache, LimboLogs.Instance); diff --git a/src/Nethermind/Nethermind.Consensus/Processing/BlockCachePreWarmer.cs b/src/Nethermind/Nethermind.Consensus/Processing/BlockCachePreWarmer.cs index db3a33ed5abe..39911c82ee36 100644 --- a/src/Nethermind/Nethermind.Consensus/Processing/BlockCachePreWarmer.cs +++ b/src/Nethermind/Nethermind.Consensus/Processing/BlockCachePreWarmer.cs @@ -70,26 +70,36 @@ private void PreWarmCachesParallel(Block suggestedBlock, Hash256 parentStateRoot void WarmupWithdrawals(ParallelOptions parallelOptions, IReleaseSpec spec, Block block, Hash256 stateRoot) { + if (parallelOptions.CancellationToken.IsCancellationRequested) return; if (spec.WithdrawalsEnabled && block.Withdrawals is not null) { - ReadOnlyTxProcessingEnv env = _envPool.Get(); - try - { - using IReadOnlyTransactionProcessor transactionProcessor = env.Build(stateRoot); - Parallel.For(0, block.Withdrawals.Length, parallelOptions, - i => env.StateProvider.WarmUp(block.Withdrawals[i].Address) - ); - } - finally - { - env.Reset(); - _envPool.Return(env); - } + Parallel.For(0, block.Withdrawals.Length, parallelOptions, + i => + { + ReadOnlyTxProcessingEnv env = _envPool.Get(); + Hash256 stateBefore = env.StateProvider.StateRoot; + env.StateProvider.StateRoot = stateRoot; + try + { + env.StateProvider.WarmUp(block.Withdrawals[i].Address); + } + catch (Exception ex) + { + if (_logger.IsDebug) _logger.Error($"Error pre-warming withdrawal {i}", ex); + } + finally + { + env.StateProvider.StateRoot = stateBefore; + env.Reset(); + _envPool.Return(env); + } + }); } } void WarmupTransactions(ParallelOptions parallelOptions, IReleaseSpec spec, Block block, Hash256 stateRoot) { + if (parallelOptions.CancellationToken.IsCancellationRequested) return; Parallel.For(0, block.Transactions.Length, parallelOptions, i => { // If the transaction has already been processed or being processed, exit early diff --git a/src/Nethermind/Nethermind.Consensus/Processing/ReadOnlyChainProcessingEnv.cs b/src/Nethermind/Nethermind.Consensus/Processing/ReadOnlyChainProcessingEnv.cs index ee64bb8cf92b..ba2071ce6833 100644 --- a/src/Nethermind/Nethermind.Consensus/Processing/ReadOnlyChainProcessingEnv.cs +++ b/src/Nethermind/Nethermind.Consensus/Processing/ReadOnlyChainProcessingEnv.cs @@ -7,7 +7,6 @@ using Nethermind.Consensus.Rewards; using Nethermind.Consensus.Validators; using Nethermind.Core.Specs; -using Nethermind.Db; using Nethermind.Logging; using Nethermind.State; @@ -41,7 +40,16 @@ public ReadOnlyChainProcessingEnv( IBlockProcessor.IBlockTransactionsExecutor transactionsExecutor = blockTransactionsExecutor ?? new BlockProcessor.BlockValidationTransactionsExecutor(_txEnv.TransactionProcessor, StateProvider); - BlockProcessor = new BlockProcessor( + BlockProcessor = CreateBlockProcessor(txEnv, blockValidator, rewardCalculator, receiptStorage, specProvider, logManager, transactionsExecutor); + + _blockProcessingQueue = new BlockchainProcessor(_txEnv.BlockTree, BlockProcessor, recoveryStep, _txEnv.StateReader, logManager, BlockchainProcessor.Options.NoReceipts); + BlockProcessingQueue = _blockProcessingQueue; + ChainProcessor = new OneTimeChainProcessor(txEnv.StateProvider, _blockProcessingQueue); + } + + protected virtual IBlockProcessor CreateBlockProcessor(ReadOnlyTxProcessingEnv txEnv, IBlockValidator blockValidator, IRewardCalculator rewardCalculator, IReceiptStorage receiptStorage, ISpecProvider specProvider, ILogManager logManager, IBlockProcessor.IBlockTransactionsExecutor transactionsExecutor) + { + return new BlockProcessor( specProvider, blockValidator, rewardCalculator, @@ -50,10 +58,6 @@ public ReadOnlyChainProcessingEnv( receiptStorage, new BlockhashStore(txEnv.BlockTree, specProvider, StateProvider), logManager); - - _blockProcessingQueue = new BlockchainProcessor(_txEnv.BlockTree, BlockProcessor, recoveryStep, _txEnv.StateReader, logManager, BlockchainProcessor.Options.NoReceipts); - BlockProcessingQueue = _blockProcessingQueue; - ChainProcessor = new OneTimeChainProcessor(txEnv.StateProvider, _blockProcessingQueue); } public void Dispose() diff --git a/src/Nethermind/Nethermind.Consensus/Processing/ReadOnlyTxProcessingEnv.cs b/src/Nethermind/Nethermind.Consensus/Processing/ReadOnlyTxProcessingEnv.cs index 15b581e9207a..fadbb5cd495c 100644 --- a/src/Nethermind/Nethermind.Consensus/Processing/ReadOnlyTxProcessingEnv.cs +++ b/src/Nethermind/Nethermind.Consensus/Processing/ReadOnlyTxProcessingEnv.cs @@ -12,52 +12,48 @@ // ReSharper disable MemberCanBePrivate.Global // ReSharper disable UnusedAutoPropertyAccessor.Global -namespace Nethermind.Consensus.Processing +namespace Nethermind.Consensus.Processing; + +public class ReadOnlyTxProcessingEnv : IReadOnlyTxProcessorSource { - public class ReadOnlyTxProcessingEnv : IReadOnlyTxProcessorSource + protected readonly ISpecProvider _specProvider; + protected readonly ILogManager? _logManager; + + public IStateReader StateReader { get; } + public IWorldState StateProvider { get; } + public ITransactionProcessor TransactionProcessor { get; set; } + public IBlockTree BlockTree { get; } + + public ReadOnlyTxProcessingEnv( + IWorldStateManager? worldStateManager, + IReadOnlyBlockTree? readOnlyBlockTree, + ISpecProvider? specProvider, + ILogManager? logManager, + PreBlockCaches? preBlockCaches = null) + { + ArgumentNullException.ThrowIfNull(worldStateManager); + ArgumentNullException.ThrowIfNull(readOnlyBlockTree); + ArgumentNullException.ThrowIfNull(specProvider); + + StateReader = worldStateManager.GlobalStateReader; + StateProvider = worldStateManager.CreateResettableWorldState(preBlockCaches); + BlockTree = readOnlyBlockTree; + _specProvider = specProvider; + _logManager = logManager; + TransactionProcessor = CreateTransactionProcessor(); + } + + protected virtual TransactionProcessor CreateTransactionProcessor() + { + BlockhashProvider blockhashProvider = new(BlockTree, _specProvider, StateProvider, _logManager); + VirtualMachine virtualMachine = new(blockhashProvider, _specProvider, _logManager); + return new TransactionProcessor(_specProvider, StateProvider, virtualMachine, _logManager); + } + + public IReadOnlyTransactionProcessor Build(Hash256 stateRoot) => new ReadOnlyTransactionProcessor(TransactionProcessor, StateProvider, stateRoot); + + public void Reset() { - public IStateReader StateReader { get; } - public IWorldState StateProvider { get; } - public ITransactionProcessor TransactionProcessor { get; set; } - public IBlockTree BlockTree { get; } - public IBlockhashProvider BlockhashProvider { get; } - public IVirtualMachine Machine { get; } - public ISpecProvider SpecProvider { get; } - - public ReadOnlyTxProcessingEnv( - IWorldStateManager worldStateManager, - IBlockTree? blockTree, - ISpecProvider? specProvider, - ILogManager? logManager) - : this(worldStateManager, blockTree?.AsReadOnly(), specProvider, logManager) - { - } - - public ReadOnlyTxProcessingEnv( - IWorldStateManager worldStateManager, - IReadOnlyBlockTree? readOnlyBlockTree, - ISpecProvider? specProvider, - ILogManager? logManager, - PreBlockCaches? preBlockCaches = null) - { - ArgumentNullException.ThrowIfNull(specProvider); - ArgumentNullException.ThrowIfNull(worldStateManager); - SpecProvider = specProvider; - StateReader = worldStateManager.GlobalStateReader; - StateProvider = worldStateManager.CreateResettableWorldState(preBlockCaches); - - BlockTree = readOnlyBlockTree ?? throw new ArgumentNullException(nameof(readOnlyBlockTree)); - BlockhashProvider = new BlockhashProvider(BlockTree, specProvider, StateProvider, logManager); - - Machine = new VirtualMachine(BlockhashProvider, specProvider, logManager); - TransactionProcessor = new TransactionProcessor(specProvider, StateProvider, Machine, logManager); - } - - public IReadOnlyTransactionProcessor Build(Hash256 stateRoot) => new ReadOnlyTransactionProcessor(TransactionProcessor, StateProvider, stateRoot); - - public void Reset() - { - StateProvider.Reset(); - } + StateProvider.Reset(); } } diff --git a/src/Nethermind/Nethermind.Core/Collections/ThrowHelper.cs b/src/Nethermind/Nethermind.Core/Collections/ThrowHelper.cs index 81a93cd19359..b0d136b07f78 100644 --- a/src/Nethermind/Nethermind.Core/Collections/ThrowHelper.cs +++ b/src/Nethermind/Nethermind.Core/Collections/ThrowHelper.cs @@ -51,13 +51,6 @@ public static void ThrowArgumentOutOfRangeException_SizeHint() throw new ArgumentOutOfRangeException("sizeHint"); } - [DoesNotReturn] - [StackTraceHidden] - public static void ThrowArgumentNullException_Options() - { - throw new ArgumentNullException("options"); - } - [DoesNotReturn] [StackTraceHidden] public static void ThrowArgumentNullException_WritingStream() diff --git a/src/Nethermind/Nethermind.Core/Threading/ThreadExtensions.cs b/src/Nethermind/Nethermind.Core/Threading/ThreadExtensions.cs index 31d892ba8b69..002c6dadbe51 100644 --- a/src/Nethermind/Nethermind.Core/Threading/ThreadExtensions.cs +++ b/src/Nethermind/Nethermind.Core/Threading/ThreadExtensions.cs @@ -10,7 +10,7 @@ public static class ThreadExtensions { public readonly struct Disposable : IDisposable { - private readonly Thread _thread; + private readonly Thread? _thread; private readonly ThreadPriority _previousPriority; internal Disposable(Thread thread) @@ -22,7 +22,10 @@ internal Disposable(Thread thread) public void Dispose() { - _thread.Priority = _previousPriority; + if (_thread is not null && Thread.CurrentThread == _thread) + { + _thread.Priority = _previousPriority; + } } } diff --git a/src/Nethermind/Nethermind.Init/Steps/RegisterRpcModules.cs b/src/Nethermind/Nethermind.Init/Steps/RegisterRpcModules.cs index 673bf3eb88c1..4c2939de9c48 100644 --- a/src/Nethermind/Nethermind.Init/Steps/RegisterRpcModules.cs +++ b/src/Nethermind/Nethermind.Init/Steps/RegisterRpcModules.cs @@ -114,18 +114,7 @@ public virtual async Task Execute(CancellationToken cancellationToken) _api.LogManager); rpcModuleProvider.RegisterBoundedByCpuCount(debugModuleFactory, _jsonRpcConfig.Timeout); - TraceModuleFactory traceModuleFactory = new( - _api.WorldStateManager, - _api.BlockTree, - _jsonRpcConfig, - _api.BlockPreprocessor, - _api.RewardCalculatorSource, - _api.ReceiptStorage, - _api.SpecProvider, - _api.PoSSwitcher, - _api.LogManager); - - rpcModuleProvider.RegisterBoundedByCpuCount(traceModuleFactory, _jsonRpcConfig.Timeout); + RegisterTraceRpcModule(rpcModuleProvider); StepDependencyException.ThrowIfNull(_api.EthereumEcdsa); @@ -249,4 +238,31 @@ protected virtual void RegisterEthRpcModule(IRpcModuleProvider rpcModuleProvider rpcModuleProvider.RegisterBounded(ethModuleFactory, _jsonRpcConfig.EthModuleConcurrentInstances ?? Environment.ProcessorCount, _jsonRpcConfig.Timeout); } + + protected ModuleFactoryBase CreateTraceModuleFactory() + { + StepDependencyException.ThrowIfNull(_api.WorldStateManager); + StepDependencyException.ThrowIfNull(_api.BlockTree); + StepDependencyException.ThrowIfNull(_api.RewardCalculatorSource); + StepDependencyException.ThrowIfNull(_api.ReceiptStorage); + StepDependencyException.ThrowIfNull(_api.SpecProvider); + + return new TraceModuleFactory( + _api.WorldStateManager, + _api.BlockTree, + _jsonRpcConfig, + _api.BlockPreprocessor, + _api.RewardCalculatorSource, + _api.ReceiptStorage, + _api.SpecProvider, + _api.PoSSwitcher, + _api.LogManager); + } + + protected virtual void RegisterTraceRpcModule(IRpcModuleProvider rpcModuleProvider) + { + ModuleFactoryBase traceModuleFactory = CreateTraceModuleFactory(); + + rpcModuleProvider.RegisterBoundedByCpuCount(traceModuleFactory, _jsonRpcConfig.Timeout); + } } diff --git a/src/Nethermind/Nethermind.Init/Steps/StepInitializationException.cs b/src/Nethermind/Nethermind.Init/Steps/StepInitializationException.cs index 33840679e7bf..8fe0e62a4f3e 100644 --- a/src/Nethermind/Nethermind.Init/Steps/StepInitializationException.cs +++ b/src/Nethermind/Nethermind.Init/Steps/StepInitializationException.cs @@ -18,7 +18,7 @@ public StepDependencyException(string message) { } - public static void ThrowIfNull([NotNull] object? argument, [CallerArgumentExpression("argument")] string? paramName = null) + public static void ThrowIfNull([NotNull] object? argument, [CallerArgumentExpression(nameof(argument))] string? paramName = null) { if (argument is not null) return; diff --git a/src/Nethermind/Nethermind.JsonRpc.Test/JsonRpcServiceTests.cs b/src/Nethermind/Nethermind.JsonRpc.Test/JsonRpcServiceTests.cs index 6748030a5bf2..0485a2e45281 100644 --- a/src/Nethermind/Nethermind.JsonRpc.Test/JsonRpcServiceTests.cs +++ b/src/Nethermind/Nethermind.JsonRpc.Test/JsonRpcServiceTests.cs @@ -38,12 +38,17 @@ public class JsonRpcServiceTests [SetUp] public void Initialize() { - Assembly jConfig = typeof(JsonRpcConfig).Assembly; _configurationProvider = new ConfigProvider(); _logManager = LimboLogs.Instance; _context = new JsonRpcContext(RpcEndpoint.Http); } + [TearDown] + public void TearDown() + { + _context?.Dispose(); + } + private IJsonRpcService _jsonRpcService = null!; private IConfigProvider _configurationProvider = null!; private ILogManager _logManager = null!; diff --git a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/RpcModuleProviderTests.cs b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/RpcModuleProviderTests.cs index 980d8f169c27..707fff9b4e09 100644 --- a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/RpcModuleProviderTests.cs +++ b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/RpcModuleProviderTests.cs @@ -28,6 +28,12 @@ public void Initialize() _context = new JsonRpcContext(RpcEndpoint.Http); } + [TearDown] + public void TearDown() + { + _context?.Dispose(); + } + [Test] public void Module_provider_will_recognize_disabled_modules() { diff --git a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Trace/ParityStyleTracerTests.cs b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Trace/ParityStyleTracerTests.cs index f811731191c4..54e8d292a821 100644 --- a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Trace/ParityStyleTracerTests.cs +++ b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Trace/ParityStyleTracerTests.cs @@ -93,7 +93,7 @@ public void Setup() [Test] public void Can_trace_raw_parity_style() { - TraceRpcModule traceRpcModule = new(NullReceiptStorage.Instance, _tracer, _blockTree, _jsonRpcConfig, MainnetSpecProvider.Instance, LimboLogs.Instance, _stateReader); + TraceRpcModule traceRpcModule = new(NullReceiptStorage.Instance, _tracer, _blockTree, _jsonRpcConfig, _stateReader); ResultWrapper result = traceRpcModule.trace_rawTransaction(Bytes.FromHexString("f889808609184e72a00082271094000000000000000000000000000000000000000080a47f74657374320000000000000000000000000000000000000000000000000000006000571ca08a8bbf888cfa37bbf0bb965423625641fc956967b81d12e23709cead01446075a01ce999b56a8a88504be365442ea61239198e23d1fce7d00fcfc5cd3b44b7215f"), new[] { "trace" }); Assert.NotNull(result.Data); } @@ -101,7 +101,7 @@ public void Can_trace_raw_parity_style() [Test] public void Can_trace_raw_parity_style_berlin_tx() { - TraceRpcModule traceRpcModule = new(NullReceiptStorage.Instance, _tracer, _blockTree, _jsonRpcConfig, MainnetSpecProvider.Instance, LimboLogs.Instance, _stateReader); + TraceRpcModule traceRpcModule = new(NullReceiptStorage.Instance, _tracer, _blockTree, _jsonRpcConfig, _stateReader); ResultWrapper result = traceRpcModule.trace_rawTransaction(Bytes.FromHexString("01f85b821e8e8204d7847735940083030d408080853a60005500c080a0f43e70c79190701347517e283ef63753f6143a5225cbb500b14d98eadfb7616ba070893923d8a1fc97499f426524f9e82f8e0322dfac7c3d7e8a9eee515f0bcdc4"), new[] { "trace" }); Assert.NotNull(result.Data); } @@ -114,7 +114,7 @@ public void Should_return_correct_block_reward(bool isPostMerge) _blockTree!.SuggestBlock(block).Should().Be(AddBlockResult.Added); _poSSwitcher!.IsPostMerge(Arg.Any()).Returns(isPostMerge); - TraceRpcModule traceRpcModule = new(NullReceiptStorage.Instance, _tracer, _blockTree, _jsonRpcConfig, MainnetSpecProvider.Instance, LimboLogs.Instance, _stateReader); + TraceRpcModule traceRpcModule = new(NullReceiptStorage.Instance, _tracer, _blockTree, _jsonRpcConfig, _stateReader); ParityTxTraceFromStore[] result = traceRpcModule.trace_block(new BlockParameter(block.Number)).Data.ToArray(); if (isPostMerge) { diff --git a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/TraceRpcModuleTests.cs b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/TraceRpcModuleTests.cs index 0e499183eb8c..115afc9123f3 100644 --- a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/TraceRpcModuleTests.cs +++ b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/TraceRpcModuleTests.cs @@ -72,7 +72,7 @@ public async Task Build(ISpecProvider? specProvider = null, bool isAura = false) ReadOnlyChainProcessingEnv executeProcessingEnv = CreateChainProcessingEnv(executeBlockTransactionsExecutor); Tracer tracer = new(txProcessingEnv.StateProvider, traceProcessingEnv.ChainProcessor, executeProcessingEnv.ChainProcessor); - TraceRpcModule = new TraceRpcModule(receiptFinder, tracer, Blockchain.BlockFinder, JsonRpcConfig, MainnetSpecProvider.Instance, LimboLogs.Instance, txProcessingEnv.StateReader); + TraceRpcModule = new TraceRpcModule(receiptFinder, tracer, Blockchain.BlockFinder, JsonRpcConfig, txProcessingEnv.StateReader); for (int i = 1; i < 10; i++) { diff --git a/src/Nethermind/Nethermind.JsonRpc/IJsonRpcConfig.cs b/src/Nethermind/Nethermind.JsonRpc/IJsonRpcConfig.cs index c20dc47e5937..c8818c84aad6 100644 --- a/src/Nethermind/Nethermind.JsonRpc/IJsonRpcConfig.cs +++ b/src/Nethermind/Nethermind.JsonRpc/IJsonRpcConfig.cs @@ -106,6 +106,12 @@ public interface IJsonRpcConfig : IConfig [ConfigItem(Description = "The max length of HTTP request body, in bytes.", DefaultValue = "30000000")] long? MaxRequestBodySize { get; set; } + + [ConfigItem( + Description = "The max number of logs per response. For method `eth_getLogs`. If 0 then no limit.", + DefaultValue = "20000")] + public int MaxLogsPerResponse { get; set; } + [ConfigItem( Description = """ The number of concurrent instances for non-sharable calls: diff --git a/src/Nethermind/Nethermind.JsonRpc/JsonRpcConfig.cs b/src/Nethermind/Nethermind.JsonRpc/JsonRpcConfig.cs index 1e68d3dbc522..953ad379bc10 100644 --- a/src/Nethermind/Nethermind.JsonRpc/JsonRpcConfig.cs +++ b/src/Nethermind/Nethermind.JsonRpc/JsonRpcConfig.cs @@ -37,6 +37,7 @@ public int WebSocketsPort public bool BufferResponses { get; set; } public string CallsFilterFilePath { get; set; } = "Data/jsonrpc.filter"; public long? MaxRequestBodySize { get; set; } = 30000000; + public int MaxLogsPerResponse { get; set; } = 20_000; public int? EthModuleConcurrentInstances { get; set; } = null; public string JwtSecretFile { get; set; } = "keystore/jwt-secret"; public bool UnsecureDevNoRpcAuthentication { get; set; } diff --git a/src/Nethermind/Nethermind.JsonRpc/JsonRpcContext.cs b/src/Nethermind/Nethermind.JsonRpc/JsonRpcContext.cs index 9f130a4bee60..c145607924d5 100644 --- a/src/Nethermind/Nethermind.JsonRpc/JsonRpcContext.cs +++ b/src/Nethermind/Nethermind.JsonRpc/JsonRpcContext.cs @@ -1,12 +1,16 @@ // SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only +using System; +using System.Threading; using Nethermind.JsonRpc.Modules; namespace Nethermind.JsonRpc { - public class JsonRpcContext + public class JsonRpcContext : IDisposable { + public static AsyncLocal Current { get; private set; } = new(); + public static JsonRpcContext Http(JsonRpcUrl url) => new(RpcEndpoint.Http, url: url); public static JsonRpcContext WebSocket(JsonRpcUrl url) => new(RpcEndpoint.Ws, url: url); @@ -16,11 +20,19 @@ public JsonRpcContext(RpcEndpoint rpcEndpoint, IJsonRpcDuplexClient? duplexClien DuplexClient = duplexClient; Url = url; IsAuthenticated = Url?.IsAuthenticated == true || RpcEndpoint == RpcEndpoint.IPC; + Current.Value = this; } public RpcEndpoint RpcEndpoint { get; } public IJsonRpcDuplexClient? DuplexClient { get; } public JsonRpcUrl? Url { get; } public bool IsAuthenticated { get; } + public void Dispose() + { + if (Current.Value == this) + { + Current.Value = null; + } + } } } diff --git a/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/EthRpcModule.cs b/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/EthRpcModule.cs index 1e46576047f7..5c6b7b31e895 100644 --- a/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/EthRpcModule.cs +++ b/src/Nethermind/Nethermind.JsonRpc/Modules/Eth/EthRpcModule.cs @@ -12,6 +12,7 @@ using Nethermind.Blockchain.Find; using Nethermind.Blockchain.Receipts; using Nethermind.Core; +using Nethermind.Core.Collections; using Nethermind.Core.Crypto; using Nethermind.Core.Extensions; using Nethermind.Core.Specs; @@ -608,11 +609,28 @@ public ResultWrapper> eth_getLogs(Filter filter) try { - LogFilter logFilter = _blockchainBridge.GetFilter(filter.FromBlock, filter.ToBlock, - filter.Address, filter.Topics); + LogFilter logFilter = _blockchainBridge.GetFilter(filter.FromBlock, filter.ToBlock, filter.Address, filter.Topics); + IEnumerable filterLogs = _blockchainBridge.GetLogs(logFilter, fromBlock, toBlock, cancellationToken); - return ResultWrapper>.Success(GetLogs(filterLogs, cancellationTokenSource)); + ArrayPoolList logs = new(_rpcConfig.MaxLogsPerResponse); + + using (cancellationTokenSource) + { + foreach (FilterLog log in filterLogs) + { + logs.Add(log); + if (JsonRpcContext.Current.Value?.IsAuthenticated != true // not authenticated + && _rpcConfig.MaxLogsPerResponse != 0 // not unlimited + && logs.Count > _rpcConfig.MaxLogsPerResponse) + { + logs.Dispose(); + return ResultWrapper>.Fail($"Too many logs requested. Max logs per response is {_rpcConfig.MaxLogsPerResponse}.", ErrorCodes.LimitExceeded); + } + } + } + + return ResultWrapper>.Success(logs); } catch (ResourceNotFoundException exception) { diff --git a/src/Nethermind/Nethermind.JsonRpc/Modules/Trace/TraceModuleFactory.cs b/src/Nethermind/Nethermind.JsonRpc/Modules/Trace/TraceModuleFactory.cs index 9d34f031e44c..551967408fb9 100644 --- a/src/Nethermind/Nethermind.JsonRpc/Modules/Trace/TraceModuleFactory.cs +++ b/src/Nethermind/Nethermind.JsonRpc/Modules/Trace/TraceModuleFactory.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; - using Nethermind.Blockchain; using Nethermind.Blockchain.Receipts; using Nethermind.Consensus; @@ -17,56 +16,32 @@ using Nethermind.State; using Nethermind.Trie.Pruning; -namespace Nethermind.JsonRpc.Modules.Trace -{ - public class TraceModuleFactory : ModuleFactoryBase - { - private readonly IWorldStateManager _worldStateManager; - private readonly IReadOnlyBlockTree _blockTree; - private readonly IJsonRpcConfig _jsonRpcConfig; - private readonly IReceiptStorage _receiptStorage; - private readonly ISpecProvider _specProvider; - private readonly ILogManager _logManager; - private readonly IBlockPreprocessorStep _recoveryStep; - private readonly IRewardCalculatorSource _rewardCalculatorSource; - private readonly IPoSSwitcher _poSSwitcher; - - public TraceModuleFactory( - IWorldStateManager worldStateManager, - IBlockTree blockTree, - IJsonRpcConfig jsonRpcConfig, - IBlockPreprocessorStep recoveryStep, - IRewardCalculatorSource rewardCalculatorSource, - IReceiptStorage receiptFinder, - ISpecProvider specProvider, - IPoSSwitcher poSSwitcher, - ILogManager logManager) - { - _worldStateManager = worldStateManager; - _blockTree = blockTree.AsReadOnly(); - _jsonRpcConfig = jsonRpcConfig ?? throw new ArgumentNullException(nameof(jsonRpcConfig)); - _recoveryStep = recoveryStep ?? throw new ArgumentNullException(nameof(recoveryStep)); - _rewardCalculatorSource = rewardCalculatorSource ?? throw new ArgumentNullException(nameof(rewardCalculatorSource)); - _receiptStorage = receiptFinder ?? throw new ArgumentNullException(nameof(receiptFinder)); - _specProvider = specProvider ?? throw new ArgumentNullException(nameof(specProvider)); - _poSSwitcher = poSSwitcher ?? throw new ArgumentNullException(nameof(poSSwitcher)); - _logManager = logManager ?? throw new ArgumentNullException(nameof(logManager)); - logManager.GetClassLogger(); - } - - public override ITraceRpcModule Create() - { - ReadOnlyTxProcessingEnv txProcessingEnv = - new(_worldStateManager, _blockTree, _specProvider, _logManager); +namespace Nethermind.JsonRpc.Modules.Trace; - IRewardCalculator rewardCalculator = - new MergeRpcRewardCalculator(_rewardCalculatorSource.Get(txProcessingEnv.TransactionProcessor), - _poSSwitcher); +public class TraceModuleFactory( + IWorldStateManager worldStateManager, + IBlockTree blockTree, + IJsonRpcConfig jsonRpcConfig, + IBlockPreprocessorStep recoveryStep, + IRewardCalculatorSource rewardCalculatorSource, + IReceiptStorage receiptFinder, + ISpecProvider specProvider, + IPoSSwitcher poSSwitcher, + ILogManager logManager) : ModuleFactoryBase +{ + protected readonly IWorldStateManager _worldStateManager = worldStateManager; + protected readonly IReadOnlyBlockTree _blockTree = blockTree.AsReadOnly(); + protected readonly IJsonRpcConfig _jsonRpcConfig = jsonRpcConfig ?? throw new ArgumentNullException(nameof(jsonRpcConfig)); + protected readonly IReceiptStorage _receiptStorage = receiptFinder ?? throw new ArgumentNullException(nameof(receiptFinder)); + protected readonly ISpecProvider _specProvider = specProvider ?? throw new ArgumentNullException(nameof(specProvider)); + protected readonly ILogManager _logManager = logManager ?? throw new ArgumentNullException(nameof(logManager)); + protected readonly IBlockPreprocessorStep _recoveryStep = recoveryStep ?? throw new ArgumentNullException(nameof(recoveryStep)); + protected readonly IRewardCalculatorSource _rewardCalculatorSource = rewardCalculatorSource ?? throw new ArgumentNullException(nameof(rewardCalculatorSource)); + protected readonly IPoSSwitcher _poSSwitcher = poSSwitcher ?? throw new ArgumentNullException(nameof(poSSwitcher)); - RpcBlockTransactionsExecutor rpcBlockTransactionsExecutor = new(txProcessingEnv.TransactionProcessor, txProcessingEnv.StateProvider); - BlockProcessor.BlockValidationTransactionsExecutor executeBlockTransactionsExecutor = new(txProcessingEnv.TransactionProcessor, txProcessingEnv.StateProvider); + protected virtual ReadOnlyTxProcessingEnv CreateTxProcessingEnv() => new(_worldStateManager, _blockTree, _specProvider, _logManager); - ReadOnlyChainProcessingEnv CreateChainProcessingEnv(IBlockProcessor.IBlockTransactionsExecutor transactionsExecutor) => new( + protected virtual ReadOnlyChainProcessingEnv CreateChainProcessingEnv(IBlockProcessor.IBlockTransactionsExecutor transactionsExecutor, ReadOnlyTxProcessingEnv txProcessingEnv, IRewardCalculator rewardCalculator) => new( txProcessingEnv, Always.Valid, _recoveryStep, @@ -76,12 +51,23 @@ public override ITraceRpcModule Create() _logManager, transactionsExecutor); - ReadOnlyChainProcessingEnv traceProcessingEnv = CreateChainProcessingEnv(rpcBlockTransactionsExecutor); - ReadOnlyChainProcessingEnv executeProcessingEnv = CreateChainProcessingEnv(executeBlockTransactionsExecutor); + public override ITraceRpcModule Create() + { + ReadOnlyTxProcessingEnv txProcessingEnv = CreateTxProcessingEnv(); + + IRewardCalculator rewardCalculator = + new MergeRpcRewardCalculator(_rewardCalculatorSource.Get(txProcessingEnv.TransactionProcessor), + _poSSwitcher); + + RpcBlockTransactionsExecutor rpcBlockTransactionsExecutor = new(txProcessingEnv.TransactionProcessor, txProcessingEnv.StateProvider); + BlockProcessor.BlockValidationTransactionsExecutor executeBlockTransactionsExecutor = new(txProcessingEnv.TransactionProcessor, txProcessingEnv.StateProvider); - Tracer tracer = new(txProcessingEnv.StateProvider, traceProcessingEnv.ChainProcessor, executeProcessingEnv.ChainProcessor); + ReadOnlyChainProcessingEnv traceProcessingEnv = CreateChainProcessingEnv(rpcBlockTransactionsExecutor, txProcessingEnv, rewardCalculator); + ReadOnlyChainProcessingEnv executeProcessingEnv = CreateChainProcessingEnv(executeBlockTransactionsExecutor, txProcessingEnv, rewardCalculator); - return new TraceRpcModule(_receiptStorage, tracer, _blockTree, _jsonRpcConfig, _specProvider, _logManager, txProcessingEnv.StateReader); - } + Tracer tracer = new(txProcessingEnv.StateProvider, traceProcessingEnv.ChainProcessor, executeProcessingEnv.ChainProcessor); + + return new TraceRpcModule(_receiptStorage, tracer, _blockTree, _jsonRpcConfig, txProcessingEnv.StateReader); } + } diff --git a/src/Nethermind/Nethermind.JsonRpc/Modules/Trace/TraceRpcModule.cs b/src/Nethermind/Nethermind.JsonRpc/Modules/Trace/TraceRpcModule.cs index 903fb1b1bfc7..dce79316b4d2 100644 --- a/src/Nethermind/Nethermind.JsonRpc/Modules/Trace/TraceRpcModule.cs +++ b/src/Nethermind/Nethermind.JsonRpc/Modules/Trace/TraceRpcModule.cs @@ -39,24 +39,19 @@ public class TraceRpcModule : ITraceRpcModule private readonly IBlockFinder _blockFinder; private readonly TxDecoder _txDecoder = new(); private readonly IJsonRpcConfig _jsonRpcConfig; - private readonly ILogManager _logManager; - private readonly ILogger _logger; - private readonly ISpecProvider _specProvider; private readonly TimeSpan _cancellationTokenTimeout; private readonly IStateReader _stateReader; - public TraceRpcModule(IReceiptFinder? receiptFinder, ITracer? tracer, IBlockFinder? blockFinder, IJsonRpcConfig? jsonRpcConfig, ISpecProvider? specProvider, ILogManager? logManager, IStateReader stateReader) + public TraceRpcModule(IReceiptFinder? receiptFinder, ITracer? tracer, IBlockFinder? blockFinder, IJsonRpcConfig? jsonRpcConfig, IStateReader stateReader) { _receiptFinder = receiptFinder ?? throw new ArgumentNullException(nameof(receiptFinder)); _tracer = tracer ?? throw new ArgumentNullException(nameof(tracer)); _blockFinder = blockFinder ?? throw new ArgumentNullException(nameof(blockFinder)); _jsonRpcConfig = jsonRpcConfig ?? throw new ArgumentNullException(nameof(jsonRpcConfig)); - _specProvider = specProvider ?? throw new ArgumentNullException(nameof(specProvider)); - _logManager = logManager ?? throw new ArgumentNullException(nameof(logManager)); _stateReader = stateReader ?? throw new ArgumentNullException(nameof(stateReader)); - _logger = logManager.GetClassLogger(); _cancellationTokenTimeout = TimeSpan.FromMilliseconds(_jsonRpcConfig.Timeout); } + public static ParityTraceTypes GetParityTypes(string[] types) => types.Select(s => FastEnum.Parse(s, true)).Aggregate((t1, t2) => t1 | t2); diff --git a/src/Nethermind/Nethermind.JsonRpc/WebSockets/JsonRpcSocketsClient.cs b/src/Nethermind/Nethermind.JsonRpc/WebSockets/JsonRpcSocketsClient.cs index 1ea4d983058c..1176e351741b 100644 --- a/src/Nethermind/Nethermind.JsonRpc/WebSockets/JsonRpcSocketsClient.cs +++ b/src/Nethermind/Nethermind.JsonRpc/WebSockets/JsonRpcSocketsClient.cs @@ -48,6 +48,7 @@ public override void Dispose() { base.Dispose(); _sendSemaphore.Dispose(); + _jsonRpcContext.Dispose(); Closed?.Invoke(this, EventArgs.Empty); } diff --git a/src/Nethermind/Nethermind.Merge.Plugin/Handlers/ForkchoiceUpdatedHandler.cs b/src/Nethermind/Nethermind.Merge.Plugin/Handlers/ForkchoiceUpdatedHandler.cs index 5616295fe52b..bb31db180c17 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin/Handlers/ForkchoiceUpdatedHandler.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin/Handlers/ForkchoiceUpdatedHandler.cs @@ -98,7 +98,11 @@ public async Task> Handle(ForkchoiceSta private async Task?> ApplyForkchoiceUpdate(Block? newHeadBlock, ForkchoiceStateV1 forkchoiceState, PayloadAttributes? payloadAttributes) { - using ThreadExtensions.Disposable handle = Thread.CurrentThread.BoostPriority(); + // if a head is unknown we are syncing + bool isDefinitelySyncing = newHeadBlock is null; + using ThreadExtensions.Disposable handle = isDefinitelySyncing ? + default : // Don't boost priority if we are definitely syncing + Thread.CurrentThread.BoostPriority(); if (_invalidChainTracker.IsOnKnownInvalidChain(forkchoiceState.HeadBlockHash, out Hash256? lastValidHash)) { @@ -106,7 +110,7 @@ public async Task> Handle(ForkchoiceSta return ForkchoiceUpdatedV1Result.Invalid(lastValidHash); } - if (newHeadBlock is null) // if a head is unknown we are syncing + if (isDefinitelySyncing) { string simpleRequestStr = payloadAttributes is null ? forkchoiceState.ToString() : $"{forkchoiceState} {payloadAttributes}"; if (_logger.IsInfo) _logger.Info($"Received {simpleRequestStr}"); @@ -134,7 +138,7 @@ public async Task> Handle(ForkchoiceSta return ForkchoiceUpdatedV1Result.Syncing; } - BlockInfo? blockInfo = _blockTree.GetInfo(newHeadBlock.Number, newHeadBlock.GetOrCalculateHash()).Info; + BlockInfo? blockInfo = _blockTree.GetInfo(newHeadBlock!.Number, newHeadBlock.GetOrCalculateHash()).Info; BlockHeader? safeBlockHeader = ValidateBlockHash(forkchoiceState.SafeBlockHash, out string? safeBlockErrorMsg); BlockHeader? finalizedHeader = ValidateBlockHash(forkchoiceState.FinalizedBlockHash, out string? finalizationErrorMsg); string requestStr = payloadAttributes is null diff --git a/src/Nethermind/Nethermind.Optimism.Test/GasCostTests.cs b/src/Nethermind/Nethermind.Optimism.Test/GasCostTests.cs new file mode 100644 index 000000000000..677bebec6b88 --- /dev/null +++ b/src/Nethermind/Nethermind.Optimism.Test/GasCostTests.cs @@ -0,0 +1,37 @@ +// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using System.Collections; +using Nethermind.Int256; +using NUnit.Framework; + +namespace Nethermind.Optimism.Test; + +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); + + public static IEnumerable FjordL1CostCalculationTestCases + { + get + { + static TestCaseData MakeTestCase(string testCase, ulong result, ulong fastLzSize, ulong l1BaseFee, ulong blobBaseFee, ulong l1BaseFeeScalar, ulong l1BlobBaseFeeScalar) + { + return new TestCaseData(new UInt256(fastLzSize), new UInt256(l1BaseFee), new UInt256(blobBaseFee), new UInt256(l1BaseFeeScalar), new UInt256(l1BlobBaseFeeScalar)) + { + ExpectedResult = new UInt256(result), + TestName = testCase + }; + } + + yield return MakeTestCase("Low compressed size", 3203000, 50, 1000000000, 10000000, 2, 3); + yield return MakeTestCase("Below minimal #1", 3203000, 150, 1000000000, 10000000, 2, 3); + yield return MakeTestCase("Below minimal #2", 3203000, 170, 1000000000, 10000000, 2, 3); + yield return MakeTestCase("Above minimal #1", 3217602, 171, 1000000000, 10000000, 2, 3); + yield return MakeTestCase("Above minimal #2", 3994602, 200, 1000000000, 10000000, 2, 3); + yield return MakeTestCase("Regular block #1", 2883950646753, 1044, 28549556977, 1, 7600, 862000); + } + } +} diff --git a/src/Nethermind/Nethermind.Optimism.Test/ReceiptDecoderTests.cs b/src/Nethermind/Nethermind.Optimism.Test/ReceiptDecoderTests.cs index b5c27431a2d8..37e1a5e4df79 100644 --- a/src/Nethermind/Nethermind.Optimism.Test/ReceiptDecoderTests.cs +++ b/src/Nethermind/Nethermind.Optimism.Test/ReceiptDecoderTests.cs @@ -8,7 +8,7 @@ namespace Nethermind.Optimism.Test; -public partial class ReceiptDecoderTests +public class ReceiptDecoderTests { [TestCaseSource(nameof(DepositTxReceiptsSerializationTestCases))] public void Test_tx_network_form_receipts_properly_encoded_for_trie(byte[] rlp, bool includesNonce, bool includesVersion, bool shouldIncludeNonceAndVersionForTxTrie) diff --git a/src/Nethermind/Nethermind.Optimism/Create2DeployerContractRewriter.cs b/src/Nethermind/Nethermind.Optimism/Create2DeployerContractRewriter.cs index 3510481d6a2d..fc7a1714d5a6 100644 --- a/src/Nethermind/Nethermind.Optimism/Create2DeployerContractRewriter.cs +++ b/src/Nethermind/Nethermind.Optimism/Create2DeployerContractRewriter.cs @@ -11,13 +11,13 @@ namespace Nethermind.Optimism; public class Create2DeployerContractRewriter { - private readonly IOPConfigHelper _opConfigHelper; + private readonly IOptimismSpecHelper _opSpecHelper; private readonly ISpecProvider _specProvider; private readonly IBlockTree _blockTree; - public Create2DeployerContractRewriter(IOPConfigHelper opConfigHelper, ISpecProvider specProvider, IBlockTree blockTree) + public Create2DeployerContractRewriter(IOptimismSpecHelper opSpecHelper, ISpecProvider specProvider, IBlockTree blockTree) { - _opConfigHelper = opConfigHelper; + _opSpecHelper = opSpecHelper; _specProvider = specProvider; _blockTree = blockTree; } @@ -26,9 +26,9 @@ public void RewriteContract(BlockHeader header, IWorldState worldState) { IReleaseSpec spec = _specProvider.GetSpec(header); BlockHeader? parent = _blockTree.FindParent(header, BlockTreeLookupOptions.None)?.Header; - if ((parent is null || !_opConfigHelper.IsCanyon(parent)) && _opConfigHelper.IsCanyon(header)) + if ((parent is null || !_opSpecHelper.IsCanyon(parent)) && _opSpecHelper.IsCanyon(header)) { - worldState.InsertCode(_opConfigHelper.Create2DeployerAddress!, _opConfigHelper.Create2DeployerCode, spec); + worldState.InsertCode(_opSpecHelper.Create2DeployerAddress!, _opSpecHelper.Create2DeployerCode, spec); } } } diff --git a/src/Nethermind/Nethermind.Optimism/DepositTxExtensions.cs b/src/Nethermind/Nethermind.Optimism/DepositTxExtensions.cs index 2130699aadaa..5c908bb730d1 100644 --- a/src/Nethermind/Nethermind.Optimism/DepositTxExtensions.cs +++ b/src/Nethermind/Nethermind.Optimism/DepositTxExtensions.cs @@ -7,7 +7,6 @@ namespace Nethermind.Optimism; public static class DepositTxExtensions { - public static bool IsDeposit(this Transaction tx) { return tx.Type == TxType.DepositTx; diff --git a/src/Nethermind/Nethermind.Optimism/IOPConfigHelper.cs b/src/Nethermind/Nethermind.Optimism/IOptimismSpecHelper.cs similarity index 85% rename from src/Nethermind/Nethermind.Optimism/IOPConfigHelper.cs rename to src/Nethermind/Nethermind.Optimism/IOptimismSpecHelper.cs index 4320ef70bfc9..5874e01fa869 100644 --- a/src/Nethermind/Nethermind.Optimism/IOPConfigHelper.cs +++ b/src/Nethermind/Nethermind.Optimism/IOptimismSpecHelper.cs @@ -5,7 +5,7 @@ namespace Nethermind.Optimism; -public interface IOPConfigHelper +public interface IOptimismSpecHelper { Address L1FeeReceiver { get; } @@ -13,6 +13,7 @@ public interface IOPConfigHelper bool IsRegolith(BlockHeader header); bool IsCanyon(BlockHeader header); bool IsEcotone(BlockHeader header); + bool IsFjord(BlockHeader header); Address? Create2DeployerAddress { get; } byte[]? Create2DeployerCode { get; } } diff --git a/src/Nethermind/Nethermind.Optimism/InitializeBlockProducerOptimism.cs b/src/Nethermind/Nethermind.Optimism/InitializeBlockProducerOptimism.cs index 2c2b0d404ad9..06111a6445e5 100644 --- a/src/Nethermind/Nethermind.Optimism/InitializeBlockProducerOptimism.cs +++ b/src/Nethermind/Nethermind.Optimism/InitializeBlockProducerOptimism.cs @@ -34,7 +34,6 @@ protected override IBlockProducer BuildProducer() _api.BlockProducerEnvFactory = new OptimismBlockProducerEnvFactory( _api.WorldStateManager, - _api.ChainSpec, _api.BlockTree, _api.SpecProvider, _api.BlockValidator, diff --git a/src/Nethermind/Nethermind.Optimism/InitializeBlockchainOptimism.cs b/src/Nethermind/Nethermind.Optimism/InitializeBlockchainOptimism.cs index 93cf3e46194a..edf205a9767e 100644 --- a/src/Nethermind/Nethermind.Optimism/InitializeBlockchainOptimism.cs +++ b/src/Nethermind/Nethermind.Optimism/InitializeBlockchainOptimism.cs @@ -6,9 +6,11 @@ using Nethermind.Blockchain.Blocks; using Nethermind.Blockchain.Services; using Nethermind.Config; +using Nethermind.Consensus.AuRa.Withdrawals; using Nethermind.Consensus.Processing; using Nethermind.Consensus.Producers; using Nethermind.Consensus.Validators; +using Nethermind.Consensus.Withdrawals; using Nethermind.Evm; using Nethermind.Evm.TransactionProcessing; using Nethermind.Init.Steps; @@ -40,6 +42,7 @@ protected override ITransactionProcessor CreateTransactionProcessor() if (_api.SpecProvider is null) throw new StepDependencyException(nameof(_api.SpecProvider)); if (_api.SpecHelper is null) throw new StepDependencyException(nameof(_api.SpecHelper)); if (_api.L1CostHelper is null) throw new StepDependencyException(nameof(_api.L1CostHelper)); + if (_api.WorldState is null) throw new StepDependencyException(nameof(_api.WorldState)); VirtualMachine virtualMachine = CreateVirtualMachine(); @@ -105,7 +108,8 @@ protected override BlockProcessor CreateBlockProcessor() new BlockhashStore(_api.BlockTree, _api.SpecProvider, _api.WorldState), _api.LogManager, _api.SpecHelper, - contractRewriter); + contractRewriter, + new BlockProductionWithdrawalProcessor(new NullWithdrawalProcessor())); } protected override IUnclesValidator CreateUnclesValidator() => Always.Valid; diff --git a/src/Nethermind/Nethermind.Optimism/L1BlockGasInfo.cs b/src/Nethermind/Nethermind.Optimism/L1BlockGasInfo.cs index 3c43f7ac7c37..e27a2f6efafa 100644 --- a/src/Nethermind/Nethermind.Optimism/L1BlockGasInfo.cs +++ b/src/Nethermind/Nethermind.Optimism/L1BlockGasInfo.cs @@ -26,14 +26,16 @@ public readonly struct L1BlockGasInfo 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 static readonly byte[] EcotoneL1AttributesSelector = [0x44, 0x0a, 0x5e, 0x20]; + private static readonly byte[] BedrockL1AttributesSelector = [0x01, 0x5d, 0x8e, 0xb9]; + private readonly IOptimismSpecHelper _specHelper; - public L1BlockGasInfo(Block block, bool isRegolith) + public L1BlockGasInfo(Block block, IOptimismSpecHelper specHelper) { - _isRegolith = isRegolith; + _specHelper = specHelper; if (block is not null && block.Transactions.Length > 0) { @@ -45,7 +47,9 @@ public L1BlockGasInfo(Block block, bool isRegolith) Memory data = depositTx.Data.Value; - if (_isEcotone = data[0..4].Span.SequenceEqual(EcotoneL1AttributesSelector)) + _isFjord = _specHelper.IsFjord(block.Header); + + if (_isFjord || (_isEcotone = (_specHelper.IsEcotone(block.Header) && !data[0..4].Span.SequenceEqual(BedrockL1AttributesSelector)))) { if (data.Length != 164) { @@ -59,6 +63,7 @@ public L1BlockGasInfo(Block block, bool isRegolith) } else { + _isRegolith = true; if (data.Length < 4 + 32 * 8) { return; @@ -80,7 +85,12 @@ public readonly L1TxGasInfo GetTxGasInfo(Transaction tx) if (_l1GasPrice is not null) { - if (_isEcotone) + if (_isFjord) + { + UInt256 fastLzSize = OPL1CostHelper.ComputeFlzCompressLen(tx); + l1Fee = OPL1CostHelper.ComputeL1CostFjord(fastLzSize, _l1GasPrice.Value, _l1BlobBaseFee, _l1BaseFeeScalar, _l1BlobBaseFeeScalar); + } + else if (_isEcotone) { l1GasUsed = OPL1CostHelper.ComputeDataGas(tx, _isRegolith); l1Fee = OPL1CostHelper.ComputeL1CostEcotone(l1GasUsed.Value, _l1GasPrice.Value, _l1BlobBaseFee, _l1BaseFeeScalar, _l1BlobBaseFeeScalar); diff --git a/src/Nethermind/Nethermind.Optimism/OPConfigHelper.cs b/src/Nethermind/Nethermind.Optimism/OPConfigHelper.cs index 57549e96fbe7..c404456c8aa8 100644 --- a/src/Nethermind/Nethermind.Optimism/OPConfigHelper.cs +++ b/src/Nethermind/Nethermind.Optimism/OPConfigHelper.cs @@ -6,26 +6,15 @@ namespace Nethermind.Optimism; -public class OPSpecHelper : IOPConfigHelper +public class OptimismSpecHelper(OptimismParameters parameters) : IOptimismSpecHelper { - private readonly ulong _regolithTimestamp; - private readonly long _bedrockBlockNumber; - private readonly ulong? _canyonTimestamp; - private readonly ulong? _ecotoneTimestamp; + private readonly long _bedrockBlockNumber = parameters.BedrockBlockNumber; + private readonly ulong _regolithTimestamp = parameters.RegolithTimestamp; + private readonly ulong? _canyonTimestamp = parameters.CanyonTimestamp; + private readonly ulong? _ecotoneTimestamp = parameters.EcotoneTimestamp; + private readonly ulong? _fjordTimestamp = parameters.FjordTimestamp; - public Address L1FeeReceiver { get; init; } - - public OPSpecHelper(OptimismParameters parameters) - { - _regolithTimestamp = parameters.RegolithTimestamp; - _bedrockBlockNumber = parameters.BedrockBlockNumber; - _canyonTimestamp = parameters.CanyonTimestamp; - _ecotoneTimestamp = parameters.EcotoneTimestamp; - - L1FeeReceiver = parameters.L1FeeRecipient; - Create2DeployerCode = parameters.Create2DeployerCode; - Create2DeployerAddress = parameters.Create2DeployerAddress; - } + public Address L1FeeReceiver { get; init; } = parameters.L1FeeRecipient; public bool IsRegolith(BlockHeader header) { @@ -47,6 +36,11 @@ public bool IsEcotone(BlockHeader header) return header.Timestamp >= _ecotoneTimestamp; } - public Address? Create2DeployerAddress { get; } - public byte[]? Create2DeployerCode { get; } + public bool IsFjord(BlockHeader header) + { + return header.Timestamp >= _fjordTimestamp; + } + + public Address? Create2DeployerAddress { get; } = parameters.Create2DeployerAddress; + public byte[]? Create2DeployerCode { get; } = parameters.Create2DeployerCode; } diff --git a/src/Nethermind/Nethermind.Optimism/OPL1CostHelper.cs b/src/Nethermind/Nethermind.Optimism/OPL1CostHelper.cs index f6f150e83d27..ef26b270c493 100644 --- a/src/Nethermind/Nethermind.Optimism/OPL1CostHelper.cs +++ b/src/Nethermind/Nethermind.Optimism/OPL1CostHelper.cs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LGPL-3.0-only using System; +using System.Buffers; using System.Linq; using System.Runtime.CompilerServices; using Nethermind.Core; @@ -12,22 +13,30 @@ namespace Nethermind.Optimism; -public class OPL1CostHelper(IOPConfigHelper opConfigHelper, Address l1BlockAddr) : IL1CostHelper +public class OPL1CostHelper(IOptimismSpecHelper opSpecHelper, Address l1BlockAddr) : IL1CostHelper { - private readonly IOPConfigHelper _opConfigHelper = opConfigHelper; + private readonly IOptimismSpecHelper _opSpecHelper = opSpecHelper; private readonly StorageCell _l1BaseFeeSlot = new(l1BlockAddr, new UInt256(1)); private readonly StorageCell _overheadSlot = new(l1BlockAddr, new UInt256(5)); private readonly StorageCell _scalarSlot = new(l1BlockAddr, new UInt256(6)); - private static readonly UInt256 basicDevider = 1_000_000; + private static readonly UInt256 BasicDivisor = 1_000_000; // Ecotone private readonly StorageCell _blobBaseFeeSlot = new(l1BlockAddr, new UInt256(7)); private readonly StorageCell _baseFeeScalarSlot = new(l1BlockAddr, new UInt256(3)); - private static readonly UInt256 precisionMultiplier = 16; - private static readonly UInt256 precisionDevider = precisionMultiplier * basicDevider; + private static readonly UInt256 PrecisionMultiplier = 16; + private static readonly UInt256 PrecisionDivisor = PrecisionMultiplier * BasicDivisor; + + + // Fjord + private static readonly UInt256 L1CostInterceptNeg = 42_585_600; + private static readonly UInt256 L1CostFastlzCoef = 836_500; + + private static readonly UInt256 MinTransactionSizeScaled = 100 * 1_000_000; + private static readonly UInt256 FjordDivisor = 1_000_000_000_000; [SkipLocalsInit] public UInt256 ComputeL1Cost(Transaction tx, BlockHeader header, IWorldState worldState) @@ -35,15 +44,34 @@ public UInt256 ComputeL1Cost(Transaction tx, BlockHeader header, IWorldState wor if (tx.IsDeposit()) return UInt256.Zero; - UInt256 dataGas = ComputeDataGas(tx, _opConfigHelper.IsRegolith(header)); + UInt256 l1BaseFee = new(worldState.Get(_l1BaseFeeSlot), true); + + if (_opSpecHelper.IsFjord(header)) + { + UInt256 blobBaseFee = new(worldState.Get(_blobBaseFeeSlot), true); + + ReadOnlySpan scalarData = worldState.Get(_baseFeeScalarSlot); + + const int baseFeeFieldsStart = 16; + const int fieldSize = sizeof(uint); + + int l1BaseFeeScalarStart = scalarData.Length > baseFeeFieldsStart ? scalarData.Length - baseFeeFieldsStart : 0; + int l1BaseFeeScalarEnd = l1BaseFeeScalarStart + (scalarData.Length >= baseFeeFieldsStart ? fieldSize : fieldSize - baseFeeFieldsStart + scalarData.Length); + UInt256 l1BaseFeeScalar = new(scalarData[l1BaseFeeScalarStart..l1BaseFeeScalarEnd], true); + UInt256 l1BlobBaseFeeScalar = new(scalarData[l1BaseFeeScalarEnd..(l1BaseFeeScalarEnd + fieldSize)], true); + + uint fastLzSize = ComputeFlzCompressLen(tx); + + return ComputeL1CostFjord(fastLzSize, l1BaseFee, blobBaseFee, l1BaseFeeScalar, l1BlobBaseFeeScalar); + } + + UInt256 dataGas = ComputeDataGas(tx, _opSpecHelper.IsRegolith(header)); + if (dataGas.IsZero) return UInt256.Zero; - UInt256 l1BaseFee = new(worldState.Get(_l1BaseFeeSlot), true); - - if (_opConfigHelper.IsEcotone(header)) + if (_opSpecHelper.IsEcotone(header)) { - // Ecotone formula: (dataGas) * (16 * l1BaseFee * l1BaseFeeScalar + l1BlobBaseFee*l1BlobBaseFeeScalar) / 16e6 UInt256 blobBaseFee = new(worldState.Get(_blobBaseFeeSlot), true); ReadOnlySpan scalarData = worldState.Get(_baseFeeScalarSlot); @@ -60,7 +88,6 @@ public UInt256 ComputeL1Cost(Transaction tx, BlockHeader header, IWorldState wor } else { - // Pre-Ecotone formula: (dataGas + overhead) * l1BaseFee * scalar / 1e6 UInt256 overhead = new(worldState.Get(_overheadSlot), true); UInt256 feeScalar = new(worldState.Get(_scalarSlot), true); @@ -81,13 +108,146 @@ public static UInt256 ComputeDataGas(Transaction tx, bool isRegolith) return (ulong)(zeroCount * GasCostOf.TxDataZero + nonZeroCount * GasCostOf.TxDataNonZeroEip2028); } + // Fjord L1 formula: + // 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) + { + UInt256 l1FeeScaled = l1BaseFeeScalar * l1BaseFee * PrecisionMultiplier + l1BlobBaseFeeScalar * blobBaseFee; + UInt256 fastLzCost = L1CostFastlzCoef * fastLzSize; + + if (fastLzCost < L1CostInterceptNeg) + { + fastLzCost = 0; + } + else + { + fastLzCost -= L1CostInterceptNeg; + } + + var estimatedSize = UInt256.Max(MinTransactionSizeScaled, fastLzCost); + return estimatedSize * l1FeeScaled / FjordDivisor; + } + + // Ecotone formula: (dataGas) * (16 * l1BaseFee * l1BaseFeeScalar + l1BlobBaseFee*l1BlobBaseFeeScalar) / 16e6 public static UInt256 ComputeL1CostEcotone(UInt256 dataGas, UInt256 l1BaseFee, UInt256 blobBaseFee, UInt256 l1BaseFeeScalar, UInt256 l1BlobBaseFeeScalar) { - return dataGas * (precisionMultiplier * l1BaseFee * l1BaseFeeScalar + blobBaseFee * l1BlobBaseFeeScalar) / precisionDevider; + return dataGas * (PrecisionMultiplier * l1BaseFee * l1BaseFeeScalar + blobBaseFee * l1BlobBaseFeeScalar) / PrecisionDivisor; } + // Pre-Ecotone formula: (dataGas + overhead) * l1BaseFee * scalar / 1e6 public static UInt256 ComputeL1CostPreEcotone(UInt256 dataGasWithOverhead, UInt256 l1BaseFee, UInt256 feeScalar) { - return dataGasWithOverhead * l1BaseFee * feeScalar / basicDevider; + return dataGasWithOverhead * l1BaseFee * feeScalar / BasicDivisor; + } + + // Based on: + // https://github.com/ethereum-optimism/op-geth/blob/7c2819836018bfe0ca07c4e4955754834ffad4e0/core/types/rollup_cost.go + // https://github.com/Vectorized/solady/blob/5315d937d79b335c668896d7533ac603adac5315/js/solady.js + [SkipLocalsInit] + public static uint ComputeFlzCompressLen(Transaction tx) + { + byte[] encoded = Rlp.Encode(tx, RlpBehaviors.SkipTypedWrapping).Bytes; + + [SkipLocalsInit] + static uint FlzCompressLen(byte[] data) + { + uint n = 0; + uint[] ht = ArrayPool.Shared.Rent(8192); + try + { + uint u24(uint i) => data[i] | ((uint)data[i + 1] << 8) | ((uint)data[i + 2] << 16); + uint cmp(uint p, uint q, uint e) + { + uint l = 0; + for (e -= q; l < e; l++) + { + if (data[p + (int)l] != data[q + (int)l]) + { + e = 0; + } + } + return l; + } + void literals(uint r) + { + n += 0x21 * (r / 0x20); + r %= 0x20; + if (r != 0) + { + n += r + 1; + } + } + void match(uint l) + { + l--; + n += 3 * (l / 262); + if (l % 262 >= 6) + { + n += 3; + } + else + { + n += 2; + } + } + uint hash(uint v) => ((2654435769 * v) >> 19) & 0x1fff; + uint setNextHash(uint ip) + { + ht[hash(u24(ip))] = ip; + return ip + 1; + } + uint a = 0; + uint ipLimit = (uint)data.Length - 13; + if (data.Length < 13) + { + ipLimit = 0; + } + for (uint ip = a + 2; ip < ipLimit;) + { + uint d; + uint r; + for (; ; ) + { + uint s = u24(ip); + uint h = hash(s); + r = ht[h]; + ht[h] = ip; + d = ip - r; + if (ip >= ipLimit) + { + break; + } + ip++; + if (d <= 0x1fff && s == u24(r)) + { + break; + } + } + if (ip >= ipLimit) + { + break; + } + ip--; + if (ip > a) + { + literals(ip - a); + } + uint l = cmp(r + 3, ip + 3, ipLimit + 9); + match(l); + ip = setNextHash(setNextHash(ip + l)); + a = ip; + } + literals((uint)data.Length - a); + return n; + } + finally + { + ArrayPool.Shared.Return(ht); + } + } + + return FlzCompressLen(encoded); } } diff --git a/src/Nethermind/Nethermind.Optimism/OptimismBlockProcessor.cs b/src/Nethermind/Nethermind.Optimism/OptimismBlockProcessor.cs index e06cc3783600..854f5b1491be 100644 --- a/src/Nethermind/Nethermind.Optimism/OptimismBlockProcessor.cs +++ b/src/Nethermind/Nethermind.Optimism/OptimismBlockProcessor.cs @@ -29,7 +29,7 @@ public OptimismBlockProcessor( IReceiptStorage? receiptStorage, IBlockhashStore? blockhashStore, ILogManager? logManager, - IOPConfigHelper opConfigHelper, + IOptimismSpecHelper opSpecHelper, Create2DeployerContractRewriter contractRewriter, IWithdrawalProcessor? withdrawalProcessor = null) : base(specProvider, blockValidator, rewardCalculator, blockTransactionsExecutor, @@ -37,7 +37,7 @@ public OptimismBlockProcessor( { ArgumentNullException.ThrowIfNull(stateProvider); _contractRewriter = contractRewriter; - ReceiptsTracer = new OptimismBlockReceiptTracer(opConfigHelper, stateProvider); + ReceiptsTracer = new OptimismBlockReceiptTracer(opSpecHelper, stateProvider); } protected override TxReceipt[] ProcessBlock(Block block, IBlockTracer blockTracer, ProcessingOptions options) diff --git a/src/Nethermind/Nethermind.Optimism/OptimismBlockProducerEnvFactory.cs b/src/Nethermind/Nethermind.Optimism/OptimismBlockProducerEnvFactory.cs index ade9f8fb8a8b..68581ebc710a 100644 --- a/src/Nethermind/Nethermind.Optimism/OptimismBlockProducerEnvFactory.cs +++ b/src/Nethermind/Nethermind.Optimism/OptimismBlockProducerEnvFactory.cs @@ -14,53 +14,40 @@ using Nethermind.Consensus.Withdrawals; using Nethermind.Core.Specs; using Nethermind.Logging; -using Nethermind.Specs.ChainSpecStyle; using Nethermind.State; using Nethermind.TxPool; namespace Nethermind.Optimism; -public class OptimismBlockProducerEnvFactory : BlockProducerEnvFactory +public class OptimismBlockProducerEnvFactory( + IWorldStateManager worldStateManager, + IBlockTree blockTree, + ISpecProvider specProvider, + IBlockValidator blockValidator, + IRewardCalculatorSource rewardCalculatorSource, + IReceiptStorage receiptStorage, + IBlockPreprocessorStep blockPreprocessorStep, + ITxPool txPool, + ITransactionComparerProvider transactionComparerProvider, + IBlocksConfig blocksConfig, + OptimismSpecHelper specHelper, + OPL1CostHelper l1CostHelper, + ILogManager logManager) : BlockProducerEnvFactory( + worldStateManager, + blockTree, + specProvider, + blockValidator, + rewardCalculatorSource, + receiptStorage, + blockPreprocessorStep, + txPool, + transactionComparerProvider, + blocksConfig, + logManager) { - private readonly ChainSpec _chainSpec; - private readonly OPSpecHelper _specHelper; - private readonly OPL1CostHelper _l1CostHelper; - - public OptimismBlockProducerEnvFactory( - IWorldStateManager worldStateManager, - ChainSpec chainSpec, - IBlockTree blockTree, - ISpecProvider specProvider, - IBlockValidator blockValidator, - IRewardCalculatorSource rewardCalculatorSource, - IReceiptStorage receiptStorage, - IBlockPreprocessorStep blockPreprocessorStep, - ITxPool txPool, - ITransactionComparerProvider transactionComparerProvider, - IBlocksConfig blocksConfig, - OPSpecHelper specHelper, - OPL1CostHelper l1CostHelper, - ILogManager logManager) : base(worldStateManager, - blockTree, specProvider, blockValidator, - rewardCalculatorSource, receiptStorage, blockPreprocessorStep, - txPool, transactionComparerProvider, blocksConfig, logManager) - { - _specHelper = specHelper; - _l1CostHelper = l1CostHelper; - _chainSpec = chainSpec; - TransactionsExecutorFactory = new OptimismTransactionsExecutorFactory(specProvider, logManager); - } - protected override ReadOnlyTxProcessingEnv CreateReadonlyTxProcessingEnv(IWorldStateManager worldStateManager, - ReadOnlyBlockTree readOnlyBlockTree) - { - ReadOnlyTxProcessingEnv result = new(worldStateManager, - readOnlyBlockTree, _specProvider, _logManager); - result.TransactionProcessor = - new OptimismTransactionProcessor(_specProvider, result.StateProvider, result.Machine, _logManager, _l1CostHelper, _specHelper); - - return result; - } + ReadOnlyBlockTree readOnlyBlockTree) => + new OptimismReadOnlyTxProcessingEnv(worldStateManager, readOnlyBlockTree, _specProvider, _logManager, l1CostHelper, specHelper); protected override ITxSource CreateTxSourceForProducer(ITxSource? additionalTxSource, ReadOnlyTxProcessingEnv processingEnv, @@ -90,8 +77,8 @@ protected override BlockProcessor CreateBlockProcessor( receiptStorage, new BlockhashStore(_blockTree, specProvider, readOnlyTxProcessingEnv.StateProvider), logManager, - _specHelper, - new Create2DeployerContractRewriter(_specHelper, _specProvider, _blockTree), + specHelper, + new Create2DeployerContractRewriter(specHelper, _specProvider, _blockTree), new BlockProductionWithdrawalProcessor(new WithdrawalProcessor(readOnlyTxProcessingEnv.StateProvider, logManager))); } } diff --git a/src/Nethermind/Nethermind.Optimism/OptimismBlockReceiptTracer.cs b/src/Nethermind/Nethermind.Optimism/OptimismBlockReceiptTracer.cs index 7f43df08c326..aab105b90906 100644 --- a/src/Nethermind/Nethermind.Optimism/OptimismBlockReceiptTracer.cs +++ b/src/Nethermind/Nethermind.Optimism/OptimismBlockReceiptTracer.cs @@ -11,12 +11,12 @@ namespace Nethermind.Optimism; public class OptimismBlockReceiptTracer : BlockReceiptsTracer { - private readonly IOPConfigHelper _opConfigHelper; + private readonly IOptimismSpecHelper _opSpecHelper; private readonly IWorldState _worldState; - public OptimismBlockReceiptTracer(IOPConfigHelper opConfigHelper, IWorldState worldState) + public OptimismBlockReceiptTracer(IOptimismSpecHelper opSpecHelper, IWorldState worldState) { - _opConfigHelper = opConfigHelper; + _opSpecHelper = opSpecHelper; _worldState = worldState; } @@ -35,7 +35,7 @@ public OptimismBlockReceiptTracer(IOPConfigHelper opConfigHelper, IWorldState wo { depositNonce--; } - if (_opConfigHelper.IsCanyon(header)) + if (_opSpecHelper.IsCanyon(header)) { version = 1; } diff --git a/src/Nethermind/Nethermind.Optimism/OptimismNethermindApi.cs b/src/Nethermind/Nethermind.Optimism/OptimismNethermindApi.cs index 9f39d63b1ff5..8e1e8f4002d2 100644 --- a/src/Nethermind/Nethermind.Optimism/OptimismNethermindApi.cs +++ b/src/Nethermind/Nethermind.Optimism/OptimismNethermindApi.cs @@ -22,5 +22,5 @@ public OptimismNethermindApi( public IInvalidChainTracker? InvalidChainTracker { get; set; } public OPL1CostHelper? L1CostHelper { get; set; } - public OPSpecHelper? SpecHelper { get; set; } + public OptimismSpecHelper? SpecHelper { get; set; } } diff --git a/src/Nethermind/Nethermind.Optimism/OptimismPayloadPreparationService.cs b/src/Nethermind/Nethermind.Optimism/OptimismPayloadPreparationService.cs index 71187bba01a0..35fd2e3abb29 100644 --- a/src/Nethermind/Nethermind.Optimism/OptimismPayloadPreparationService.cs +++ b/src/Nethermind/Nethermind.Optimism/OptimismPayloadPreparationService.cs @@ -8,6 +8,7 @@ using Nethermind.Int256; using Nethermind.Logging; using Nethermind.Merge.Plugin.BlockProduction; +using Nethermind.Optimism.Rpc; namespace Nethermind.Optimism; diff --git a/src/Nethermind/Nethermind.Optimism/OptimismPayloadTxSource.cs b/src/Nethermind/Nethermind.Optimism/OptimismPayloadTxSource.cs index 77f3c9ca35f4..53b23ea26951 100644 --- a/src/Nethermind/Nethermind.Optimism/OptimismPayloadTxSource.cs +++ b/src/Nethermind/Nethermind.Optimism/OptimismPayloadTxSource.cs @@ -6,6 +6,7 @@ using Nethermind.Consensus.Producers; using Nethermind.Consensus.Transactions; using Nethermind.Core; +using Nethermind.Optimism.Rpc; namespace Nethermind.Optimism; diff --git a/src/Nethermind/Nethermind.Optimism/OptimismPlugin.cs b/src/Nethermind/Nethermind.Optimism/OptimismPlugin.cs index ecf5388e5029..997d05beb7cd 100644 --- a/src/Nethermind/Nethermind.Optimism/OptimismPlugin.cs +++ b/src/Nethermind/Nethermind.Optimism/OptimismPlugin.cs @@ -26,6 +26,7 @@ using Nethermind.Serialization.Json; using Nethermind.Specs.ChainSpecStyle; using Nethermind.Serialization.Rlp; +using Nethermind.Optimism.Rpc; namespace Nethermind.Optimism; diff --git a/src/Nethermind/Nethermind.Optimism/OptimismPostMergeBlockProducer.cs b/src/Nethermind/Nethermind.Optimism/OptimismPostMergeBlockProducer.cs index 2f1e53c562bb..93df8a49f9c9 100644 --- a/src/Nethermind/Nethermind.Optimism/OptimismPostMergeBlockProducer.cs +++ b/src/Nethermind/Nethermind.Optimism/OptimismPostMergeBlockProducer.cs @@ -13,6 +13,7 @@ using Nethermind.Core.Specs; using Nethermind.Logging; using Nethermind.Merge.Plugin.BlockProduction; +using Nethermind.Optimism.Rpc; using Nethermind.State; namespace Nethermind.Optimism; diff --git a/src/Nethermind/Nethermind.Optimism/OptimismReadOnlyTxProcessingEnv.cs b/src/Nethermind/Nethermind.Optimism/OptimismReadOnlyTxProcessingEnv.cs new file mode 100644 index 000000000000..ad5fba0d7506 --- /dev/null +++ b/src/Nethermind/Nethermind.Optimism/OptimismReadOnlyTxProcessingEnv.cs @@ -0,0 +1,38 @@ +// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using Nethermind.Blockchain; +using Nethermind.Consensus.Processing; +using Nethermind.Core.Specs; +using Nethermind.Evm; +using Nethermind.Evm.TransactionProcessing; +using Nethermind.Logging; +using Nethermind.State; +using System; + +namespace Nethermind.Optimism; + +public class OptimismReadOnlyTxProcessingEnv( + IWorldStateManager worldStateManager, + IReadOnlyBlockTree readOnlyBlockTree, + ISpecProvider specProvider, + ILogManager logManager, + IL1CostHelper l1CostHelper, + IOptimismSpecHelper opSpecHelper, + PreBlockCaches? preBlockCaches = null) : ReadOnlyTxProcessingEnv( + worldStateManager, + readOnlyBlockTree, + specProvider, + logManager, + preBlockCaches + ) +{ + protected override TransactionProcessor CreateTransactionProcessor() + { + ArgumentNullException.ThrowIfNull(_logManager); + + BlockhashProvider blockhashProvider = new(BlockTree, _specProvider, StateProvider, _logManager); + VirtualMachine virtualMachine = new(blockhashProvider, _specProvider, _logManager); + return new OptimismTransactionProcessor(_specProvider, StateProvider, virtualMachine, _logManager, l1CostHelper, opSpecHelper); + } +} diff --git a/src/Nethermind/Nethermind.Optimism/OptimismTransactionProcessor.cs b/src/Nethermind/Nethermind.Optimism/OptimismTransactionProcessor.cs index 4322fa58f32c..ccf025474357 100644 --- a/src/Nethermind/Nethermind.Optimism/OptimismTransactionProcessor.cs +++ b/src/Nethermind/Nethermind.Optimism/OptimismTransactionProcessor.cs @@ -13,23 +13,14 @@ namespace Nethermind.Optimism; -public class OptimismTransactionProcessor : TransactionProcessor +public class OptimismTransactionProcessor( + ISpecProvider specProvider, + IWorldState worldState, + IVirtualMachine virtualMachine, + ILogManager logManager, + IL1CostHelper l1CostHelper, + IOptimismSpecHelper opSpecHelper) : TransactionProcessor(specProvider, worldState, virtualMachine, logManager) { - private readonly IL1CostHelper _l1CostHelper; - private readonly IOPConfigHelper _opConfigHelper; - - public OptimismTransactionProcessor( - ISpecProvider? specProvider, - IWorldState? worldState, - IVirtualMachine? virtualMachine, - ILogManager? logManager, - IL1CostHelper l1CostHelper, - IOPConfigHelper opConfigHelper) : base(specProvider, worldState, virtualMachine, logManager) - { - _l1CostHelper = l1CostHelper; - _opConfigHelper = opConfigHelper; - } - private UInt256? _currentTxL1Cost; protected override TransactionResult Execute(Transaction tx, in BlockExecutionContext blCtx, ITxTracer tracer, ExecutionOptions opts) @@ -108,7 +99,7 @@ protected override TransactionResult BuyGas(Transaction tx, BlockHeader header, return "insufficient sender balance"; } - UInt256 l1Cost = _currentTxL1Cost ??= _l1CostHelper.ComputeL1Cost(tx, header, WorldState); + UInt256 l1Cost = _currentTxL1Cost ??= l1CostHelper.ComputeL1Cost(tx, header, WorldState); if (UInt256.SubtractUnderflow(balanceLeft, l1Cost, out balanceLeft)) { TraceLogInvalidTx(tx, $"INSUFFICIENT_SENDER_BALANCE: ({tx.SenderAddress})_BALANCE = {senderBalance}"); @@ -158,10 +149,10 @@ protected override void PayFees(Transaction tx, BlockHeader header, IReleaseSpec // Skip coinbase payments for deposit tx in Regolith base.PayFees(tx, header, spec, tracer, substate, spentGas, premiumPerGas, statusCode); - if (_opConfigHelper.IsBedrock(header)) + if (opSpecHelper.IsBedrock(header)) { - UInt256 l1Cost = _currentTxL1Cost ??= _l1CostHelper.ComputeL1Cost(tx, header, WorldState); - WorldState.AddToBalanceAndCreateIfNotExists(_opConfigHelper.L1FeeReceiver, l1Cost, spec); + UInt256 l1Cost = _currentTxL1Cost ??= l1CostHelper.ComputeL1Cost(tx, header, WorldState); + WorldState.AddToBalanceAndCreateIfNotExists(opSpecHelper.L1FeeReceiver, l1Cost, spec); } } } @@ -171,7 +162,7 @@ protected override long Refund(Transaction tx, BlockHeader header, IReleaseSpec { // if deposit: skip refunds, skip tipping coinbase // Regolith changes this behaviour to report the actual gasUsed instead of always reporting all gas used. - if (tx.IsDeposit() && !_opConfigHelper.IsRegolith(header)) + if (tx.IsDeposit() && !opSpecHelper.IsRegolith(header)) { // Record deposits as using all their gas // System Transactions are special & are not recorded as using any gas (anywhere) diff --git a/src/Nethermind/Nethermind.Optimism/OptimismTxPoolTxSource.cs b/src/Nethermind/Nethermind.Optimism/OptimismTxPoolTxSource.cs index b91f085b892c..7334e9448b45 100644 --- a/src/Nethermind/Nethermind.Optimism/OptimismTxPoolTxSource.cs +++ b/src/Nethermind/Nethermind.Optimism/OptimismTxPoolTxSource.cs @@ -6,6 +6,7 @@ using Nethermind.Consensus.Producers; using Nethermind.Consensus.Transactions; using Nethermind.Core; +using Nethermind.Optimism.Rpc; namespace Nethermind.Optimism; diff --git a/src/Nethermind/Nethermind.Optimism/ReadOnlyChainProcessingEnv.cs b/src/Nethermind/Nethermind.Optimism/ReadOnlyChainProcessingEnv.cs new file mode 100644 index 000000000000..8c97a784c819 --- /dev/null +++ b/src/Nethermind/Nethermind.Optimism/ReadOnlyChainProcessingEnv.cs @@ -0,0 +1,54 @@ +// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using Nethermind.Blockchain.Blocks; +using Nethermind.Blockchain.Receipts; +using Nethermind.Consensus.Processing; +using Nethermind.Consensus.Rewards; +using Nethermind.Consensus.Validators; +using Nethermind.Consensus.Withdrawals; +using Nethermind.Core.Specs; +using Nethermind.Logging; + +namespace Nethermind.Optimism; + +/// +/// Not thread safe. +/// +public class OptimismReadOnlyChainProcessingEnv( + ReadOnlyTxProcessingEnv txEnv, + IBlockValidator blockValidator, + IBlockPreprocessorStep recoveryStep, + IRewardCalculator rewardCalculator, + IReceiptStorage receiptStorage, + ISpecProvider specProvider, + ILogManager logManager, + IOptimismSpecHelper opSpecHelper, + Create2DeployerContractRewriter contractRewriter, + IWithdrawalProcessor? withdrawalProcessor, + IBlockProcessor.IBlockTransactionsExecutor? blockTransactionsExecutor = null) : ReadOnlyChainProcessingEnv( + txEnv, + blockValidator, + recoveryStep, + rewardCalculator, + receiptStorage, + specProvider, + logManager, + blockTransactionsExecutor) +{ + protected override IBlockProcessor CreateBlockProcessor(ReadOnlyTxProcessingEnv txEnv, IBlockValidator blockValidator, IRewardCalculator rewardCalculator, IReceiptStorage receiptStorage, ISpecProvider specProvider, ILogManager logManager, IBlockProcessor.IBlockTransactionsExecutor transactionsExecutor) + { + return new OptimismBlockProcessor( + specProvider, + blockValidator, + rewardCalculator, + transactionsExecutor, + StateProvider, + receiptStorage, + new BlockhashStore(txEnv.BlockTree, specProvider, StateProvider), + logManager, + opSpecHelper, + contractRewriter, + withdrawalProcessor); + } +} diff --git a/src/Nethermind/Nethermind.Optimism/IOptimismEngineRpcModule.cs b/src/Nethermind/Nethermind.Optimism/Rpc/IOptimismEngineRpcModule.cs similarity index 99% rename from src/Nethermind/Nethermind.Optimism/IOptimismEngineRpcModule.cs rename to src/Nethermind/Nethermind.Optimism/Rpc/IOptimismEngineRpcModule.cs index 08b1ee5f25fb..a4fff0ee4377 100644 --- a/src/Nethermind/Nethermind.Optimism/IOptimismEngineRpcModule.cs +++ b/src/Nethermind/Nethermind.Optimism/Rpc/IOptimismEngineRpcModule.cs @@ -7,7 +7,7 @@ using Nethermind.JsonRpc.Modules; using Nethermind.Merge.Plugin.Data; -namespace Nethermind.Optimism; +namespace Nethermind.Optimism.Rpc; [RpcModule(ModuleType.Engine)] diff --git a/src/Nethermind/Nethermind.Optimism/Rpc/IOptimismEthRpcModule.cs b/src/Nethermind/Nethermind.Optimism/Rpc/IOptimismEthRpcModule.cs index 9f95e6207339..963fbe27a4b7 100644 --- a/src/Nethermind/Nethermind.Optimism/Rpc/IOptimismEthRpcModule.cs +++ b/src/Nethermind/Nethermind.Optimism/Rpc/IOptimismEthRpcModule.cs @@ -7,7 +7,7 @@ using Nethermind.JsonRpc; using Nethermind.Blockchain.Find; -namespace Nethermind.Optimism; +namespace Nethermind.Optimism.Rpc; [RpcModule(ModuleType.Eth)] public interface IOptimismEthRpcModule : IEthRpcModule diff --git a/src/Nethermind/Nethermind.Optimism/OptimismEngineRpcModule.cs b/src/Nethermind/Nethermind.Optimism/Rpc/OptimismEngineRpcModule.cs similarity index 98% rename from src/Nethermind/Nethermind.Optimism/OptimismEngineRpcModule.cs rename to src/Nethermind/Nethermind.Optimism/Rpc/OptimismEngineRpcModule.cs index 79e063eb4b69..92aba891d7b6 100644 --- a/src/Nethermind/Nethermind.Optimism/OptimismEngineRpcModule.cs +++ b/src/Nethermind/Nethermind.Optimism/Rpc/OptimismEngineRpcModule.cs @@ -7,7 +7,7 @@ using Nethermind.Merge.Plugin; using Nethermind.Merge.Plugin.Data; -namespace Nethermind.Optimism; +namespace Nethermind.Optimism.Rpc; public class OptimismEngineRpcModule : IOptimismEngineRpcModule { diff --git a/src/Nethermind/Nethermind.Optimism/Rpc/OptimismEthModuleFactory.cs b/src/Nethermind/Nethermind.Optimism/Rpc/OptimismEthModuleFactory.cs index 6d45fe82bdd9..d3e6bbd605e7 100644 --- a/src/Nethermind/Nethermind.Optimism/Rpc/OptimismEthModuleFactory.cs +++ b/src/Nethermind/Nethermind.Optimism/Rpc/OptimismEthModuleFactory.cs @@ -19,7 +19,7 @@ using Nethermind.Crypto; using Nethermind.JsonRpc.Client; -namespace Nethermind.Optimism; +namespace Nethermind.Optimism.Rpc; public class OptimismEthModuleFactory( IJsonRpcConfig rpcConfig, @@ -40,7 +40,7 @@ public class OptimismEthModuleFactory( IAccountStateProvider accountStateProvider, IEthereumEcdsa ecdsa, ITxSealer sealer, - IOPConfigHelper opConfigHelper + IOptimismSpecHelper opSpecHelper ) : ModuleFactoryBase { @@ -61,7 +61,7 @@ IOPConfigHelper opConfigHelper private readonly ITxSealer _sealer = sealer ?? throw new ArgumentNullException(nameof(sealer)); private readonly IBlockFinder _blockFinder = blockFinder ?? throw new ArgumentNullException(nameof(blockFinder)); private readonly IReceiptFinder _receiptFinder = receiptFinder ?? throw new ArgumentNullException(nameof(receiptFinder)); - private readonly IOPConfigHelper _opConfigHelper = opConfigHelper ?? throw new ArgumentNullException(nameof(opConfigHelper)); + private readonly IOptimismSpecHelper _opSpecHelper = opSpecHelper ?? throw new ArgumentNullException(nameof(opSpecHelper)); public override IOptimismEthRpcModule Create() { @@ -84,7 +84,7 @@ public override IOptimismEthRpcModule Create() _accountStateProvider, _ecdsa, _sealer, - _opConfigHelper + _opSpecHelper ); } } diff --git a/src/Nethermind/Nethermind.Optimism/Rpc/OptimismEthRpcModule.cs b/src/Nethermind/Nethermind.Optimism/Rpc/OptimismEthRpcModule.cs index 7f42d0d76cad..8e78818a6ac3 100644 --- a/src/Nethermind/Nethermind.Optimism/Rpc/OptimismEthRpcModule.cs +++ b/src/Nethermind/Nethermind.Optimism/Rpc/OptimismEthRpcModule.cs @@ -1,7 +1,6 @@ // SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only -using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Nethermind.Blockchain.Find; @@ -26,7 +25,7 @@ using Nethermind.TxPool; using Nethermind.Wallet; -namespace Nethermind.Optimism; +namespace Nethermind.Optimism.Rpc; public class OptimismEthRpcModule : EthRpcModule, IOptimismEthRpcModule { @@ -34,7 +33,7 @@ public class OptimismEthRpcModule : EthRpcModule, IOptimismEthRpcModule private readonly IAccountStateProvider _accountStateProvider; private readonly IEthereumEcdsa _ecdsa; private readonly ITxSealer _sealer; - private readonly IOPConfigHelper _opConfigHelper; + private readonly IOptimismSpecHelper _opSpecHelper; public OptimismEthRpcModule( IJsonRpcConfig rpcConfig, @@ -55,7 +54,7 @@ public OptimismEthRpcModule( IAccountStateProvider accountStateProvider, IEthereumEcdsa ecdsa, ITxSealer sealer, - IOPConfigHelper opConfigHelper) : base( + IOptimismSpecHelper opSpecHelper) : base( rpcConfig, blockchainBridge, blockFinder, @@ -74,12 +73,12 @@ public OptimismEthRpcModule( _accountStateProvider = accountStateProvider; _ecdsa = ecdsa; _sealer = sealer; - _opConfigHelper = opConfigHelper; + _opSpecHelper = opSpecHelper; } public new ResultWrapper eth_getBlockReceipts(BlockParameter blockParameter) { - static ResultWrapper GetBlockReceipts(IReceiptFinder receiptFinder, BlockParameter blockParameter, IBlockFinder blockFinder, ISpecProvider specProvider, IOPConfigHelper opConfigHelper) + static ResultWrapper GetBlockReceipts(IReceiptFinder receiptFinder, BlockParameter blockParameter, IBlockFinder blockFinder, ISpecProvider specProvider, IOptimismSpecHelper opSpecHelper) { SearchResult searchResult = blockFinder.SearchForBlock(blockParameter); if (searchResult.IsError) @@ -91,7 +90,7 @@ public OptimismEthRpcModule( OptimismTxReceipt[] receipts = receiptFinder.Get(block).Cast().ToArray() ?? new OptimismTxReceipt[block.Transactions.Length]; bool isEip1559Enabled = specProvider.GetSpec(block.Header).IsEip1559Enabled; - L1BlockGasInfo l1BlockGasInfo = new(block, opConfigHelper.IsRegolith(block!.Header)); + L1BlockGasInfo l1BlockGasInfo = new(block, opSpecHelper); OptimismReceiptForRpc[]? result = [.. receipts .Zip(block.Transactions, (r, t) => @@ -101,7 +100,7 @@ public OptimismEthRpcModule( return ResultWrapper.Success(result); } - return GetBlockReceipts(_receiptFinder, blockParameter, _blockFinder, _specProvider, _opConfigHelper); + return GetBlockReceipts(_receiptFinder, blockParameter, _blockFinder, _specProvider, _opSpecHelper); } public override async Task> eth_sendTransaction(TransactionForRpc rpcTx) @@ -154,7 +153,7 @@ public override async Task> eth_sendRawTransaction(byte[] Block block = foundBlock.Object; - L1BlockGasInfo l1GasInfo = new(block, _opConfigHelper.IsRegolith(block.Header)); + L1BlockGasInfo l1GasInfo = new(block, _opSpecHelper); return ResultWrapper.Success( new(txHash, (OptimismTxReceipt)receipt, gasInfo.Value, l1GasInfo.GetTxGasInfo(block.Transactions.First(tx => tx.Hash == txHash)), logIndexStart)); } diff --git a/src/Nethermind/Nethermind.Optimism/OptimismPayloadAttributes.cs b/src/Nethermind/Nethermind.Optimism/Rpc/OptimismPayloadAttributes.cs similarity index 97% rename from src/Nethermind/Nethermind.Optimism/OptimismPayloadAttributes.cs rename to src/Nethermind/Nethermind.Optimism/Rpc/OptimismPayloadAttributes.cs index f1727be019c2..8db3156fcae1 100644 --- a/src/Nethermind/Nethermind.Optimism/OptimismPayloadAttributes.cs +++ b/src/Nethermind/Nethermind.Optimism/Rpc/OptimismPayloadAttributes.cs @@ -12,7 +12,7 @@ using Nethermind.Core.Specs; using Nethermind.Serialization.Rlp; -namespace Nethermind.Optimism; +namespace Nethermind.Optimism.Rpc; public class OptimismPayloadAttributes : PayloadAttributes { @@ -69,7 +69,7 @@ protected override int ComputePayloadIdMembersSize() => protected override int WritePayloadIdMembers(BlockHeader parentHeader, Span inputSpan) { - int offset = base.WritePayloadIdMembers(parentHeader, inputSpan); + var offset = base.WritePayloadIdMembers(parentHeader, inputSpan); inputSpan[offset] = NoTxPool ? (byte)1 : (byte)0; offset += 1; @@ -122,9 +122,7 @@ public override string ToString() .Append($"{nameof(Transactions)}: {Transactions?.Length ?? 0}"); if (Withdrawals is not null) - { sb.Append($", {nameof(Withdrawals)} count: {Withdrawals.Length}"); - } sb.Append('}'); return sb.ToString(); diff --git a/src/Nethermind/Nethermind.Optimism/Rpc/OptimismReceiptForRpc.cs b/src/Nethermind/Nethermind.Optimism/Rpc/OptimismReceiptForRpc.cs index 2077279e73fb..d902059872b4 100644 --- a/src/Nethermind/Nethermind.Optimism/Rpc/OptimismReceiptForRpc.cs +++ b/src/Nethermind/Nethermind.Optimism/Rpc/OptimismReceiptForRpc.cs @@ -7,7 +7,7 @@ using Nethermind.JsonRpc.Data; using System.Text.Json.Serialization; -namespace Nethermind.Optimism; +namespace Nethermind.Optimism.Rpc; public class OptimismReceiptForRpc : ReceiptForRpc { diff --git a/src/Nethermind/Nethermind.Optimism/Rpc/OptimismTraceModuleFactory.cs b/src/Nethermind/Nethermind.Optimism/Rpc/OptimismTraceModuleFactory.cs new file mode 100644 index 000000000000..c6b8326ed4de --- /dev/null +++ b/src/Nethermind/Nethermind.Optimism/Rpc/OptimismTraceModuleFactory.cs @@ -0,0 +1,58 @@ +// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using Nethermind.Blockchain; +using Nethermind.Blockchain.Receipts; +using Nethermind.Consensus; +using Nethermind.Consensus.Processing; +using Nethermind.Consensus.Rewards; +using Nethermind.Consensus.Validators; +using Nethermind.Consensus.Withdrawals; +using Nethermind.Core.Specs; +using Nethermind.JsonRpc; +using Nethermind.JsonRpc.Modules.Trace; +using Nethermind.Logging; +using Nethermind.State; + +namespace Nethermind.Optimism.Rpc; + +public class OptimismTraceModuleFactory( + IWorldStateManager worldStateManager, + IBlockTree blockTree, + IJsonRpcConfig jsonRpcConfig, + IBlockPreprocessorStep recoveryStep, + IRewardCalculatorSource rewardCalculatorSource, + IReceiptStorage receiptFinder, + ISpecProvider specProvider, + IPoSSwitcher poSSwitcher, + ILogManager logManager, + IL1CostHelper l1CostHelper, + IOptimismSpecHelper opSpecHelper, + Create2DeployerContractRewriter contractRewriter, + IWithdrawalProcessor withdrawalProcessor) : TraceModuleFactory( + worldStateManager, + blockTree, + jsonRpcConfig, + recoveryStep, + rewardCalculatorSource, + receiptFinder, + specProvider, + poSSwitcher, + logManager) +{ + protected override ReadOnlyTxProcessingEnv CreateTxProcessingEnv() => + new OptimismReadOnlyTxProcessingEnv(_worldStateManager, _blockTree, _specProvider, _logManager, l1CostHelper, opSpecHelper); + + protected override ReadOnlyChainProcessingEnv CreateChainProcessingEnv(IBlockProcessor.IBlockTransactionsExecutor transactionsExecutor, ReadOnlyTxProcessingEnv txProcessingEnv, IRewardCalculator rewardCalculator) => new OptimismReadOnlyChainProcessingEnv( + txProcessingEnv, + Always.Valid, + _recoveryStep, + rewardCalculator, + _receiptStorage, + _specProvider, + _logManager, + opSpecHelper, + contractRewriter, + withdrawalProcessor, + transactionsExecutor); +} diff --git a/src/Nethermind/Nethermind.Optimism/Rpc/RegisterOptimismRpcModules.cs b/src/Nethermind/Nethermind.Optimism/Rpc/RegisterOptimismRpcModules.cs index fe417eacd37c..c72ad28a6c62 100644 --- a/src/Nethermind/Nethermind.Optimism/Rpc/RegisterOptimismRpcModules.cs +++ b/src/Nethermind/Nethermind.Optimism/Rpc/RegisterOptimismRpcModules.cs @@ -4,16 +4,19 @@ using System; using Nethermind.Api; using Nethermind.Blockchain; +using Nethermind.Consensus.AuRa.Withdrawals; +using Nethermind.Consensus.Withdrawals; using Nethermind.Init.Steps; using Nethermind.JsonRpc; using Nethermind.JsonRpc.Client; using Nethermind.JsonRpc.Modules; +using Nethermind.JsonRpc.Modules.Eth; using Nethermind.JsonRpc.Modules.Eth.FeeHistory; using Nethermind.Logging; using Nethermind.TxPool; using Nethermind.Wallet; -namespace Nethermind.Optimism; +namespace Nethermind.Optimism.Rpc; public class RegisterOptimismRpcModules : RegisterRpcModules { @@ -54,6 +57,7 @@ protected override void RegisterEthRpcModule(IRpcModuleProvider rpcModuleProvide BasicJsonRpcClient? sequencerJsonRpcClient = _config.SequencerUrl is null ? null : new(new Uri(_config.SequencerUrl), _api.EthereumJsonSerializer, _api.LogManager); + ModuleFactoryBase ethModuleFactory = CreateEthModuleFactory(); ITxSigner txSigner = new WalletTxSigner(_api.Wallet, _api.SpecProvider.ChainId); TxSealer sealer = new(txSigner, _api.Timestamper); @@ -85,4 +89,33 @@ protected override void RegisterEthRpcModule(IRpcModuleProvider rpcModuleProvide rpcModuleProvider.RegisterBounded(optimismEthModuleFactory, _jsonRpcConfig.EthModuleConcurrentInstances ?? Environment.ProcessorCount, _jsonRpcConfig.Timeout); } + + protected override void RegisterTraceRpcModule(IRpcModuleProvider rpcModuleProvider) + { + StepDependencyException.ThrowIfNull(_api.WorldStateManager); + StepDependencyException.ThrowIfNull(_api.BlockTree); + StepDependencyException.ThrowIfNull(_api.ReceiptStorage); + StepDependencyException.ThrowIfNull(_api.RewardCalculatorSource); + StepDependencyException.ThrowIfNull(_api.SpecProvider); + StepDependencyException.ThrowIfNull(_api.WorldState); + StepDependencyException.ThrowIfNull(_api.L1CostHelper); + StepDependencyException.ThrowIfNull(_api.SpecHelper); + + OptimismTraceModuleFactory traceModuleFactory = new( + _api.WorldStateManager, + _api.BlockTree, + _jsonRpcConfig, + _api.BlockPreprocessor, + _api.RewardCalculatorSource, + _api.ReceiptStorage, + _api.SpecProvider, + _api.PoSSwitcher, + _api.LogManager, + _api.L1CostHelper, + _api.SpecHelper, + new Create2DeployerContractRewriter(_api.SpecHelper, _api.SpecProvider, _api.BlockTree), + new BlockProductionWithdrawalProcessor(new NullWithdrawalProcessor())); + + rpcModuleProvider.RegisterBoundedByCpuCount(traceModuleFactory, _jsonRpcConfig.Timeout); + } } diff --git a/src/Nethermind/Nethermind.Runner/JsonRpc/Startup.cs b/src/Nethermind/Nethermind.Runner/JsonRpc/Startup.cs index 6625abe7e9a6..5c6c24f61560 100644 --- a/src/Nethermind/Nethermind.Runner/JsonRpc/Startup.cs +++ b/src/Nethermind/Nethermind.Runner/JsonRpc/Startup.cs @@ -160,7 +160,7 @@ await PushErrorResponse(StatusCodes.Status403Forbidden, ErrorCodes.InvalidReques CountingPipeReader request = new(ctx.Request.BodyReader); try { - JsonRpcContext jsonRpcContext = JsonRpcContext.Http(jsonRpcUrl); + using JsonRpcContext jsonRpcContext = JsonRpcContext.Http(jsonRpcUrl); await foreach (JsonRpcResult result in jsonRpcProcessor.ProcessAsync(request, jsonRpcContext)) { using (result) @@ -215,7 +215,7 @@ await PushErrorResponse(StatusCodes.Status403Forbidden, ErrorCodes.InvalidReques { jsonSerializer.Serialize(resultWriter, result.Response); } - + await resultWriter.CompleteAsync(); if (stream is not null) { ctx.Response.ContentLength = resultWriter.WrittenCount; diff --git a/src/Nethermind/Nethermind.Runner/configs/chiado.cfg b/src/Nethermind/Nethermind.Runner/configs/chiado.cfg index b6b6cab19c36..18726ba0af23 100644 --- a/src/Nethermind/Nethermind.Runner/configs/chiado.cfg +++ b/src/Nethermind/Nethermind.Runner/configs/chiado.cfg @@ -15,8 +15,8 @@ }, "Sync": { "FastSync": true, - "PivotNumber": 10080000, - "PivotHash": "0x722df5c632d0e2dcdd0971800cdeee3a24cd719618f9eb2474b2ce17266859eb", + "PivotNumber": 10200000, + "PivotHash": "0x66705e2ef5f4edcd627afe1e512903778c780b185c9b3dc92e6934e295683afd", "PivotTotalDifficulty": "231708131825107706987652208063906496124457284", "FastSyncCatchUpHeightDelta": "10000000000", "UseGethLimitsInFastBlocks": false diff --git a/src/Nethermind/Nethermind.Runner/configs/energyweb.cfg b/src/Nethermind/Nethermind.Runner/configs/energyweb.cfg index 06b4747ef3ef..e54f328f45e5 100644 --- a/src/Nethermind/Nethermind.Runner/configs/energyweb.cfg +++ b/src/Nethermind/Nethermind.Runner/configs/energyweb.cfg @@ -11,9 +11,9 @@ }, "Sync": { "FastSync": true, - "PivotNumber": 30210000, - "PivotHash": "0x748a132b28ccc1db24fe2115b60096ceed449e2359ad1b8a4865700f58a218e5", - "PivotTotalDifficulty": "10279930304681550981228546890513717667712235485", + "PivotNumber": 30320000, + "PivotHash": "0x7e06ec6e44fa1a5fdbc25aa33758451465083ef73e8935d7174d2aa3122578a7", + "PivotTotalDifficulty": "10317361365042854212209518097331212170972166406", "FastBlocks": true, "UseGethLimitsInFastBlocks": false, "FastSyncCatchUpHeightDelta": 10000000000 diff --git a/src/Nethermind/Nethermind.Runner/configs/exosama.cfg b/src/Nethermind/Nethermind.Runner/configs/exosama.cfg index c2a6be68bcab..782b1cb621d2 100644 --- a/src/Nethermind/Nethermind.Runner/configs/exosama.cfg +++ b/src/Nethermind/Nethermind.Runner/configs/exosama.cfg @@ -11,9 +11,9 @@ }, "Sync": { "FastSync": true, - "PivotNumber": 10170000, - "PivotHash": "0xdcb2859b4e44cdc04967dbcc33c5e1015ccff7f1325391a11dba834b7967fed8", - "PivotTotalDifficulty": "3460671671585944173422519757581082710154033286", + "PivotNumber": 10290000, + "PivotHash": "0x55a1b682599b65ba2712393c130e25a3992ac32cf278ce6785d772067f695657", + "PivotTotalDifficulty": "3501505555616456789038124710472894895528513286", "FastBlocks": true, "UseGethLimitsInFastBlocks": false, "FastSyncCatchUpHeightDelta": 10000000000 diff --git a/src/Nethermind/Nethermind.Runner/configs/gnosis.cfg b/src/Nethermind/Nethermind.Runner/configs/gnosis.cfg index 2e24563a30f0..aae981b34a77 100644 --- a/src/Nethermind/Nethermind.Runner/configs/gnosis.cfg +++ b/src/Nethermind/Nethermind.Runner/configs/gnosis.cfg @@ -12,8 +12,8 @@ }, "Sync": { "FastSync": true, - "PivotNumber": 34240000, - "PivotHash": "0x36ac41a7a5f3e6096c86e13cc43d1cd2b532e6cb1c75fc4668d3363fbd4c3b63", + "PivotNumber": 34350000, + "PivotHash": "0x456b1aa69a62a859343be8f1a9b607d482a58d4e80d82cb7c53f24bcc5b352e9", "PivotTotalDifficulty": "8626000110427538733349499292577475819600160930", "FastBlocks": true, "UseGethLimitsInFastBlocks": false, diff --git a/src/Nethermind/Nethermind.Runner/configs/joc-mainnet.cfg b/src/Nethermind/Nethermind.Runner/configs/joc-mainnet.cfg index b6d36df8b10a..c9b1a620d9fd 100644 --- a/src/Nethermind/Nethermind.Runner/configs/joc-mainnet.cfg +++ b/src/Nethermind/Nethermind.Runner/configs/joc-mainnet.cfg @@ -12,9 +12,9 @@ "FastSync": true, "SnapSync": true, "FastBlocks": true, - "PivotNumber": 11530000, - "PivotHash": "0x14ed185b94010f5cceeed3166c32e9f18236c4feff1979f2379b18c754a27951", - "PivotTotalDifficulty": "23036561" + "PivotNumber": 11650000, + "PivotHash": "0x7a9089d0e6a3f43b5b0321f7aa4da8ec37e4bc1220d1b7cb5b22dd058fa2dd03", + "PivotTotalDifficulty": "23276561" }, "Metrics": { "NodeName": "JOC-Mainnet" diff --git a/src/Nethermind/Nethermind.Runner/configs/joc-testnet.cfg b/src/Nethermind/Nethermind.Runner/configs/joc-testnet.cfg index 337f54aeb84a..d13d50c4a2fb 100644 --- a/src/Nethermind/Nethermind.Runner/configs/joc-testnet.cfg +++ b/src/Nethermind/Nethermind.Runner/configs/joc-testnet.cfg @@ -11,9 +11,9 @@ "Sync": { "FastSync": true, "SnapSync": true, - "PivotNumber": 5140000, - "PivotHash": "0x7b4ff9ef1211ec2f83ccfe75d6dedb00884ddaebc44862709c28c9da1f9ff91b", - "PivotTotalDifficulty": "10109126" + "PivotNumber": 5260000, + "PivotHash": "0xfeedf52b4e93509a31e933f04b5115d1395ebe46cde5105bff44cd7ce60e71b9", + "PivotTotalDifficulty": "10295113" }, "Metrics": { "NodeName": "JOC-Testnet" diff --git a/src/Nethermind/Nethermind.Runner/configs/mainnet.cfg b/src/Nethermind/Nethermind.Runner/configs/mainnet.cfg index 9f70fe24cf6a..e33b0a332659 100644 --- a/src/Nethermind/Nethermind.Runner/configs/mainnet.cfg +++ b/src/Nethermind/Nethermind.Runner/configs/mainnet.cfg @@ -9,8 +9,8 @@ "Sync": { "FastSync": true, "SnapSync": true, - "PivotNumber": 19999000, - "PivotHash": "0xd5819463e6d620e02b9a996802aae2872d00fcd36a9fe283428be278cf2895e4", + "PivotNumber": 20049000, + "PivotHash": "0x7e1be28e7effe28715bee8a1bc9991ea966979b84e62432a32c543dcf8e45624", "PivotTotalDifficulty": "58750003716598352816469", "FastBlocks": true, "FastSyncCatchUpHeightDelta": "10000000000" diff --git a/src/Nethermind/Nethermind.Runner/configs/sepolia.cfg b/src/Nethermind/Nethermind.Runner/configs/sepolia.cfg index be95db31d1ce..e9aff51d60b3 100644 --- a/src/Nethermind/Nethermind.Runner/configs/sepolia.cfg +++ b/src/Nethermind/Nethermind.Runner/configs/sepolia.cfg @@ -17,8 +17,8 @@ "FastSync": true, "SnapSync": true, "UseGethLimitsInFastBlocks": true, - "PivotNumber": 6020000, - "PivotHash": "0x19f6751b9a58ee205bba64278d55929b4805c4062e13bfdd17119fb508651486", + "PivotNumber": 6067000, + "PivotHash": "0xec18eaec616ea4cec9cd09ab19eee43cfea9fe03addcae2a8eb4868b0fe64c36", "PivotTotalDifficulty": "17000018015853232", "FastSyncCatchUpHeightDelta": "10000000000" }, diff --git a/src/Nethermind/Nethermind.Runner/configs/volta.cfg b/src/Nethermind/Nethermind.Runner/configs/volta.cfg index 3322ac6cb7f9..3f1549a91cf8 100644 --- a/src/Nethermind/Nethermind.Runner/configs/volta.cfg +++ b/src/Nethermind/Nethermind.Runner/configs/volta.cfg @@ -15,9 +15,9 @@ }, "Sync": { "FastSync": true, - "PivotNumber": 27980000, - "PivotHash": "0x6e545436661459d165abc395f294201ff70ad4e741a170283993edeecf1b176d", - "PivotTotalDifficulty": "9521100626447858207705221515940874556167594281", + "PivotNumber": 28070000, + "PivotHash": "0x40256b527c12040e809347751dfa67d896f292a123e912d85dc4d6039f778b33", + "PivotTotalDifficulty": "9551726039470742669416925230609733695198421023", "UseGethLimitsInFastBlocks": false, "FastSyncCatchUpHeightDelta": 10000000000 }, diff --git a/src/Nethermind/Nethermind.Serialization.Json/StreamPipeWriter.cs b/src/Nethermind/Nethermind.Serialization.Json/StreamPipeWriter.cs index da1ecd2a3fb5..89f802e849fc 100644 --- a/src/Nethermind/Nethermind.Serialization.Json/StreamPipeWriter.cs +++ b/src/Nethermind/Nethermind.Serialization.Json/StreamPipeWriter.cs @@ -18,7 +18,8 @@ namespace Nethermind.Serialization.Json; public interface ICountingBufferWriter : IBufferWriter { - public long WrittenCount { get; } + long WrittenCount { get; } + ValueTask CompleteAsync(Exception? exception = null); } public sealed class CountingPipeWriter : ICountingBufferWriter @@ -42,6 +43,12 @@ public void Advance(int count) public Memory GetMemory(int sizeHint = 0) => _writer.GetMemory(sizeHint); public Span GetSpan(int sizeHint = 0) => _writer.GetSpan(sizeHint); + + public ValueTask CompleteAsync(Exception? exception = null) + { + return _writer.CompleteAsync(); + } + } public sealed class CountingStreamPipeWriter : PipeWriter, ICountingBufferWriter @@ -84,11 +91,6 @@ public CountingStreamPipeWriter(Stream writingStream, StreamPipeWriterOptions? o { ThrowHelper.ThrowArgumentNullException_WritingStream(); } - if (options is null) - { - ThrowHelper.ThrowArgumentNullException_Options(); - } - InnerStream = writingStream; _minimumBufferSize = options?.MinimumBufferSize ?? 4096; _pool = options?.Pool == MemoryPool.Shared ? null : options?.Pool; diff --git a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpecLoader.cs b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpecLoader.cs index c69a7a6dcda6..769a9858633f 100644 --- a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpecLoader.cs +++ b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpecLoader.cs @@ -337,6 +337,8 @@ static AuRaParameters.Validator LoadValidator(ChainSpecJson.AuRaValidatorJson va BedrockBlockNumber = chainSpecJson.Engine.Optimism.BedrockBlockNumber, CanyonTimestamp = chainSpecJson.Engine.Optimism.CanyonTimestamp, EcotoneTimestamp = chainSpecJson.Engine.Optimism.EcotoneTimestamp, + FjordTimestamp = chainSpecJson.Engine.Optimism.FjordTimestamp, + L1FeeRecipient = chainSpecJson.Engine.Optimism.L1FeeRecipient, L1BlockAddress = chainSpecJson.Engine.Optimism.L1BlockAddress, CanyonBaseFeeChangeDenominator = chainSpecJson.Engine.Optimism.CanyonBaseFeeChangeDenominator, diff --git a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/Json/ChainSpecJson.cs b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/Json/ChainSpecJson.cs index 3393b95f5d2e..4600e1f97772 100644 --- a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/Json/ChainSpecJson.cs +++ b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/Json/ChainSpecJson.cs @@ -174,6 +174,7 @@ internal class OptimismEngineJson public long BedrockBlockNumber => Params.BedrockBlockNumber; public ulong? CanyonTimestamp => Params.CanyonTimestamp; public ulong? EcotoneTimestamp => Params.EcotoneTimestamp; + public ulong? FjordTimestamp => Params.FjordTimestamp; public Address L1FeeRecipient => Params.L1FeeRecipient; public Address L1BlockAddress => Params.L1BlockAddress; public UInt256 CanyonBaseFeeChangeDenominator => Params.CanyonBaseFeeChangeDenominator; @@ -188,6 +189,7 @@ internal class OptimismEngineParamsJson public long BedrockBlockNumber { get; set; } public ulong? CanyonTimestamp { get; set; } public ulong? EcotoneTimestamp { get; set; } + public ulong? FjordTimestamp { get; set; } public Address L1FeeRecipient { get; set; } public Address L1BlockAddress { get; set; } public UInt256 CanyonBaseFeeChangeDenominator { get; set; } diff --git a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/OptimismParameters.cs b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/OptimismParameters.cs index 31c45d81dc12..b457040ebcf4 100644 --- a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/OptimismParameters.cs +++ b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/OptimismParameters.cs @@ -16,6 +16,8 @@ public class OptimismParameters public ulong? EcotoneTimestamp { get; set; } + public ulong? FjordTimestamp { get; set; } + public Address L1FeeRecipient { get; set; } public Address L1BlockAddress { get; set; } diff --git a/tools/docgen/JsonRpcGenerator.cs b/tools/docgen/JsonRpcGenerator.cs index 424dcff4ec5c..5257ccd7b3b7 100644 --- a/tools/docgen/JsonRpcGenerator.cs +++ b/tools/docgen/JsonRpcGenerator.cs @@ -6,7 +6,6 @@ using Nethermind.JsonRpc.Modules.Evm; using Nethermind.JsonRpc.Modules.Rpc; using Nethermind.JsonRpc.Modules.Subscribe; -using Nethermind.JsonRpc.Modules.Witness; using Newtonsoft.Json; namespace Nethermind.DocGen; @@ -23,8 +22,7 @@ internal static void Generate() typeof(IEvmRpcModule).FullName, typeof(IRpcModule).FullName, typeof(IRpcRpcModule).FullName, - typeof(ISubscribeRpcModule).FullName, - typeof(IWitnessRpcModule).FullName + typeof(ISubscribeRpcModule).FullName }; var types = new[] { "Nethermind.JsonRpc", "Nethermind.Consensus.Clique" } .SelectMany(a => Assembly.Load(a).GetTypes())