diff --git a/.editorconfig b/.editorconfig index 472016080b2..b8d038cba7f 100644 --- a/.editorconfig +++ b/.editorconfig @@ -9,7 +9,7 @@ indent_style = space insert_final_newline = true trim_trailing_whitespace = true -file_header_template = SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited\nSPDX-License-Identifier: LGPL-3.0-only +file_header_template = SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited\nSPDX-License-Identifier: LGPL-3.0-only [*.cs] indent_size = 4 @@ -34,31 +34,31 @@ dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case dotnet_naming_symbols.interface.applicable_kinds = interface dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected -dotnet_naming_symbols.interface.required_modifiers = +dotnet_naming_symbols.interface.required_modifiers = dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected -dotnet_naming_symbols.types.required_modifiers = +dotnet_naming_symbols.types.required_modifiers = dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected -dotnet_naming_symbols.non_field_members.required_modifiers = +dotnet_naming_symbols.non_field_members.required_modifiers = # Naming styles dotnet_naming_style.begins_with_i.required_prefix = I -dotnet_naming_style.begins_with_i.required_suffix = -dotnet_naming_style.begins_with_i.word_separator = +dotnet_naming_style.begins_with_i.required_suffix = +dotnet_naming_style.begins_with_i.word_separator = dotnet_naming_style.begins_with_i.capitalization = pascal_case -dotnet_naming_style.pascal_case.required_prefix = -dotnet_naming_style.pascal_case.required_suffix = -dotnet_naming_style.pascal_case.word_separator = +dotnet_naming_style.pascal_case.required_prefix = +dotnet_naming_style.pascal_case.required_suffix = +dotnet_naming_style.pascal_case.word_separator = dotnet_naming_style.pascal_case.capitalization = pascal_case -dotnet_naming_style.pascal_case.required_prefix = -dotnet_naming_style.pascal_case.required_suffix = -dotnet_naming_style.pascal_case.word_separator = +dotnet_naming_style.pascal_case.required_prefix = +dotnet_naming_style.pascal_case.required_suffix = +dotnet_naming_style.pascal_case.word_separator = dotnet_naming_style.pascal_case.capitalization = pascal_case dotnet_style_operator_placement_when_wrapping = beginning_of_line dotnet_style_coalesce_expression = true:suggestion @@ -88,4 +88,4 @@ csharp_style_expression_bodied_lambdas = true:silent csharp_style_expression_bodied_local_functions = false:silent csharp_style_var_for_built_in_types = true:silent csharp_style_var_when_type_is_apparent = true:suggestion -csharp_style_var_elsewhere = false:suggestion \ No newline at end of file +csharp_style_var_elsewhere = false:suggestion diff --git a/.github/workflows/build-solutions.yml b/.github/workflows/build-solutions.yml index 930bf01e379..f339c0f2920 100644 --- a/.github/workflows/build-solutions.yml +++ b/.github/workflows/build-solutions.yml @@ -6,38 +6,20 @@ on: push: branches: [master] -defaults: - run: - working-directory: src/Nethermind - -env: - BUILD_CONFIG: release - DOTNET_SYSTEM_CONSOLE_ALLOW_ANSI_COLOR_REDIRECTION: 1 - TERM: xterm - jobs: build: name: Build runs-on: ubuntu-latest - permissions: - contents: read + strategy: + matrix: + config: [release, debug] + solution: [Nethermind, EthereumTests, Benchmarks] steps: - name: Check out repository uses: actions/checkout@v4 with: - submodules: true - - name: Install Linux packages - run: sudo apt-get update && sudo apt-get install libsnappy-dev + submodules: ${{ matrix.solution == 'EthereumTests' }} - name: Set up .NET uses: actions/setup-dotnet@v4 - - name: Install dependencies - run: | - dotnet restore Nethermind.sln - dotnet restore EthereumTests.sln - dotnet restore Benchmarks.sln - - name: Build Nethermind.sln - run: dotnet build Nethermind.sln -c ${{ env.BUILD_CONFIG }} --no-restore - - name: Build EthereumTests.sln - run: dotnet build EthereumTests.sln -c ${{ env.BUILD_CONFIG }} --no-restore - - name: Build Benchmarks.sln - run: dotnet build Benchmarks.sln -c ${{ env.BUILD_CONFIG }} --no-restore + - name: Build ${{ matrix.solution }}.sln + run: dotnet build src/Nethermind/${{ matrix.solution }}.sln -c ${{ matrix.config }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 78f12ea5e0a..b344bb08321 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -16,7 +16,7 @@ env: PACKAGE_DIR: pkg PACKAGE_RETENTION: 7 PUB_DIR: pub - SCRIPTS_PATH: ${{ github.workspace }}/nethermind/scripts/deployment + SCRIPTS_PATH: ${{ github.workspace }}/scripts/deployment jobs: build: @@ -116,8 +116,6 @@ jobs: steps: - name: Check out Nethermind repository uses: actions/checkout@v4 - with: - path: nethermind - name: Download artifacts uses: actions/download-artifact@v4 with: @@ -141,8 +139,6 @@ jobs: steps: - name: Check out Nethermind repository uses: actions/checkout@v4 - with: - path: nethermind - name: Download artifacts uses: actions/download-artifact@v4 with: diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 026af98679f..26ef4fd581a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -56,7 +56,7 @@ Branch names must follow `snake_case` pattern. Follow the pattern `Demerzel Solutions Limited Nethermind $(Commit.Substring(0, 8)) - 1.24.0 + 1.26.0 unstable diff --git a/src/Nethermind/Directory.Packages.props b/src/Nethermind/Directory.Packages.props index 2dc7856a8d6..01c8186332e 100644 --- a/src/Nethermind/Directory.Packages.props +++ b/src/Nethermind/Directory.Packages.props @@ -4,12 +4,12 @@ - - - - - - + + + + + + @@ -24,7 +24,7 @@ - + @@ -49,14 +49,14 @@ - + - + @@ -65,15 +65,15 @@ - - + + - + @@ -88,9 +88,9 @@ - - + + - \ No newline at end of file + diff --git a/src/Nethermind/Nethermind.AccountAbstraction.Test/UserOperationSubscribeTests.cs b/src/Nethermind/Nethermind.AccountAbstraction.Test/UserOperationSubscribeTests.cs index 409ed0d0beb..799ee6444db 100644 --- a/src/Nethermind/Nethermind.AccountAbstraction.Test/UserOperationSubscribeTests.cs +++ b/src/Nethermind/Nethermind.AccountAbstraction.Test/UserOperationSubscribeTests.cs @@ -62,7 +62,7 @@ public void Setup() _blockTree = Substitute.For(); _txPool = Substitute.For(); _receiptStorage = Substitute.For(); - _receiptCanonicalityMonitor = new ReceiptCanonicalityMonitor(_blockTree, _receiptStorage, _logManager); + _receiptCanonicalityMonitor = new ReceiptCanonicalityMonitor(_receiptStorage, _logManager); _specProvider = Substitute.For(); _userOperationPools[_testPoolAddress] = Substitute.For(); _filterStore = new FilterStore(); diff --git a/src/Nethermind/Nethermind.AccountAbstraction/Executor/AABlockProducerTransactionsExecutor.cs b/src/Nethermind/Nethermind.AccountAbstraction/Executor/AABlockProducerTransactionsExecutor.cs index e3791db4b03..2066e0b9ac3 100644 --- a/src/Nethermind/Nethermind.AccountAbstraction/Executor/AABlockProducerTransactionsExecutor.cs +++ b/src/Nethermind/Nethermind.AccountAbstraction/Executor/AABlockProducerTransactionsExecutor.cs @@ -56,12 +56,12 @@ public override TxReceipt[] ProcessTransactions( { if (IsAccountAbstractionTransaction(transaction)) { - BlockProcessor.TxAction action = ProcessAccountAbstractionTransaction(block, blkCtx, transaction, i++, receiptsTracer, processingOptions, transactionsInBlock); + BlockProcessor.TxAction action = ProcessAccountAbstractionTransaction(block, in blkCtx, transaction, i++, receiptsTracer, processingOptions, transactionsInBlock); if (action == BlockProcessor.TxAction.Stop) break; } else { - BlockProcessor.TxAction action = ProcessTransaction(block, blkCtx, transaction, i++, receiptsTracer, processingOptions, transactionsInBlock); + BlockProcessor.TxAction action = ProcessTransaction(block, in blkCtx, transaction, i++, receiptsTracer, processingOptions, transactionsInBlock); if (action == BlockProcessor.TxAction.Stop) break; } } @@ -81,7 +81,7 @@ private bool IsAccountAbstractionTransaction(Transaction transaction) private BlockProcessor.TxAction ProcessAccountAbstractionTransaction( Block block, - BlockExecutionContext blkCtx, + in BlockExecutionContext blkCtx, Transaction currentTx, int index, BlockReceiptsTracer receiptsTracer, @@ -90,7 +90,7 @@ private BlockProcessor.TxAction ProcessAccountAbstractionTransaction( { int snapshot = receiptsTracer.TakeSnapshot(); - BlockProcessor.TxAction action = ProcessTransaction(block, blkCtx, currentTx, index, receiptsTracer, processingOptions, transactionsInBlock, false); + BlockProcessor.TxAction action = ProcessTransaction(block, in blkCtx, currentTx, index, receiptsTracer, processingOptions, transactionsInBlock, false); if (action != BlockProcessor.TxAction.Add) { return action; diff --git a/src/Nethermind/Nethermind.Api/IApiWithStores.cs b/src/Nethermind/Nethermind.Api/IApiWithStores.cs index 8a5bfa981d5..f6e02313adc 100644 --- a/src/Nethermind/Nethermind.Api/IApiWithStores.cs +++ b/src/Nethermind/Nethermind.Api/IApiWithStores.cs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LGPL-3.0-only using Nethermind.Blockchain; +using Nethermind.Blockchain.Blocks; using Nethermind.Blockchain.Find; using Nethermind.Blockchain.Receipts; using Nethermind.Consensus; @@ -27,5 +28,6 @@ public interface IApiWithStores : IBasicApi IReceiptFinder? ReceiptFinder { get; set; } IReceiptMonitor? ReceiptMonitor { get; set; } IWallet? Wallet { get; set; } + IBlockStore? BadBlocksStore { get; set; } } } diff --git a/src/Nethermind/Nethermind.Api/IInitConfig.cs b/src/Nethermind/Nethermind.Api/IInitConfig.cs index fa2600c4d5d..c72d7477666 100644 --- a/src/Nethermind/Nethermind.Api/IInitConfig.cs +++ b/src/Nethermind/Nethermind.Api/IInitConfig.cs @@ -74,15 +74,15 @@ public interface IInitConfig : IConfig [ConfigItem(Description = "The hint on the max memory limit, in bytes, to configure the database and networking memory allocations.", DefaultValue = "null")] long? MemoryHint { get; set; } + [ConfigItem(Description = "The maximum number of bad blocks observed on the network that will be stored to disk.", DefaultValue = "100")] + long? BadBlocksStored { get; set; } + [ConfigItem(Description = "[TECHNICAL] Disable garbage collector on newPayload", DefaultValue = "true", HiddenFromDocs = true)] bool DisableGcOnNewPayload { get; set; } [ConfigItem(Description = "[TECHNICAL] Disable setting malloc options. Set to true if using different memory allocator or manually setting malloc opts.", DefaultValue = "false", HiddenFromDocs = true)] bool DisableMallocOpts { get; set; } - [ConfigItem(Description = "Directory with era1 archives from which ancient blocks will be served.", DefaultValue = "", HiddenFromDocs = false)] - string AncientDataDirectory { get; set; } - [ConfigItem(Description = "[TECHNICAL] Exit when block number is reached. Useful for scripting and testing.", DefaultValue = "null", HiddenFromDocs = true)] long? ExitOnBlockNumber { get; set; } } diff --git a/src/Nethermind/Nethermind.Api/InitConfig.cs b/src/Nethermind/Nethermind.Api/InitConfig.cs index 0f34360044c..f594913ae3e 100644 --- a/src/Nethermind/Nethermind.Api/InitConfig.cs +++ b/src/Nethermind/Nethermind.Api/InitConfig.cs @@ -31,6 +31,7 @@ public class InitConfig : IInitConfig public string RpcDbUrl { get; set; } = String.Empty; public long? MemoryHint { get; set; } + public long? BadBlocksStored { get; set; } = 100; public bool DisableGcOnNewPayload { get; set; } = true; public bool DisableMallocOpts { get; set; } = false; public long? ExitOnBlockNumber { get; set; } = null; diff --git a/src/Nethermind/Nethermind.Api/NethermindApi.cs b/src/Nethermind/Nethermind.Api/NethermindApi.cs index 0454db9cd53..37c2bbbd517 100644 --- a/src/Nethermind/Nethermind.Api/NethermindApi.cs +++ b/src/Nethermind/Nethermind.Api/NethermindApi.cs @@ -7,6 +7,7 @@ using Nethermind.Abi; using Nethermind.Api.Extensions; using Nethermind.Blockchain; +using Nethermind.Blockchain.Blocks; using Nethermind.Blockchain.Filters; using Nethermind.Blockchain.Find; using Nethermind.Blockchain.FullPruning; @@ -210,6 +211,7 @@ public ISealEngine SealEngine public IEthSyncingInfo? EthSyncingInfo { get; set; } public IBlockProductionPolicy? BlockProductionPolicy { get; set; } public IWallet? Wallet { get; set; } + public IBlockStore? BadBlocksStore { get; set; } public ITransactionComparerProvider? TransactionComparerProvider { get; set; } public IWebSocketsManager WebSocketsManager { get; set; } = new WebSocketsManager(); diff --git a/src/Nethermind/Nethermind.Blockchain.Test/Producers/BlockProducerBaseTests.BaseFee.cs b/src/Nethermind/Nethermind.Blockchain.Test/Producers/BlockProducerBaseTests.BaseFee.cs index 4e66e5bd708..988136b6896 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/Producers/BlockProducerBaseTests.BaseFee.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/Producers/BlockProducerBaseTests.BaseFee.cs @@ -255,7 +255,7 @@ public async Task BlockProducer_returns_correct_fork_base_fee() .WithEip1559TransitionBlock(7) .CreateTestBlockchain() .BlocksBeforeTransitionShouldHaveZeroBaseFee() - .AssertNewBlock(Eip1559Constants.ForkBaseFee); + .AssertNewBlock(Eip1559Constants.DefaultForkBaseFee); await scenario.Finish(); } @@ -266,7 +266,7 @@ public async Task BlockProducer_returns_correctly_decreases_base_fee_on_empty_bl .WithEip1559TransitionBlock(6) .CreateTestBlockchain() .BlocksBeforeTransitionShouldHaveZeroBaseFee() - .AssertNewBlock(Eip1559Constants.ForkBaseFee) + .AssertNewBlock(Eip1559Constants.DefaultForkBaseFee) .AssertNewBlock(875000000) .AssertNewBlock(765625000) .AssertNewBlock(669921875) @@ -283,7 +283,7 @@ public async Task BaseFee_should_decrease_when_we_send_transactions_below_gas_ta .CreateTestBlockchain(gasLimit) .DeployContract() .BlocksBeforeTransitionShouldHaveZeroBaseFee() - .AssertNewBlock(Eip1559Constants.ForkBaseFee) + .AssertNewBlock(Eip1559Constants.DefaultForkBaseFee) .SendLegacyTransaction(gasLimit / 3, 20.GWei()) .SendEip1559Transaction(gasLimit / 3, 1.GWei(), 20.GWei()) .AssertNewBlock(875000000) @@ -301,7 +301,7 @@ public async Task BaseFee_should_not_change_when_we_send_transactions_equal_gas_ .CreateTestBlockchain(gasTarget) .DeployContract() .BlocksBeforeTransitionShouldHaveZeroBaseFee() - .AssertNewBlock(Eip1559Constants.ForkBaseFee) + .AssertNewBlock(Eip1559Constants.DefaultForkBaseFee) .SendLegacyTransaction(gasTarget / 2, 20.GWei()) .SendEip1559Transaction(gasTarget / 2, 1.GWei(), 20.GWei()) .AssertNewBlock(875000000) @@ -319,7 +319,7 @@ public async Task BaseFee_should_increase_when_we_send_transactions_above_gas_ta .CreateTestBlockchain(gasTarget) .DeployContract() .BlocksBeforeTransitionShouldHaveZeroBaseFee() - .AssertNewBlock(Eip1559Constants.ForkBaseFee) + .AssertNewBlock(Eip1559Constants.DefaultForkBaseFee) .SendLegacyTransaction(gasTarget / 2, 20.GWei()) .SendEip1559Transaction(gasTarget / 2, 1.GWei(), 20.GWei()) .SendLegacyTransaction(gasTarget / 2, 20.GWei()) @@ -337,7 +337,7 @@ public async Task When_base_fee_decreases_previously_fee_too_low_transaction_is_ .WithEip1559TransitionBlock(6) .CreateTestBlockchain(gasTarget) .BlocksBeforeTransitionShouldHaveZeroBaseFee() - .AssertNewBlock(Eip1559Constants.ForkBaseFee) + .AssertNewBlock(Eip1559Constants.DefaultForkBaseFee) .SendLegacyTransaction(gasTarget / 2, 7.GWei() / 10, nonce: UInt256.Zero) .AssertNewBlock(875000000) .AssertNewBlock(765625000) diff --git a/src/Nethermind/Nethermind.Blockchain.Test/Receipts/PersistentReceiptStorageTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/Receipts/PersistentReceiptStorageTests.cs index aa0c2f505e0..6269c21cbb7 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/Receipts/PersistentReceiptStorageTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/Receipts/PersistentReceiptStorageTests.cs @@ -290,17 +290,22 @@ public void When_TxLookupLimitIs_NegativeOne_DoNotIndexTxHash() _receiptsDb.GetColumnDb(ReceiptsColumns.Transactions)[receipts[0].TxHash!.Bytes].Should().BeNull(); } - [Test] - public void Should_not_index_tx_hash_if_blockNumber_is_negative() + [TestCase(1L, false)] + [TestCase(10L, false)] + [TestCase(11L, true)] + public void Should_only_prune_index_tx_hashes_if_blockNumber_is_bigger_than_lookupLimit(long blockNumber, bool WillPruneOldIndicies) { _receiptConfig.TxLookupLimit = 10; CreateStorage(); _blockTree.BlockAddedToMain += - Raise.EventWith(new BlockReplacementEventArgs(Build.A.Block.WithNumber(1).TestObject)); + Raise.EventWith(new BlockReplacementEventArgs(Build.A.Block.WithNumber(blockNumber).TestObject)); Thread.Sleep(100); IEnumerable calls = _blockTree.ReceivedCalls() - .Where(call => !call.GetMethodInfo().Name.EndsWith(nameof(_blockTree.BlockAddedToMain))); - calls.Should().BeEmpty(); + .Where(call => call.GetMethodInfo().Name.EndsWith(nameof(_blockTree.FindBlock))); + if (WillPruneOldIndicies) + calls.Should().NotBeEmpty(); + else + calls.Should().BeEmpty(); } [Test] @@ -342,27 +347,49 @@ public void When_NewHeadBlock_Remove_TxIndex_OfRemovedBlock() [Test] public async Task When_NewHeadBlock_Remove_TxIndex_OfRemovedBlock_Unless_ItsAlsoInNewBlock() { + _receiptConfig.CompactTxIndex = _useCompactReceipts; CreateStorage(); (Block block, TxReceipt[] receipts) = InsertBlock(); + Block block2 = Build.A.Block + .WithParent(block) + .WithNumber(2) + .WithTransactions(Build.A.Transaction.SignedAndResolved(TestItem.PrivateKeyC).TestObject) + .TestObject; + _blockTree.FindBestSuggestedHeader().Returns(block2.Header); + _blockTree.BlockAddedToMain += Raise.EventWith(new BlockReplacementEventArgs(block2)); if (_receiptConfig.CompactTxIndex) { - _receiptsDb.GetColumnDb(ReceiptsColumns.Transactions)[receipts[0].TxHash!.Bytes].Should().BeEquivalentTo(Rlp.Encode(block.Number).Bytes); + _receiptsDb.GetColumnDb(ReceiptsColumns.Transactions)[block.Transactions[0].Hash!.Bytes].Should().BeEquivalentTo(Rlp.Encode(block.Number).Bytes); } else { - _receiptsDb.GetColumnDb(ReceiptsColumns.Transactions)[receipts[0].TxHash!.Bytes].Should().NotBeNull(); + _receiptsDb.GetColumnDb(ReceiptsColumns.Transactions)[block.Transactions[0].Hash!.Bytes].Should().BeEquivalentTo(block.Hash!.Bytes.ToArray()); } - Block newHead = Build.A.Block + Block block3 = Build.A.Block .WithNumber(1) + .WithTransactions(block2.Transactions) + .WithExtraData(new byte[1]) + .TestObject; + Block block4 = Build.A.Block + .WithNumber(2) .WithTransactions(block.Transactions) + .WithExtraData(new byte[1]) .TestObject; - _blockTree.FindBestSuggestedHeader().Returns(newHead.Header); - _blockTree.BlockAddedToMain += Raise.EventWith(new BlockReplacementEventArgs(newHead, block)); + _blockTree.FindBestSuggestedHeader().Returns(block4.Header); + _blockTree.BlockAddedToMain += Raise.EventWith(new BlockReplacementEventArgs(block3, block)); + _blockTree.BlockAddedToMain += Raise.EventWith(new BlockReplacementEventArgs(block4, block2)); await Task.Delay(100); - _receiptsDb.GetColumnDb(ReceiptsColumns.Transactions)[receipts[0].TxHash!.Bytes].Should().NotBeNull(); + if (_receiptConfig.CompactTxIndex) + { + _receiptsDb.GetColumnDb(ReceiptsColumns.Transactions)[block4.Transactions[0].Hash!.Bytes].Should().BeEquivalentTo(Rlp.Encode(block4.Number).Bytes); + } + else + { + _receiptsDb.GetColumnDb(ReceiptsColumns.Transactions)[block4.Transactions[0].Hash!.Bytes].Should().BeEquivalentTo(block4.Hash!.Bytes.ToArray()); + } } [Test] diff --git a/src/Nethermind/Nethermind.Blockchain/BlockTree.cs b/src/Nethermind/Nethermind.Blockchain/BlockTree.cs index 4a7eefa42fb..368f6201ea8 100644 --- a/src/Nethermind/Nethermind.Blockchain/BlockTree.cs +++ b/src/Nethermind/Nethermind.Blockchain/BlockTree.cs @@ -43,6 +43,7 @@ public partial class BlockTree : IBlockTree private readonly IHeaderStore _headerStore; private readonly IDb _blockInfoDb; private readonly IDb _metadataDb; + private readonly IBlockStore _badBlockStore; private readonly LruCache _invalidBlocks = new(128, 128, "invalid blocks"); @@ -110,6 +111,7 @@ public BlockTree( IHeaderStore? headerDb, IDb? blockInfoDb, IDb? metadataDb, + IBlockStore? badBlockStore, IChainLevelInfoRepository? chainLevelInfoRepository, ISpecProvider? specProvider, IBloomStorage? bloomStorage, @@ -121,6 +123,7 @@ public BlockTree( _headerStore = headerDb ?? throw new ArgumentNullException(nameof(headerDb)); _blockInfoDb = blockInfoDb ?? throw new ArgumentNullException(nameof(blockInfoDb)); _metadataDb = metadataDb ?? throw new ArgumentNullException(nameof(metadataDb)); + _badBlockStore = badBlockStore ?? throw new ArgumentNullException(nameof(badBlockStore)); _specProvider = specProvider ?? throw new ArgumentNullException(nameof(specProvider)); _bloomStorage = bloomStorage ?? throw new ArgumentNullException(nameof(bloomStorage)); _syncConfig = syncConfig ?? throw new ArgumentNullException(nameof(syncConfig)); @@ -710,6 +713,7 @@ public void DeleteInvalidBlock(Block invalidBlock) if (_logger.IsDebug) _logger.Debug($"Deleting invalid block {invalidBlock.ToString(Block.Format.FullHashAndNumber)}"); _invalidBlocks.Set(invalidBlock.Hash, invalidBlock); + _badBlockStore.Insert(invalidBlock); BestSuggestedHeader = Head?.Header; BestSuggestedBody = Head; diff --git a/src/Nethermind/Nethermind.Blockchain/Blocks/BlockStore.cs b/src/Nethermind/Nethermind.Blockchain/Blocks/BlockStore.cs index 830223ec0ab..67bf3d902b1 100644 --- a/src/Nethermind/Nethermind.Blockchain/Blocks/BlockStore.cs +++ b/src/Nethermind/Nethermind.Blockchain/Blocks/BlockStore.cs @@ -3,6 +3,8 @@ using System; using System.Buffers; +using System.Collections.Generic; +using System.Linq; using Nethermind.Core; using Nethermind.Core.Caching; using Nethermind.Core.Crypto; @@ -20,10 +22,12 @@ public class BlockStore : IBlockStore private readonly LruCache _blockCache = new(CacheSize, CacheSize, "blocks"); + private long? _maxSize; - public BlockStore(IDb blockDb) + public BlockStore(IDb blockDb, long? maxSize = null) { _blockDb = blockDb; + _maxSize = maxSize; } public void SetMetadata(byte[] key, byte[] value) @@ -36,6 +40,18 @@ public void SetMetadata(byte[] key, byte[] value) return _blockDb.Get(key); } + private void TruncateToMaxSize() + { + int toDelete = (int)(_blockDb.GetSize() - _maxSize!); + if (toDelete > 0) + { + foreach (var blockToDelete in GetAll().Take(toDelete)) + { + Delete(blockToDelete.Number, blockToDelete.Hash); + } + } + } + public void Insert(Block block, WriteFlags writeFlags = WriteFlags.None) { if (block.Hash is null) @@ -48,6 +64,11 @@ public void Insert(Block block, WriteFlags writeFlags = WriteFlags.None) using NettyRlpStream newRlp = _blockDecoder.EncodeToNewNettyStream(block); _blockDb.Set(block.Number, block.Hash, newRlp.AsSpan(), writeFlags); + + if (_maxSize is not null) + { + TruncateToMaxSize(); + } } private static void GetBlockNumPrefixedKey(long blockNumber, Hash256 blockHash, Span output) @@ -88,4 +109,9 @@ public void Cache(Block block) { _blockCache.Set(block.Hash, block); } + + public IEnumerable GetAll() + { + return _blockDb.GetAllValues(true).Select(bytes => _blockDecoder.Decode(bytes.AsRlpStream())); + } } diff --git a/src/Nethermind/Nethermind.Blockchain/Blocks/IBlockStore.cs b/src/Nethermind/Nethermind.Blockchain/Blocks/IBlockStore.cs index a84f2c5fe4a..6621182c949 100644 --- a/src/Nethermind/Nethermind.Blockchain/Blocks/IBlockStore.cs +++ b/src/Nethermind/Nethermind.Blockchain/Blocks/IBlockStore.cs @@ -1,6 +1,7 @@ // SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only +using System.Collections.Generic; using Nethermind.Core; using Nethermind.Core.Crypto; using Nethermind.Serialization.Rlp; @@ -16,6 +17,7 @@ public interface IBlockStore void Insert(Block block, WriteFlags writeFlags = WriteFlags.None); void Delete(long blockNumber, Hash256 blockHash); Block? Get(long blockNumber, Hash256 blockHash, bool shouldCache = true); + IEnumerable GetAll(); ReceiptRecoveryBlock? GetReceiptRecoveryBlock(long blockNumber, Hash256 blockHash); void Cache(Block block); diff --git a/src/Nethermind/Nethermind.Blockchain/ReceiptCanonicalityMonitor.cs b/src/Nethermind/Nethermind.Blockchain/ReceiptCanonicalityMonitor.cs index d6d35d8b0ef..4d6b55283d9 100644 --- a/src/Nethermind/Nethermind.Blockchain/ReceiptCanonicalityMonitor.cs +++ b/src/Nethermind/Nethermind.Blockchain/ReceiptCanonicalityMonitor.cs @@ -16,24 +16,20 @@ public interface IReceiptMonitor : IDisposable public class ReceiptCanonicalityMonitor : IReceiptMonitor { - private readonly IBlockTree _blockTree; private readonly IReceiptStorage _receiptStorage; private readonly ILogger _logger; public event EventHandler? ReceiptsInserted; - public ReceiptCanonicalityMonitor(IBlockTree? blockTree, IReceiptStorage? receiptStorage, ILogManager? logManager) + public ReceiptCanonicalityMonitor(IReceiptStorage? receiptStorage, ILogManager? logManager) { - _blockTree = blockTree ?? throw new ArgumentNullException(nameof(blockTree)); _receiptStorage = receiptStorage ?? throw new ArgumentNullException(nameof(receiptStorage)); _logger = logManager?.GetClassLogger() ?? throw new ArgumentNullException(nameof(logManager)); - _blockTree.BlockAddedToMain += OnBlockAddedToMain; + _receiptStorage.ReceiptsInserted += OnBlockAddedToMain; } private void OnBlockAddedToMain(object sender, BlockReplacementEventArgs e) { - _receiptStorage.EnsureCanonical(e.Block); - // we don't want this to be on main processing thread Task.Run(() => TriggerReceiptInsertedEvent(e.Block, e.PreviousBlock)); } @@ -59,7 +55,7 @@ private void TriggerReceiptInsertedEvent(Block newBlock, Block? previousBlock) public void Dispose() { - _blockTree.BlockAddedToMain -= OnBlockAddedToMain; + _receiptStorage.ReceiptsInserted -= OnBlockAddedToMain; } } } diff --git a/src/Nethermind/Nethermind.Blockchain/Receipts/IReceiptStorage.cs b/src/Nethermind/Nethermind.Blockchain/Receipts/IReceiptStorage.cs index f1abcef89c9..236540cbe48 100644 --- a/src/Nethermind/Nethermind.Blockchain/Receipts/IReceiptStorage.cs +++ b/src/Nethermind/Nethermind.Blockchain/Receipts/IReceiptStorage.cs @@ -3,6 +3,7 @@ using Nethermind.Core; using Nethermind.Core.Crypto; +using System; namespace Nethermind.Blockchain.Receipts { @@ -14,5 +15,10 @@ public interface IReceiptStorage : IReceiptFinder long MigratedBlockNumber { get; set; } bool HasBlock(long blockNumber, Hash256 hash); void EnsureCanonical(Block block); + + /// + /// Receipts for a block are inserted + /// + event EventHandler ReceiptsInserted; } } diff --git a/src/Nethermind/Nethermind.Blockchain/Receipts/InMemoryReceiptStorage.cs b/src/Nethermind/Nethermind.Blockchain/Receipts/InMemoryReceiptStorage.cs index a118a0aec87..4b78996a0ac 100644 --- a/src/Nethermind/Nethermind.Blockchain/Receipts/InMemoryReceiptStorage.cs +++ b/src/Nethermind/Nethermind.Blockchain/Receipts/InMemoryReceiptStorage.cs @@ -11,13 +11,27 @@ namespace Nethermind.Blockchain.Receipts public class InMemoryReceiptStorage : IReceiptStorage { private readonly bool _allowReceiptIterator; + private readonly IBlockTree? _blockTree; private readonly ConcurrentDictionary _receipts = new(); private readonly ConcurrentDictionary _transactions = new(); - public InMemoryReceiptStorage(bool allowReceiptIterator = true) +#pragma warning disable CS0067 + public event EventHandler ReceiptsInserted; +#pragma warning restore CS0067 + + public InMemoryReceiptStorage(bool allowReceiptIterator = true, IBlockTree? blockTree = null) { _allowReceiptIterator = allowReceiptIterator; + _blockTree = blockTree; + if (_blockTree is not null) + _blockTree.BlockAddedToMain += BlockTree_BlockAddedToMain; + } + + private void BlockTree_BlockAddedToMain(object? sender, BlockReplacementEventArgs e) + { + EnsureCanonical(e.Block); + ReceiptsInserted?.Invoke(this, e); } public Hash256 FindBlockHash(Hash256 txHash) diff --git a/src/Nethermind/Nethermind.Blockchain/Receipts/NullReceiptStorage.cs b/src/Nethermind/Nethermind.Blockchain/Receipts/NullReceiptStorage.cs index 22f6b7fdc21..802c8d858e5 100644 --- a/src/Nethermind/Nethermind.Blockchain/Receipts/NullReceiptStorage.cs +++ b/src/Nethermind/Nethermind.Blockchain/Receipts/NullReceiptStorage.cs @@ -11,6 +11,10 @@ public class NullReceiptStorage : IReceiptStorage { public static NullReceiptStorage Instance { get; } = new(); +#pragma warning disable CS0067 + public event EventHandler ReceiptsInserted; +#pragma warning restore CS0067 + public Hash256? FindBlockHash(Hash256 hash) => null; private NullReceiptStorage() diff --git a/src/Nethermind/Nethermind.Blockchain/Receipts/PersistentReceiptStorage.cs b/src/Nethermind/Nethermind.Blockchain/Receipts/PersistentReceiptStorage.cs index ca972f1aa9a..a186d13d1d2 100644 --- a/src/Nethermind/Nethermind.Blockchain/Receipts/PersistentReceiptStorage.cs +++ b/src/Nethermind/Nethermind.Blockchain/Receipts/PersistentReceiptStorage.cs @@ -39,6 +39,8 @@ public class PersistentReceiptStorage : IReceiptStorage private const int CacheSize = 64; private readonly LruCache _receiptsCache = new(CacheSize, CacheSize, "receipts"); + public event EventHandler ReceiptsInserted; + public PersistentReceiptStorage( IColumnsDb receiptsDb, ISpecProvider specProvider, @@ -78,6 +80,8 @@ private void BlockTreeOnBlockAddedToMain(object? sender, BlockReplacementEventAr { RemoveBlockTx(e.PreviousBlock, e.Block); } + EnsureCanonical(e.Block); + ReceiptsInserted?.Invoke(this, e); // Dont block main loop Task.Run(() => diff --git a/src/Nethermind/Nethermind.Consensus.Test/TargetAdjustedGasLimitCalculatorTests.cs b/src/Nethermind/Nethermind.Consensus.Test/TargetAdjustedGasLimitCalculatorTests.cs index d3006e499c7..2f96501987d 100644 --- a/src/Nethermind/Nethermind.Consensus.Test/TargetAdjustedGasLimitCalculatorTests.cs +++ b/src/Nethermind/Nethermind.Consensus.Test/TargetAdjustedGasLimitCalculatorTests.cs @@ -27,7 +27,7 @@ public void Is_bump_on_1559_eip_block() TargetAdjustedGasLimitCalculator targetedAdjustedGasLimitCalculator = new(specProvider, new BlocksConfig()); BlockHeader header = Build.A.BlockHeader.WithNumber(londonBlock - 1).WithGasLimit(gasLimit).TestObject; long actualValue = targetedAdjustedGasLimitCalculator.GetGasLimit(header); - Assert.That(actualValue, Is.EqualTo(gasLimit * Eip1559Constants.ElasticityMultiplier)); + Assert.That(actualValue, Is.EqualTo(gasLimit * Eip1559Constants.DefaultElasticityMultiplier)); } } } diff --git a/src/Nethermind/Nethermind.Consensus/Eip1559GasLimitAdjuster.cs b/src/Nethermind/Nethermind.Consensus/Eip1559GasLimitAdjuster.cs index 3c1ecb4138f..98e15179438 100644 --- a/src/Nethermind/Nethermind.Consensus/Eip1559GasLimitAdjuster.cs +++ b/src/Nethermind/Nethermind.Consensus/Eip1559GasLimitAdjuster.cs @@ -14,7 +14,7 @@ public static long AdjustGasLimit(IReleaseSpec releaseSpec, long gasLimit, long long adjustedGasLimit = gasLimit; if (releaseSpec.Eip1559TransitionBlock == blockNumber) { - adjustedGasLimit *= Eip1559Constants.ElasticityMultiplier; + adjustedGasLimit *= releaseSpec.ElasticityMultiplier; } return adjustedGasLimit; diff --git a/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.BlockProductionTransactionsExecutor.cs b/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.BlockProductionTransactionsExecutor.cs index f794d3b64b6..fdaab77ccdb 100644 --- a/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.BlockProductionTransactionsExecutor.cs +++ b/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.BlockProductionTransactionsExecutor.cs @@ -79,7 +79,7 @@ public virtual TxReceipt[] ProcessTransactions(Block block, ProcessingOptions pr BlockExecutionContext blkCtx = new(block.Header); foreach (Transaction currentTx in transactions) { - TxAction action = ProcessTransaction(block, blkCtx, currentTx, i++, receiptsTracer, processingOptions, transactionsInBlock); + TxAction action = ProcessTransaction(block, in blkCtx, currentTx, i++, receiptsTracer, processingOptions, transactionsInBlock); if (action == TxAction.Stop) break; } @@ -91,7 +91,7 @@ public virtual TxReceipt[] ProcessTransactions(Block block, ProcessingOptions pr protected TxAction ProcessTransaction( Block block, - BlockExecutionContext blkCtx, + in BlockExecutionContext blkCtx, Transaction currentTx, int index, BlockReceiptsTracer receiptsTracer, @@ -109,7 +109,7 @@ protected TxAction ProcessTransaction( } else { - _transactionProcessor.ProcessTransaction(blkCtx, currentTx, receiptsTracer, processingOptions, _stateProvider); + _transactionProcessor.ProcessTransaction(in blkCtx, currentTx, receiptsTracer, processingOptions, _stateProvider); if (addToBlock) { diff --git a/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.BlockValidationTransactionsExecutor.cs b/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.BlockValidationTransactionsExecutor.cs index 116ba87a90c..e520562d4e2 100644 --- a/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.BlockValidationTransactionsExecutor.cs +++ b/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.BlockValidationTransactionsExecutor.cs @@ -39,14 +39,14 @@ public TxReceipt[] ProcessTransactions(Block block, ProcessingOptions processing for (int i = 0; i < block.Transactions.Length; i++) { Transaction currentTx = block.Transactions[i]; - ProcessTransaction(blkCtx, currentTx, i, receiptsTracer, processingOptions); + ProcessTransaction(in blkCtx, currentTx, i, receiptsTracer, processingOptions); } return receiptsTracer.TxReceipts.ToArray(); } - private void ProcessTransaction(BlockExecutionContext blkCtx, Transaction currentTx, int index, BlockReceiptsTracer receiptsTracer, ProcessingOptions processingOptions) + private void ProcessTransaction(in BlockExecutionContext blkCtx, Transaction currentTx, int index, BlockReceiptsTracer receiptsTracer, ProcessingOptions processingOptions) { - _transactionProcessor.ProcessTransaction(blkCtx, currentTx, receiptsTracer, processingOptions, _stateProvider); + _transactionProcessor.ProcessTransaction(in blkCtx, currentTx, receiptsTracer, processingOptions, _stateProvider); TransactionProcessed?.Invoke(this, new TxProcessedEventArgs(index, currentTx, receiptsTracer.TxReceipts[index])); } } diff --git a/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs b/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs index 232c125c38b..f7f5bd8c803 100644 --- a/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs +++ b/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs @@ -43,7 +43,7 @@ public partial class BlockProcessor : IBlockProcessor /// We use a single receipt tracer for all blocks. Internally receipt tracer forwards most of the calls /// to any block-specific tracers. /// - private readonly BlockReceiptsTracer _receiptsTracer; + protected BlockReceiptsTracer ReceiptsTracer { get; set; } public BlockProcessor( ISpecProvider? specProvider, @@ -67,7 +67,7 @@ public BlockProcessor( _blockTransactionsExecutor = blockTransactionsExecutor ?? throw new ArgumentNullException(nameof(blockTransactionsExecutor)); _beaconBlockRootHandler = new BeaconBlockRootHandler(); - _receiptsTracer = new BlockReceiptsTracer(); + ReceiptsTracer = new BlockReceiptsTracer(); } public event EventHandler BlockProcessed; @@ -226,13 +226,13 @@ protected virtual TxReceipt[] ProcessBlock( { IReleaseSpec spec = _specProvider.GetSpec(block.Header); - _receiptsTracer.SetOtherTracer(blockTracer); - _receiptsTracer.StartNewBlockTrace(block); + ReceiptsTracer.SetOtherTracer(blockTracer); + ReceiptsTracer.StartNewBlockTrace(block); _beaconBlockRootHandler.ApplyContractStateChanges(block, spec, _stateProvider); _stateProvider.Commit(spec); - TxReceipt[] receipts = _blockTransactionsExecutor.ProcessTransactions(block, options, _receiptsTracer, spec); + TxReceipt[] receipts = _blockTransactionsExecutor.ProcessTransactions(block, options, ReceiptsTracer, spec); if (spec.IsEip4844Enabled) { @@ -242,7 +242,7 @@ protected virtual TxReceipt[] ProcessBlock( block.Header.ReceiptsRoot = receipts.GetReceiptsRoot(spec, block.ReceiptsRoot); ApplyMinerRewards(block, blockTracer, spec); _withdrawalProcessor.ProcessWithdrawals(block, spec); - _receiptsTracer.EndBlockTrace(); + ReceiptsTracer.EndBlockTrace(); _stateProvider.Commit(spec); @@ -260,7 +260,7 @@ protected virtual TxReceipt[] ProcessBlock( // TODO: block processor pipeline private void StoreTxReceipts(Block block, TxReceipt[] txReceipts) { - // Setting canonical is done by ReceiptCanonicalityMonitor on block move to main + // Setting canonical is done when the BlockAddedToMain event is firec _receiptStorage.Insert(block, txReceipts, false); } diff --git a/src/Nethermind/Nethermind.Consensus/Processing/ProcessingStats.cs b/src/Nethermind/Nethermind.Consensus/Processing/ProcessingStats.cs index 5f29f9af04e..ed6d13e5520 100644 --- a/src/Nethermind/Nethermind.Consensus/Processing/ProcessingStats.cs +++ b/src/Nethermind/Nethermind.Consensus/Processing/ProcessingStats.cs @@ -124,7 +124,7 @@ public void UpdateStats(Block? block, IBlockTree blockTreeCtx, int recoveryQueue decimal bps = chunkMicroseconds == 0 ? -1 : chunkBlocks / chunkMicroseconds * 1000 * 1000; decimal chunkMs = (chunkMicroseconds == 0 ? -1 : chunkMicroseconds / 1000); decimal runMs = (runMicroseconds == 0 ? -1 : runMicroseconds / 1000); - string blockGas = Evm.Metrics.BlockMinGasPrice != decimal.MaxValue ? $" Gas gwei: {Evm.Metrics.BlockMinGasPrice:N2} .. {whiteText}{Math.Max(Evm.Metrics.BlockMinGasPrice, Evm.Metrics.BlockEstMedianGasPrice):N2}{resetColor} ({Evm.Metrics.BlockAveGasPrice:N2}) .. {Evm.Metrics.BlockMaxGasPrice:N2}" : ""; + string blockGas = Evm.Metrics.BlockMinGasPrice != float.MaxValue ? $" Gas gwei: {Evm.Metrics.BlockMinGasPrice:N2} .. {whiteText}{Math.Max(Evm.Metrics.BlockMinGasPrice, Evm.Metrics.BlockEstMedianGasPrice):N2}{resetColor} ({Evm.Metrics.BlockAveGasPrice:N2}) .. {Evm.Metrics.BlockMaxGasPrice:N2}" : ""; if (chunkBlocks > 1) { _logger.Info($"Processed {block.Number - chunkBlocks + 1,9}...{block.Number,9} | {chunkMs,9:N2} ms | slot {runMs,7:N0} ms |{blockGas}"); diff --git a/src/Nethermind/Nethermind.Consensus/Processing/RecoverSignature.cs b/src/Nethermind/Nethermind.Consensus/Processing/RecoverSignature.cs index c9e6d56dcb6..b39602df51b 100644 --- a/src/Nethermind/Nethermind.Consensus/Processing/RecoverSignature.cs +++ b/src/Nethermind/Nethermind.Consensus/Processing/RecoverSignature.cs @@ -58,7 +58,15 @@ public void RecoverData(Block block) // Don't access txPool in Parallel loop as increases contention foreach (Transaction blockTransaction in block.Transactions.Where(tx => tx.IsSigned && tx.SenderAddress is null)) { - _txPool.TryGetPendingTransaction(blockTransaction.Hash, out Transaction? transaction); + Transaction? transaction = null; + try + { + _txPool.TryGetPendingTransaction(blockTransaction.Hash, out transaction); + } + catch (Exception e) + { + if (_logger.IsError) _logger.Error($"An error occured while getting pending a transaction from TxPool, Transaction: {blockTransaction}", e); + } Address sender = transaction?.SenderAddress; if (sender != null) diff --git a/src/Nethermind/Nethermind.Consensus/Processing/TransactionProcessorAdapterExtensions.cs b/src/Nethermind/Nethermind.Consensus/Processing/TransactionProcessorAdapterExtensions.cs index 7e92e41dd13..9b57646922a 100644 --- a/src/Nethermind/Nethermind.Consensus/Processing/TransactionProcessorAdapterExtensions.cs +++ b/src/Nethermind/Nethermind.Consensus/Processing/TransactionProcessorAdapterExtensions.cs @@ -12,7 +12,7 @@ namespace Nethermind.Consensus.Processing; internal static class TransactionProcessorAdapterExtensions { public static void ProcessTransaction(this ITransactionProcessorAdapter transactionProcessor, - BlockExecutionContext blkCtx, + in BlockExecutionContext blkCtx, Transaction currentTx, BlockReceiptsTracer receiptsTracer, ProcessingOptions processingOptions, @@ -24,7 +24,7 @@ public static void ProcessTransaction(this ITransactionProcessorAdapter transact } using ITxTracer tracer = receiptsTracer.StartNewTxTrace(currentTx); - transactionProcessor.Execute(currentTx, blkCtx, receiptsTracer); + transactionProcessor.Execute(currentTx, in blkCtx, receiptsTracer); receiptsTracer.EndTxTrace(); } } diff --git a/src/Nethermind/Nethermind.Core.Test/BlockHeaderTests.cs b/src/Nethermind/Nethermind.Core.Test/BlockHeaderTests.cs index b2c59314889..849c25d3364 100644 --- a/src/Nethermind/Nethermind.Core.Test/BlockHeaderTests.cs +++ b/src/Nethermind/Nethermind.Core.Test/BlockHeaderTests.cs @@ -114,10 +114,13 @@ public void Eip_1559_CalculateBaseFee(long gasTarget, long baseFee, long expecte IReleaseSpec releaseSpec = Substitute.For(); releaseSpec.IsEip1559Enabled.Returns(true); releaseSpec.Eip1559BaseFeeMinValue.Returns((UInt256?)minimalBaseFee); + releaseSpec.ForkBaseFee.Returns(Eip1559Constants.DefaultForkBaseFee); + releaseSpec.BaseFeeMaxChangeDenominator.Returns(Eip1559Constants.DefaultBaseFeeMaxChangeDenominator); + releaseSpec.ElasticityMultiplier.Returns(Eip1559Constants.DefaultElasticityMultiplier); BlockHeader blockHeader = Build.A.BlockHeader.TestObject; blockHeader.Number = 2001; - blockHeader.GasLimit = gasTarget * Eip1559Constants.ElasticityMultiplier; + blockHeader.GasLimit = gasTarget * Eip1559Constants.DefaultElasticityMultiplier; blockHeader.BaseFeePerGas = (UInt256)baseFee; blockHeader.GasUsed = gasUsed; UInt256 actualBaseFee = BaseFeeCalculator.Calculate(blockHeader, releaseSpec); @@ -141,10 +144,13 @@ public void Eip_1559_CalculateBaseFee_shared_test_cases((BaseFeeTestCases Info, { IReleaseSpec releaseSpec = Substitute.For(); releaseSpec.IsEip1559Enabled.Returns(true); + releaseSpec.ForkBaseFee.Returns(Eip1559Constants.DefaultForkBaseFee); + releaseSpec.BaseFeeMaxChangeDenominator.Returns(Eip1559Constants.DefaultBaseFeeMaxChangeDenominator); + releaseSpec.ElasticityMultiplier.Returns(Eip1559Constants.DefaultElasticityMultiplier); BlockHeader blockHeader = Build.A.BlockHeader.TestObject; blockHeader.Number = 2001; - blockHeader.GasLimit = testCase.Info.ParentTargetGasUsed * Eip1559Constants.ElasticityMultiplier; + blockHeader.GasLimit = testCase.Info.ParentTargetGasUsed * Eip1559Constants.DefaultElasticityMultiplier; blockHeader.BaseFeePerGas = (UInt256)testCase.Info.ParentBaseFee; blockHeader.GasUsed = testCase.Info.ParentGasUsed; UInt256 actualBaseFee = BaseFeeCalculator.Calculate(blockHeader, releaseSpec); diff --git a/src/Nethermind/Nethermind.Core.Test/Blockchain/TestBlockchain.cs b/src/Nethermind/Nethermind.Core.Test/Blockchain/TestBlockchain.cs index 4c83df1211f..4215fda3fa3 100644 --- a/src/Nethermind/Nethermind.Core.Test/Blockchain/TestBlockchain.cs +++ b/src/Nethermind/Nethermind.Core.Test/Blockchain/TestBlockchain.cs @@ -160,13 +160,13 @@ protected virtual async Task Build(ISpecProvider? specProvider = _trieStoreWatcher = new TrieStoreBoundaryWatcher(WorldStateManager, BlockTree, LogManager); - ReceiptStorage = new InMemoryReceiptStorage(); + ReceiptStorage = new InMemoryReceiptStorage(blockTree: BlockTree); VirtualMachine virtualMachine = new(new BlockhashProvider(BlockTree, LogManager), SpecProvider, LogManager); TxProcessor = new TransactionProcessor(SpecProvider, State, virtualMachine, LogManager); BlockPreprocessorStep = new RecoverSignatures(EthereumEcdsa, TxPool, SpecProvider, LogManager); HeaderValidator = new HeaderValidator(BlockTree, Always.Valid, SpecProvider, LogManager); - new ReceiptCanonicalityMonitor(BlockTree, ReceiptStorage, LogManager); + new ReceiptCanonicalityMonitor(ReceiptStorage, LogManager); BlockValidator = new BlockValidator( new TxValidator(SpecProvider.ChainId), diff --git a/src/Nethermind/Nethermind.Core.Test/Builders/BlockTreeBuilder.cs b/src/Nethermind/Nethermind.Core.Test/Builders/BlockTreeBuilder.cs index 56433437a71..b61e4b993f7 100644 --- a/src/Nethermind/Nethermind.Core.Test/Builders/BlockTreeBuilder.cs +++ b/src/Nethermind/Nethermind.Core.Test/Builders/BlockTreeBuilder.cs @@ -47,6 +47,7 @@ public BlockTreeBuilder(Block genesisBlock, ISpecProvider specProvider) BlockNumbersDb = new TestMemDb(); BlockInfoDb = new TestMemDb(); MetadataDb = new TestMemDb(); + BadBlocksDb = new TestMemDb(); _genesisBlock = genesisBlock; _specProvider = specProvider; @@ -79,6 +80,7 @@ public BlockTree BlockTree HeaderStore, BlockInfoDb, MetadataDb, + BadBlockStore, ChainLevelInfoRepository, _specProvider, BloomStorage, @@ -105,6 +107,7 @@ protected override void BeforeReturn() public ISyncConfig SyncConfig { get; set; } = new SyncConfig(); public IDb BlocksDb { get; set; } + public IDb BadBlocksDb { get; set; } private IBlockStore? _blockStore; public IBlockStore BlockStore @@ -139,6 +142,18 @@ public IHeaderStore HeaderStore public IDb MetadataDb { get; set; } + private IBlockStore? _badBlockStore; + public IBlockStore BadBlockStore + { + get + { + return _badBlockStore ??= new BlockStore(BadBlocksDb, 100); + } + set + { + _badBlockStore = value; + } + } private IChainLevelInfoRepository? _chainLevelInfoRepository; public IChainLevelInfoRepository ChainLevelInfoRepository @@ -384,6 +399,18 @@ public BlockTreeBuilder WithBlockStore(IBlockStore blockStore) return this; } + public BlockTreeBuilder WithBadBlockStore(IBlockStore blockStore) + { + BadBlockStore = blockStore; + return this; + } + + public BlockTreeBuilder WithHeaderStore(IHeaderStore headerStore) + { + HeaderStore = headerStore; + return this; + } + public BlockTreeBuilder WithBlocksDb(IDb blocksDb) { BlocksDb = blocksDb; diff --git a/src/Nethermind/Nethermind.Core/BaseFeeCalculator.cs b/src/Nethermind/Nethermind.Core/BaseFeeCalculator.cs index 70b72473a73..268997f6df9 100644 --- a/src/Nethermind/Nethermind.Core/BaseFeeCalculator.cs +++ b/src/Nethermind/Nethermind.Core/BaseFeeCalculator.cs @@ -18,7 +18,7 @@ public static UInt256 Calculate(BlockHeader parent, IEip1559Spec specFor1559) long gasDelta; UInt256 feeDelta; bool isForkBlockNumber = specFor1559.Eip1559TransitionBlock == parent.Number + 1; - long parentGasTarget = parent.GasLimit / Eip1559Constants.ElasticityMultiplier; + long parentGasTarget = parent.GasLimit / specFor1559.ElasticityMultiplier; if (isForkBlockNumber) parentGasTarget = parent.GasLimit; @@ -30,20 +30,20 @@ public static UInt256 Calculate(BlockHeader parent, IEip1559Spec specFor1559) { gasDelta = parent.GasUsed - parentGasTarget; feeDelta = UInt256.Max( - parentBaseFee * (UInt256)gasDelta / (UInt256)parentGasTarget / Eip1559Constants.BaseFeeMaxChangeDenominator, + parentBaseFee * (UInt256)gasDelta / (UInt256)parentGasTarget / specFor1559.BaseFeeMaxChangeDenominator, UInt256.One); expectedBaseFee = parentBaseFee + feeDelta; } else { gasDelta = parentGasTarget - parent.GasUsed; - feeDelta = parentBaseFee * (UInt256)gasDelta / (UInt256)parentGasTarget / Eip1559Constants.BaseFeeMaxChangeDenominator; + feeDelta = parentBaseFee * (UInt256)gasDelta / (UInt256)parentGasTarget / specFor1559.BaseFeeMaxChangeDenominator; expectedBaseFee = UInt256.Max(parentBaseFee - feeDelta, 0); } if (isForkBlockNumber) { - expectedBaseFee = Eip1559Constants.ForkBaseFee; + expectedBaseFee = specFor1559.ForkBaseFee; } if (specFor1559.Eip1559BaseFeeMinValue.HasValue) diff --git a/src/Nethermind/Nethermind.Core/Caching/LruCache.cs b/src/Nethermind/Nethermind.Core/Caching/LruCache.cs index d96a4bc8d4b..e202c3cb5a4 100644 --- a/src/Nethermind/Nethermind.Core/Caching/LruCache.cs +++ b/src/Nethermind/Nethermind.Core/Caching/LruCache.cs @@ -146,6 +146,19 @@ public KeyValuePair[] ToArray() return array; } + [MethodImpl(MethodImplOptions.Synchronized)] + public TValue[] GetValues() + { + int i = 0; + TValue[] array = new TValue[_cacheMap.Count]; + foreach (KeyValuePair> kvp in _cacheMap) + { + array[i++] = kvp.Value.Value.Value; + } + + return array; + } + private void Replace(TKey key, TValue value) { LinkedListNode? node = _leastRecentlyUsed; diff --git a/src/Nethermind/Nethermind.Core/Eip1559Constants.cs b/src/Nethermind/Nethermind.Core/Eip1559Constants.cs index c2895bed910..cab44982cae 100644 --- a/src/Nethermind/Nethermind.Core/Eip1559Constants.cs +++ b/src/Nethermind/Nethermind.Core/Eip1559Constants.cs @@ -14,10 +14,5 @@ public class Eip1559Constants public static readonly UInt256 DefaultBaseFeeMaxChangeDenominator = 8; public static readonly int DefaultElasticityMultiplier = 2; - - // The above values are the default ones. However, we're allowing to override it from genesis - public static UInt256 ForkBaseFee { get; set; } = DefaultForkBaseFee; - public static UInt256 BaseFeeMaxChangeDenominator { get; set; } = DefaultBaseFeeMaxChangeDenominator; - public static long ElasticityMultiplier { get; set; } = DefaultElasticityMultiplier; } } diff --git a/src/Nethermind/Nethermind.Core/Specs/IEip1559Spec.cs b/src/Nethermind/Nethermind.Core/Specs/IEip1559Spec.cs index 33e5723eed3..0d343448551 100644 --- a/src/Nethermind/Nethermind.Core/Specs/IEip1559Spec.cs +++ b/src/Nethermind/Nethermind.Core/Specs/IEip1559Spec.cs @@ -17,5 +17,8 @@ public interface IEip1559Spec public long Eip1559TransitionBlock { get; } public Address? Eip1559FeeCollector => null; public UInt256? Eip1559BaseFeeMinValue => null; + public UInt256 ForkBaseFee { get; } + public UInt256 BaseFeeMaxChangeDenominator { get; } + public long ElasticityMultiplier { get; } } } diff --git a/src/Nethermind/Nethermind.Core/TransactionReceipt.cs b/src/Nethermind/Nethermind.Core/TransactionReceipt.cs index ea5f9c57531..5de0b0d85f3 100644 --- a/src/Nethermind/Nethermind.Core/TransactionReceipt.cs +++ b/src/Nethermind/Nethermind.Core/TransactionReceipt.cs @@ -39,6 +39,9 @@ public class TxReceipt public LogEntry[]? Logs { get; set; } public string? Error { get; set; } + public ulong? DepositNonce { get; set; } + public ulong? DepositReceiptVersion { get; set; } + /// /// Ignores receipt output on RLP serialization. /// Output is either StateRoot or StatusCode depending on eip configuration. diff --git a/src/Nethermind/Nethermind.Db.Rocks/DbOnTheRocks.cs b/src/Nethermind/Nethermind.Db.Rocks/DbOnTheRocks.cs index 2351d3c3367..99f4b222dcb 100644 --- a/src/Nethermind/Nethermind.Db.Rocks/DbOnTheRocks.cs +++ b/src/Nethermind/Nethermind.Db.Rocks/DbOnTheRocks.cs @@ -6,7 +6,6 @@ using System.Collections.Generic; using System.IO; using System.IO.Abstractions; -using System.Net.Sockets; using System.Reflection; using System.Threading; using ConcurrentCollections; @@ -15,7 +14,6 @@ using Nethermind.Core.Crypto; using Nethermind.Core.Exceptions; using Nethermind.Core.Extensions; -using Nethermind.Core.Threading; using Nethermind.Db.Rocks.Config; using Nethermind.Db.Rocks.Statistics; using Nethermind.Logging; @@ -26,9 +24,6 @@ namespace Nethermind.Db.Rocks; public class DbOnTheRocks : IDb, ITunableDb { - private McsPriorityLock _readThrottle = new(); - private McsPriorityLock _writeThrottle = new(); - private ILogger _logger; private string? _fullPath; @@ -505,7 +500,6 @@ public byte[]? this[ReadOnlySpan key] } } - using var handle = _readThrottle.Acquire(); return _db.Get(key, cf); } catch (RocksDbSharpException e) @@ -528,7 +522,6 @@ internal void SetWithColumnFamily(ReadOnlySpan key, ColumnFamilyHandle? cf try { - using var handle = _writeThrottle.Acquire(); if (value.IsNull()) { _db.Remove(key, cf, WriteFlagsToWriteOptions(flags)); @@ -572,7 +565,6 @@ internal void SetWithColumnFamily(ReadOnlySpan key, ColumnFamilyHandle? cf { try { - using var handle = _readThrottle.Acquire(); return _db.MultiGet(keys); } catch (RocksDbSharpException e) @@ -596,11 +588,8 @@ internal Span GetSpanWithColumnFamily(ReadOnlySpan key, ColumnFamily try { - Span span; - using (var handle = _readThrottle.Acquire()) - { - span = _db.GetSpan(key, cf); - } + Span span = _db.GetSpan(key, cf); + if (!span.IsNullOrEmpty()) { Interlocked.Increment(ref _allocatedSpan); @@ -636,7 +625,6 @@ public void Remove(ReadOnlySpan key) try { - using var handle = _writeThrottle.Acquire(); _db.Remove(key, null, WriteOptions); } catch (RocksDbSharpException e) @@ -672,7 +660,10 @@ protected internal Iterator CreateIterator(bool ordered = false, ColumnFamilyHan public IEnumerable GetAllKeys(bool ordered = false) { - ObjectDisposedException.ThrowIf(_isDisposing, this); + if (_isDisposing) + { + throw new ObjectDisposedException($"Attempted to read form a disposed database {Name}"); + } Iterator iterator = CreateIterator(ordered); return GetAllKeysCore(iterator); @@ -821,7 +812,6 @@ public bool KeyExists(ReadOnlySpan key) try { - using var handle = _readThrottle.Acquire(); // seems it has no performance impact return _db.Get(key) is not null; // return _db.Get(key, 32, _keyExistsBuffer, 0, 0, null, null) != -1; @@ -900,10 +890,7 @@ public void Dispose() try { - using (var handle = _dbOnTheRocks._writeThrottle.Acquire()) - { - _dbOnTheRocks._db.Write(_rocksBatch, _dbOnTheRocks.WriteFlagsToWriteOptions(_writeFlags)); - } + _dbOnTheRocks._db.Write(_rocksBatch, _dbOnTheRocks.WriteFlagsToWriteOptions(_writeFlags)); _dbOnTheRocks._currentBatches.TryRemove(this); ReturnWriteBatch(_rocksBatch); @@ -957,10 +944,7 @@ private void FlushOnTooManyWrites() try { - using (var handle = _dbOnTheRocks._writeThrottle.Acquire()) - { - _dbOnTheRocks._db.Write(currentBatch, _dbOnTheRocks.WriteFlagsToWriteOptions(_writeFlags)); - } + _dbOnTheRocks._db.Write(currentBatch, _dbOnTheRocks.WriteFlagsToWriteOptions(_writeFlags)); ReturnWriteBatch(currentBatch); } catch (RocksDbSharpException e) diff --git a/src/Nethermind/Nethermind.Db/DbNames.cs b/src/Nethermind/Nethermind.Db/DbNames.cs index 4d9f0c21350..c6004120c0b 100644 --- a/src/Nethermind/Nethermind.Db/DbNames.cs +++ b/src/Nethermind/Nethermind.Db/DbNames.cs @@ -13,6 +13,7 @@ public static class DbNames public const string BlockNumbers = "blockNumbers"; public const string Receipts = "receipts"; public const string BlockInfos = "blockInfos"; + public const string BadBlocks = "badBlocks"; public const string Bloom = "bloom"; public const string Witness = "witness"; public const string CHT = "canonicalHashTrie"; diff --git a/src/Nethermind/Nethermind.Db/IDbProvider.cs b/src/Nethermind/Nethermind.Db/IDbProvider.cs index dce39fe558a..7c4b764ff11 100644 --- a/src/Nethermind/Nethermind.Db/IDbProvider.cs +++ b/src/Nethermind/Nethermind.Db/IDbProvider.cs @@ -22,6 +22,7 @@ public interface IDbProvider : IDisposable public IDb HeadersDb => GetDb(DbNames.Headers); public IDb BlockNumbersDb => GetDb(DbNames.BlockNumbers); public IDb BlockInfosDb => GetDb(DbNames.BlockInfos); + public IDb BadBlocksDb => GetDb(DbNames.BadBlocks); // BloomDB progress / config (does not contain blooms - they are kept in bloom storage) public IDb BloomDb => GetDb(DbNames.Bloom); diff --git a/src/Nethermind/Nethermind.Db/Metrics.cs b/src/Nethermind/Nethermind.Db/Metrics.cs index 349b7eb430e..114a5227bd1 100644 --- a/src/Nethermind/Nethermind.Db/Metrics.cs +++ b/src/Nethermind/Nethermind.Db/Metrics.cs @@ -126,6 +126,14 @@ public static class Metrics [Description("Number of Metadata DB writes.")] public static long MetadataDbWrites { get; set; } + [CounterMetric] + [Description("Number of BadBlocks DB writes.")] + public static long BadBlocksDbWrites { get; set; } + + [CounterMetric] + [Description("Number of BadBlocks DB reads.")] + public static long BadBlocksDbReads { get; set; } + [CounterMetric] [Description("Number of BlobTransactions DB reads.")] public static long BlobTransactionsDbReads { get; set; } diff --git a/src/Nethermind/Nethermind.Db/StandardDbInitializer.cs b/src/Nethermind/Nethermind.Db/StandardDbInitializer.cs index 543f9adf8ea..d3832216b0d 100644 --- a/src/Nethermind/Nethermind.Db/StandardDbInitializer.cs +++ b/src/Nethermind/Nethermind.Db/StandardDbInitializer.cs @@ -41,6 +41,7 @@ private void RegisterAll(bool useReceiptsDb, bool useBlobsDb) RegisterDb(BuildRocksDbSettings(DbNames.Headers, () => Metrics.HeaderDbReads++, () => Metrics.HeaderDbWrites++)); RegisterDb(BuildRocksDbSettings(DbNames.BlockNumbers, () => Metrics.BlockNumberDbReads++, () => Metrics.BlockNumberDbWrites++)); RegisterDb(BuildRocksDbSettings(DbNames.BlockInfos, () => Metrics.BlockInfosDbReads++, () => Metrics.BlockInfosDbWrites++)); + RegisterDb(BuildRocksDbSettings(DbNames.BadBlocks, () => Metrics.BadBlocksDbReads++, () => Metrics.BadBlocksDbWrites++)); RocksDbSettings stateDbSettings = BuildRocksDbSettings(DbNames.State, () => Metrics.StateDbReads++, () => Metrics.StateDbWrites++); RegisterCustomDb(DbNames.State, () => new FullPruningDb( diff --git a/src/Nethermind/Nethermind.Evm/ExecutionEnvironment.cs b/src/Nethermind/Nethermind.Evm/ExecutionEnvironment.cs index afd332d5a39..ec6600fef8e 100644 --- a/src/Nethermind/Nethermind.Evm/ExecutionEnvironment.cs +++ b/src/Nethermind/Nethermind.Evm/ExecutionEnvironment.cs @@ -17,7 +17,7 @@ public ExecutionEnvironment Address caller, Address? codeSource, ReadOnlyMemory inputData, - TxExecutionContext txExecutionContext, + in TxExecutionContext txExecutionContext, UInt256 transferValue, UInt256 value, int callDepth = 0) diff --git a/src/Nethermind/Nethermind.Evm/Metrics.cs b/src/Nethermind/Nethermind.Evm/Metrics.cs index b904d0cd249..f9d16abd6c3 100644 --- a/src/Nethermind/Nethermind.Evm/Metrics.cs +++ b/src/Nethermind/Nethermind.Evm/Metrics.cs @@ -90,23 +90,23 @@ public class Metrics [Description("Number of contract create calls.")] public static long Creates { get; set; } internal static long Transactions { get; set; } - internal static decimal AveGasPrice { get; set; } - internal static decimal MinGasPrice { get; set; } = decimal.MaxValue; - internal static decimal MaxGasPrice { get; set; } - internal static decimal EstMedianGasPrice { get; set; } + internal static float AveGasPrice { get; set; } + internal static float MinGasPrice { get; set; } = float.MaxValue; + internal static float MaxGasPrice { get; set; } + internal static float EstMedianGasPrice { get; set; } internal static long BlockTransactions { get; set; } - internal static decimal BlockAveGasPrice { get; set; } - internal static decimal BlockMinGasPrice { get; set; } = decimal.MaxValue; - internal static decimal BlockMaxGasPrice { get; set; } - internal static decimal BlockEstMedianGasPrice { get; set; } + internal static float BlockAveGasPrice { get; set; } + internal static float BlockMinGasPrice { get; set; } = float.MaxValue; + internal static float BlockMaxGasPrice { get; set; } + internal static float BlockEstMedianGasPrice { get; set; } public static void ResetBlockStats() { BlockTransactions = 0; - BlockAveGasPrice = 0m; - BlockMaxGasPrice = 0m; - BlockEstMedianGasPrice = 0m; - BlockMinGasPrice = decimal.MaxValue; + BlockAveGasPrice = 0.0f; + BlockMaxGasPrice = 0.0f; + BlockEstMedianGasPrice = 0.0f; + BlockMinGasPrice = float.MaxValue; } } diff --git a/src/Nethermind/Nethermind.Evm/Tracing/BlockReceiptsTracer.cs b/src/Nethermind/Nethermind.Evm/Tracing/BlockReceiptsTracer.cs index 5c456e673b8..c43469bd91c 100644 --- a/src/Nethermind/Nethermind.Evm/Tracing/BlockReceiptsTracer.cs +++ b/src/Nethermind/Nethermind.Evm/Tracing/BlockReceiptsTracer.cs @@ -12,7 +12,7 @@ namespace Nethermind.Evm.Tracing; public class BlockReceiptsTracer : IBlockTracer, ITxTracer, IJournal, ITxTracerWrapper { - private Block _block = null!; + protected Block Block = null!; public bool IsTracingReceipt => true; public bool IsTracingActions => _currentTxTracer.IsTracingActions; public bool IsTracingOpLevelStorage => _currentTxTracer.IsTracingOpLevelStorage; @@ -42,7 +42,8 @@ public void MarkAsSuccess(Address recipient, long gasSpent, byte[] output, LogEn if (_currentTxTracer.IsTracingReceipt) { - _currentTxTracer.MarkAsSuccess(recipient, gasSpent, output, logs); + // TODO: is no stateRoot a bug? + _currentTxTracer.MarkAsSuccess(recipient, gasSpent, output, logs, null); } } @@ -58,30 +59,31 @@ public void MarkAsFailed(Address recipient, long gasSpent, byte[] output, string if (_currentTxTracer.IsTracingReceipt) { - _currentTxTracer.MarkAsFailed(recipient, gasSpent, output, error); + // TODO: is no stateRoot a bug? + _currentTxTracer.MarkAsFailed(recipient, gasSpent, output, error, null); } } - private TxReceipt BuildFailedReceipt(Address recipient, long gasSpent, string error, Hash256? stateRoot = null) + protected TxReceipt BuildFailedReceipt(Address recipient, long gasSpent, string error, Hash256? stateRoot) { TxReceipt receipt = BuildReceipt(recipient, gasSpent, StatusCode.Failure, Array.Empty(), stateRoot); receipt.Error = error; return receipt; } - private TxReceipt BuildReceipt(Address recipient, long spentGas, byte statusCode, LogEntry[] logEntries, Hash256? stateRoot = null) + protected virtual TxReceipt BuildReceipt(Address recipient, long spentGas, byte statusCode, LogEntry[] logEntries, Hash256? stateRoot) { - Transaction transaction = _currentTx!; + Transaction transaction = CurrentTx!; TxReceipt txReceipt = new() { Logs = logEntries, TxType = transaction.Type, Bloom = logEntries.Length == 0 ? Bloom.Empty : new Bloom(logEntries), - GasUsedTotal = _block.GasUsed, + GasUsedTotal = Block.GasUsed, StatusCode = statusCode, Recipient = transaction.IsContractCreation ? null : recipient, - BlockHash = _block.Hash, - BlockNumber = _block.Number, + BlockHash = Block.Hash, + BlockNumber = Block.Number, Index = _currentIndex, GasUsed = spentGas, Sender = transaction.SenderAddress, @@ -193,7 +195,7 @@ public void ReportFees(UInt256 fees, UInt256 burntFees) private ITxTracer _currentTxTracer = NullTxTracer.Instance; private int _currentIndex; private readonly List _txReceipts = new(); - private Transaction? _currentTx; + protected Transaction? CurrentTx; public IReadOnlyList TxReceipts => _txReceipts; public TxReceipt LastReceipt => _txReceipts[^1]; public bool IsTracingRewards => _otherTracer.IsTracingRewards; @@ -211,7 +213,7 @@ public void Restore(int snapshot) _txReceipts.RemoveAt(_txReceipts.Count - 1); } - _block.Header.GasUsed = _txReceipts.Count > 0 ? _txReceipts.Last().GasUsedTotal : 0; + Block.Header.GasUsed = _txReceipts.Count > 0 ? _txReceipts.Last().GasUsedTotal : 0; } public void ReportReward(Address author, string rewardType, UInt256 rewardValue) => @@ -224,7 +226,7 @@ public void StartNewBlockTrace(Block block) throw new InvalidOperationException("other tracer not set in receipts tracer"); } - _block = block; + Block = block; _currentIndex = 0; _txReceipts.Clear(); @@ -233,7 +235,7 @@ public void StartNewBlockTrace(Block block) public ITxTracer StartNewTxTrace(Transaction? tx) { - _currentTx = tx; + CurrentTx = tx; _currentTxTracer = _otherTracer.StartNewTxTrace(tx); return _currentTxTracer; } @@ -250,7 +252,7 @@ public void EndBlockTrace() if (_txReceipts.Count > 0) { Bloom blockBloom = new(); - _block.Header.Bloom = blockBloom; + Block.Header.Bloom = blockBloom; for (int index = 0; index < _txReceipts.Count; index++) { TxReceipt? receipt = _txReceipts[index]; diff --git a/src/Nethermind/Nethermind.Evm/Tracing/GasEstimator.cs b/src/Nethermind/Nethermind.Evm/Tracing/GasEstimator.cs index 7ae1c6c64a3..a2ddc2c0397 100644 --- a/src/Nethermind/Nethermind.Evm/Tracing/GasEstimator.cs +++ b/src/Nethermind/Nethermind.Evm/Tracing/GasEstimator.cs @@ -89,7 +89,7 @@ private bool TryExecutableTransaction(Transaction transaction, BlockHeader block transaction.GasLimit = gasLimit; BlockExecutionContext blCtx = new(block); - _transactionProcessor.CallAndRestore(transaction, blCtx, tracer.WithCancellation(token)); + _transactionProcessor.CallAndRestore(transaction, in blCtx, tracer.WithCancellation(token)); transaction.GasLimit = originalGasLimit; diff --git a/src/Nethermind/Nethermind.Evm/TransactionProcessing/BuildUpTransactionProcessorAdapter.cs b/src/Nethermind/Nethermind.Evm/TransactionProcessing/BuildUpTransactionProcessorAdapter.cs index 3583b6480b9..acfb1c7d295 100644 --- a/src/Nethermind/Nethermind.Evm/TransactionProcessing/BuildUpTransactionProcessorAdapter.cs +++ b/src/Nethermind/Nethermind.Evm/TransactionProcessing/BuildUpTransactionProcessorAdapter.cs @@ -15,7 +15,7 @@ public BuildUpTransactionProcessorAdapter(ITransactionProcessor transactionProce _transactionProcessor = transactionProcessor; } - public void Execute(Transaction transaction, BlockExecutionContext blkCtx, ITxTracer txTracer) => - _transactionProcessor.BuildUp(transaction, blkCtx, txTracer); + public void Execute(Transaction transaction, in BlockExecutionContext blkCtx, ITxTracer txTracer) => + _transactionProcessor.BuildUp(transaction, in blkCtx, txTracer); } } diff --git a/src/Nethermind/Nethermind.Evm/TransactionProcessing/CallAndRestoreTransactionProcessorAdapter.cs b/src/Nethermind/Nethermind.Evm/TransactionProcessing/CallAndRestoreTransactionProcessorAdapter.cs index 7042c9337a1..d518b5ee279 100644 --- a/src/Nethermind/Nethermind.Evm/TransactionProcessing/CallAndRestoreTransactionProcessorAdapter.cs +++ b/src/Nethermind/Nethermind.Evm/TransactionProcessing/CallAndRestoreTransactionProcessorAdapter.cs @@ -15,7 +15,7 @@ public CallAndRestoreTransactionProcessorAdapter(ITransactionProcessor transacti _transactionProcessor = transactionProcessor; } - public void Execute(Transaction transaction, BlockExecutionContext blkCtx, ITxTracer txTracer) => - _transactionProcessor.CallAndRestore(transaction, blkCtx, txTracer); + public void Execute(Transaction transaction, in BlockExecutionContext blkCtx, ITxTracer txTracer) => + _transactionProcessor.CallAndRestore(transaction, in blkCtx, txTracer); } } diff --git a/src/Nethermind/Nethermind.Evm/TransactionProcessing/ChangeableTransactionProcessorAdapter.cs b/src/Nethermind/Nethermind.Evm/TransactionProcessing/ChangeableTransactionProcessorAdapter.cs index 231950c656c..661a6698820 100644 --- a/src/Nethermind/Nethermind.Evm/TransactionProcessing/ChangeableTransactionProcessorAdapter.cs +++ b/src/Nethermind/Nethermind.Evm/TransactionProcessing/ChangeableTransactionProcessorAdapter.cs @@ -22,9 +22,9 @@ public ChangeableTransactionProcessorAdapter(ITransactionProcessor transactionPr TransactionProcessor = transactionProcessor; } - public void Execute(Transaction transaction, BlockExecutionContext blkCtx, ITxTracer txTracer) + public void Execute(Transaction transaction, in BlockExecutionContext blkCtx, ITxTracer txTracer) { - CurrentAdapter.Execute(transaction, blkCtx, txTracer); + CurrentAdapter.Execute(transaction, in blkCtx, txTracer); } } } diff --git a/src/Nethermind/Nethermind.Evm/TransactionProcessing/ExecuteTransactionProcessorAdapter.cs b/src/Nethermind/Nethermind.Evm/TransactionProcessing/ExecuteTransactionProcessorAdapter.cs index 2b4967dd3cd..b0f51de953e 100644 --- a/src/Nethermind/Nethermind.Evm/TransactionProcessing/ExecuteTransactionProcessorAdapter.cs +++ b/src/Nethermind/Nethermind.Evm/TransactionProcessing/ExecuteTransactionProcessorAdapter.cs @@ -15,7 +15,7 @@ public ExecuteTransactionProcessorAdapter(ITransactionProcessor transactionProce _transactionProcessor = transactionProcessor; } - public void Execute(Transaction transaction, BlockExecutionContext blkCtx, ITxTracer txTracer) => - _transactionProcessor.Execute(transaction, blkCtx, txTracer); + public void Execute(Transaction transaction, in BlockExecutionContext blkCtx, ITxTracer txTracer) => + _transactionProcessor.Execute(transaction, in blkCtx, txTracer); } } diff --git a/src/Nethermind/Nethermind.Evm/TransactionProcessing/ITransactionProcessor.cs b/src/Nethermind/Nethermind.Evm/TransactionProcessing/ITransactionProcessor.cs index 972ac5be1d8..21973ee817a 100644 --- a/src/Nethermind/Nethermind.Evm/TransactionProcessing/ITransactionProcessor.cs +++ b/src/Nethermind/Nethermind.Evm/TransactionProcessing/ITransactionProcessor.cs @@ -11,21 +11,21 @@ public interface ITransactionProcessor /// /// Execute transaction, commit state /// - void Execute(Transaction transaction, BlockExecutionContext blCtx, ITxTracer txTracer); + void Execute(Transaction transaction, in BlockExecutionContext blCtx, ITxTracer txTracer); /// /// Call transaction, rollback state /// - void CallAndRestore(Transaction transaction, BlockExecutionContext blCtx, ITxTracer txTracer); + void CallAndRestore(Transaction transaction, in BlockExecutionContext blCtx, ITxTracer txTracer); /// /// Execute transaction, keep the state uncommitted /// - void BuildUp(Transaction transaction, BlockExecutionContext blCtx, ITxTracer txTracer); + void BuildUp(Transaction transaction, in BlockExecutionContext blCtx, ITxTracer txTracer); /// /// Call transaction, no validations, commit state /// Will NOT charge gas from sender account, so stateDiff will miss gas fee /// - void Trace(Transaction transaction, BlockExecutionContext blCtx, ITxTracer txTracer); + void Trace(Transaction transaction, in BlockExecutionContext blCtx, ITxTracer txTracer); } diff --git a/src/Nethermind/Nethermind.Evm/TransactionProcessing/ITransactionProcessorAdapter.cs b/src/Nethermind/Nethermind.Evm/TransactionProcessing/ITransactionProcessorAdapter.cs index 06ab48f127e..4f09f301792 100644 --- a/src/Nethermind/Nethermind.Evm/TransactionProcessing/ITransactionProcessorAdapter.cs +++ b/src/Nethermind/Nethermind.Evm/TransactionProcessing/ITransactionProcessorAdapter.cs @@ -8,6 +8,6 @@ namespace Nethermind.Evm.TransactionProcessing { public interface ITransactionProcessorAdapter { - void Execute(Transaction transaction, BlockExecutionContext blkCtx, ITxTracer txTracer); + void Execute(Transaction transaction, in BlockExecutionContext blkCtx, ITxTracer txTracer); } } diff --git a/src/Nethermind/Nethermind.Evm/TransactionProcessing/ReadOnlyTransactionProcessor.cs b/src/Nethermind/Nethermind.Evm/TransactionProcessing/ReadOnlyTransactionProcessor.cs index 97c68f0aec2..f6999143fd9 100644 --- a/src/Nethermind/Nethermind.Evm/TransactionProcessing/ReadOnlyTransactionProcessor.cs +++ b/src/Nethermind/Nethermind.Evm/TransactionProcessing/ReadOnlyTransactionProcessor.cs @@ -23,17 +23,17 @@ public ReadOnlyTransactionProcessor(ITransactionProcessor transactionProcessor, _stateProvider.StateRoot = startState ?? throw new ArgumentNullException(nameof(startState)); } - public void Execute(Transaction transaction, BlockExecutionContext blCtx, ITxTracer txTracer) => - _transactionProcessor.Execute(transaction, blCtx, txTracer); + public void Execute(Transaction transaction, in BlockExecutionContext blCtx, ITxTracer txTracer) => + _transactionProcessor.Execute(transaction, in blCtx, txTracer); - public void CallAndRestore(Transaction transaction, BlockExecutionContext blCtx, ITxTracer txTracer) => - _transactionProcessor.CallAndRestore(transaction, blCtx, txTracer); + public void CallAndRestore(Transaction transaction, in BlockExecutionContext blCtx, ITxTracer txTracer) => + _transactionProcessor.CallAndRestore(transaction, in blCtx, txTracer); - public void BuildUp(Transaction transaction, BlockExecutionContext blCtx, ITxTracer txTracer) => - _transactionProcessor.BuildUp(transaction, blCtx, txTracer); + public void BuildUp(Transaction transaction, in BlockExecutionContext blCtx, ITxTracer txTracer) => + _transactionProcessor.BuildUp(transaction, in blCtx, txTracer); - public void Trace(Transaction transaction, BlockExecutionContext blCtx, ITxTracer txTracer) => - _transactionProcessor.Trace(transaction, blCtx, txTracer); + public void Trace(Transaction transaction, in BlockExecutionContext blCtx, ITxTracer txTracer) => + _transactionProcessor.Trace(transaction, in blCtx, txTracer); public bool IsContractDeployed(Address address) => _stateProvider.IsContract(address); diff --git a/src/Nethermind/Nethermind.Evm/TransactionProcessing/TraceTransactionProcessorAdapter.cs b/src/Nethermind/Nethermind.Evm/TransactionProcessing/TraceTransactionProcessorAdapter.cs index 3b51b89ccee..6c75c5b5e19 100644 --- a/src/Nethermind/Nethermind.Evm/TransactionProcessing/TraceTransactionProcessorAdapter.cs +++ b/src/Nethermind/Nethermind.Evm/TransactionProcessing/TraceTransactionProcessorAdapter.cs @@ -15,7 +15,7 @@ public TraceTransactionProcessorAdapter(ITransactionProcessor transactionProcess _transactionProcessor = transactionProcessor; } - public void Execute(Transaction transaction, BlockExecutionContext blkCtx, ITxTracer txTracer) => - _transactionProcessor.Trace(transaction, blkCtx, txTracer); + public void Execute(Transaction transaction, in BlockExecutionContext blkCtx, ITxTracer txTracer) => + _transactionProcessor.Trace(transaction, in blkCtx, txTracer); } } diff --git a/src/Nethermind/Nethermind.Evm/TransactionProcessing/TransactionProcessor.cs b/src/Nethermind/Nethermind.Evm/TransactionProcessing/TransactionProcessor.cs index 8eb05afb4be..e5f954c2aab 100644 --- a/src/Nethermind/Nethermind.Evm/TransactionProcessing/TransactionProcessor.cs +++ b/src/Nethermind/Nethermind.Evm/TransactionProcessing/TransactionProcessor.cs @@ -72,30 +72,30 @@ public TransactionProcessor( Ecdsa = new EthereumEcdsa(specProvider.ChainId, logManager); } - public void CallAndRestore(Transaction transaction, BlockExecutionContext blCtx, ITxTracer txTracer) + public void CallAndRestore(Transaction transaction, in BlockExecutionContext blCtx, ITxTracer txTracer) { - Execute(transaction, blCtx, txTracer, ExecutionOptions.CommitAndRestore); + Execute(transaction, in blCtx, txTracer, ExecutionOptions.CommitAndRestore); } - public void BuildUp(Transaction transaction, BlockExecutionContext blCtx, ITxTracer txTracer) + public void BuildUp(Transaction transaction, in BlockExecutionContext blCtx, ITxTracer txTracer) { // we need to treat the result of previous transaction as the original value of next transaction // when we do not commit WorldState.TakeSnapshot(true); - Execute(transaction, blCtx, txTracer, ExecutionOptions.None); + Execute(transaction, in blCtx, txTracer, ExecutionOptions.None); } - public void Execute(Transaction transaction, BlockExecutionContext blCtx, ITxTracer txTracer) + public void Execute(Transaction transaction, in BlockExecutionContext blCtx, ITxTracer txTracer) { - Execute(transaction, blCtx, txTracer, ExecutionOptions.Commit); + Execute(transaction, in blCtx, txTracer, ExecutionOptions.Commit); } - public void Trace(Transaction transaction, BlockExecutionContext blCtx, ITxTracer txTracer) + public void Trace(Transaction transaction, in BlockExecutionContext blCtx, ITxTracer txTracer) { - Execute(transaction, blCtx, txTracer, ExecutionOptions.NoValidation); + Execute(transaction, in blCtx, txTracer, ExecutionOptions.NoValidation); } - protected virtual void Execute(Transaction tx, BlockExecutionContext blCtx, ITxTracer tracer, ExecutionOptions opts) + protected virtual void Execute(Transaction tx, in BlockExecutionContext blCtx, ITxTracer tracer, ExecutionOptions opts) { BlockHeader header = blCtx.Header; IReleaseSpec spec = SpecProvider.GetSpec(header); @@ -117,7 +117,7 @@ protected virtual void Execute(Transaction tx, BlockExecutionContext blCtx, ITxT if (opts == ExecutionOptions.Commit || opts == ExecutionOptions.None) { - decimal gasPrice = (decimal)effectiveGasPrice / 1_000_000_000m; + float gasPrice = (float)((double)effectiveGasPrice / 1_000_000_000.0); Metrics.MinGasPrice = Math.Min(gasPrice, Metrics.MinGasPrice); Metrics.MaxGasPrice = Math.Max(gasPrice, Metrics.MaxGasPrice); @@ -125,11 +125,11 @@ protected virtual void Execute(Transaction tx, BlockExecutionContext blCtx, ITxT Metrics.BlockMaxGasPrice = Math.Max(gasPrice, Metrics.BlockMaxGasPrice); Metrics.AveGasPrice = (Metrics.AveGasPrice * Metrics.Transactions + gasPrice) / (Metrics.Transactions + 1); - Metrics.EstMedianGasPrice += Metrics.AveGasPrice * 0.01m * decimal.Sign(gasPrice - Metrics.EstMedianGasPrice); + Metrics.EstMedianGasPrice += Metrics.AveGasPrice * 0.01f * float.Sign(gasPrice - Metrics.EstMedianGasPrice); Metrics.Transactions++; Metrics.BlockAveGasPrice = (Metrics.BlockAveGasPrice * Metrics.BlockTransactions + gasPrice) / (Metrics.BlockTransactions + 1); - Metrics.BlockEstMedianGasPrice += Metrics.BlockAveGasPrice * 0.01m * decimal.Sign(gasPrice - Metrics.BlockEstMedianGasPrice); + Metrics.BlockEstMedianGasPrice += Metrics.BlockAveGasPrice * 0.01f * float.Sign(gasPrice - Metrics.BlockEstMedianGasPrice); Metrics.BlockTransactions++; } @@ -147,7 +147,7 @@ protected virtual void Execute(Transaction tx, BlockExecutionContext blCtx, ITxT if (commit) WorldState.Commit(spec, tracer.IsTracingState ? tracer : NullTxTracer.Instance); - ExecutionEnvironment env = BuildExecutionEnvironmnet(tx, blCtx, spec, tracer, opts, effectiveGasPrice); + ExecutionEnvironment env = BuildExecutionEnvironmnet(tx, in blCtx, spec, tracer, opts, effectiveGasPrice); long gasAvailable = tx.GasLimit - intrinsicGas; if (!ExecuteEVMCall(tx, header, spec, tracer, opts, gasAvailable, env, out TransactionSubstate? substate, out long spentGas, out byte statusCode)) @@ -433,7 +433,7 @@ protected virtual bool IncrementNonce(Transaction tx, BlockHeader header, IRelea } protected virtual ExecutionEnvironment BuildExecutionEnvironmnet( - Transaction tx, BlockExecutionContext blCtx, IReleaseSpec spec, ITxTracer tracer, ExecutionOptions opts, + Transaction tx, in BlockExecutionContext blCtx, IReleaseSpec spec, ITxTracer tracer, ExecutionOptions opts, in UInt256 effectiveGasPrice) { Address recipient = tx.GetRecipient(tx.IsContractCreation ? WorldState.GetNonce(tx.SenderAddress) : 0) ?? @@ -441,7 +441,7 @@ protected virtual ExecutionEnvironment BuildExecutionEnvironmnet( throw new InvalidDataException("Recipient has not been resolved properly before tx execution"); TxExecutionContext executionContext = - new(blCtx, tx.SenderAddress, effectiveGasPrice, tx.BlobVersionedHashes); + new(in blCtx, tx.SenderAddress, effectiveGasPrice, tx.BlobVersionedHashes); CodeInfo codeInfo = tx.IsContractCreation ? new(tx.Data.AsArray()) : VirtualMachine.GetCachedCodeInfo(WorldState, recipient, spec); @@ -450,7 +450,7 @@ protected virtual ExecutionEnvironment BuildExecutionEnvironmnet( return new ExecutionEnvironment ( - txExecutionContext: executionContext, + txExecutionContext: in executionContext, value: tx.Value, transferValue: tx.Value, caller: tx.SenderAddress, diff --git a/src/Nethermind/Nethermind.Evm/TxExecutionContext.cs b/src/Nethermind/Nethermind.Evm/TxExecutionContext.cs index 2e00bddb906..637c6fc0258 100644 --- a/src/Nethermind/Nethermind.Evm/TxExecutionContext.cs +++ b/src/Nethermind/Nethermind.Evm/TxExecutionContext.cs @@ -13,7 +13,7 @@ public readonly struct TxExecutionContext public UInt256 GasPrice { get; } public byte[][]? BlobVersionedHashes { get; } - public TxExecutionContext(BlockExecutionContext blockExecutionContext, Address origin, in UInt256 gasPrice, byte[][] blobVersionedHashes) + public TxExecutionContext(in BlockExecutionContext blockExecutionContext, Address origin, in UInt256 gasPrice, byte[][] blobVersionedHashes) { BlockExecutionContext = blockExecutionContext; Origin = origin; diff --git a/src/Nethermind/Nethermind.Evm/VirtualMachine.cs b/src/Nethermind/Nethermind.Evm/VirtualMachine.cs index 3ddd12fbc2d..d388f58a775 100644 --- a/src/Nethermind/Nethermind.Evm/VirtualMachine.cs +++ b/src/Nethermind/Nethermind.Evm/VirtualMachine.cs @@ -2297,7 +2297,7 @@ private EvmExceptionType InstructionCall( ExecutionEnvironment callEnv = new ( - txExecutionContext: env.TxExecutionContext, + txExecutionContext: in env.TxExecutionContext, callDepth: env.CallDepth + 1, caller: caller, codeSource: codeSource, @@ -2535,7 +2535,7 @@ private EvmExceptionType InstructionSelfDestruct(EvmState vmState, ref ExecutionEnvironment callEnv = new ( - txExecutionContext: env.TxExecutionContext, + txExecutionContext: in env.TxExecutionContext, callDepth: env.CallDepth + 1, caller: env.ExecutingAccount, executingAccount: contractAddress, diff --git a/src/Nethermind/Nethermind.Init/Steps/InitializeBlockTree.cs b/src/Nethermind/Nethermind.Init/Steps/InitializeBlockTree.cs index bd4036393c9..404a6c997a9 100644 --- a/src/Nethermind/Nethermind.Init/Steps/InitializeBlockTree.cs +++ b/src/Nethermind/Nethermind.Init/Steps/InitializeBlockTree.cs @@ -52,12 +52,14 @@ public Task Execute(CancellationToken cancellationToken) IBlockStore blockStore = new BlockStore(_get.DbProvider.BlocksDb); IHeaderStore headerStore = new HeaderStore(_get.DbProvider.HeadersDb, _get.DbProvider.BlockNumbersDb); + IBlockStore badBlockStore = _set.BadBlocksStore = new BlockStore(_get.DbProvider.BadBlocksDb, initConfig.BadBlocksStored); IBlockTree blockTree = _set.BlockTree = new BlockTree( blockStore, headerStore, _get.DbProvider.BlockInfosDb, _get.DbProvider.MetadataDb, + badBlockStore, chainLevelInfoRepository, _get.SpecProvider, bloomStorage, diff --git a/src/Nethermind/Nethermind.Init/Steps/InitializeBlockchain.cs b/src/Nethermind/Nethermind.Init/Steps/InitializeBlockchain.cs index 798b19e6b91..f87e07b38f7 100644 --- a/src/Nethermind/Nethermind.Init/Steps/InitializeBlockchain.cs +++ b/src/Nethermind/Nethermind.Init/Steps/InitializeBlockchain.cs @@ -73,7 +73,7 @@ protected virtual Task InitBlockchain() IStateReader stateReader = setApi.StateReader!; ITxPool txPool = _api.TxPool = CreateTxPool(); - ReceiptCanonicalityMonitor receiptCanonicalityMonitor = new(getApi.BlockTree, getApi.ReceiptStorage, _api.LogManager); + ReceiptCanonicalityMonitor receiptCanonicalityMonitor = new(getApi.ReceiptStorage, _api.LogManager); getApi.DisposeStack.Push(receiptCanonicalityMonitor); _api.ReceiptMonitor = receiptCanonicalityMonitor; diff --git a/src/Nethermind/Nethermind.Init/Steps/RegisterRpcModules.cs b/src/Nethermind/Nethermind.Init/Steps/RegisterRpcModules.cs index 9d318bcb3dd..298c969c97c 100644 --- a/src/Nethermind/Nethermind.Init/Steps/RegisterRpcModules.cs +++ b/src/Nethermind/Nethermind.Init/Steps/RegisterRpcModules.cs @@ -29,7 +29,6 @@ using Nethermind.Network.Config; using Nethermind.JsonRpc.Modules.Rpc; using Nethermind.Serialization.Json; -using Nethermind.Blockchain; namespace Nethermind.Init.Steps; @@ -117,6 +116,7 @@ public virtual async Task Execute(CancellationToken cancellationToken) if (_api.KeyStore is null) throw new StepDependencyException(nameof(_api.KeyStore)); if (_api.PeerPool is null) throw new StepDependencyException(nameof(_api.PeerPool)); if (_api.WitnessRepository is null) throw new StepDependencyException(nameof(_api.WitnessRepository)); + if (_api.BadBlocksStore is null) throw new StepDependencyException(nameof(_api.BadBlocksStore)); ProofModuleFactory proofModuleFactory = new(_api.WorldStateManager, _api.BlockTree, _api.BlockPreprocessor, _api.ReceiptFinder, _api.SpecProvider, _api.LogManager); rpcModuleProvider.RegisterBounded(proofModuleFactory, 2, rpcConfig.Timeout); @@ -134,6 +134,7 @@ public virtual async Task Execute(CancellationToken cancellationToken) _api.ConfigProvider, _api.SpecProvider, _api.SyncModeSelector, + _api.BadBlocksStore, _api.FileSystem, _api.LogManager); rpcModuleProvider.RegisterBoundedByCpuCount(debugModuleFactory, rpcConfig.Timeout); @@ -166,31 +167,21 @@ public virtual async Task Execute(CancellationToken cancellationToken) ManualPruningTrigger pruningTrigger = new(); _api.PruningTrigger.Add(pruningTrigger); - - IEraExporter eraService = new EraExporter( - _api.FileSystem, - _api.BlockTree, - _api.ReceiptStorage, - _api.SpecProvider, - BlockchainIds.GetBlockchainName(_api.SpecProvider.NetworkId), - _api.LogManager); AdminRpcModule adminRpcModule = new( _api.BlockTree, networkConfig, _api.PeerPool, _api.StaticNodesManager, _api.Enode, - eraService, initConfig.BaseDbPath, - pruningTrigger, - _api.ProcessExitToken!); + pruningTrigger); rpcModuleProvider.RegisterSingle(adminRpcModule); if (_api.TxPoolInfoProvider is null) throw new StepDependencyException(nameof(_api.TxPoolInfoProvider)); TxPoolRpcModule txPoolRpcModule = new(_api.TxPoolInfoProvider, _api.LogManager); rpcModuleProvider.RegisterSingle(txPoolRpcModule); - + if (_api.SyncServer is null) throw new StepDependencyException(nameof(_api.SyncServer)); if (_api.EngineSignerStore is null) throw new StepDependencyException(nameof(_api.EngineSignerStore)); diff --git a/src/Nethermind/Nethermind.JsonRpc.Benchmark/EthModuleBenchmarks.cs b/src/Nethermind/Nethermind.JsonRpc.Benchmark/EthModuleBenchmarks.cs index c846f9c8169..a0fc56d439d 100644 --- a/src/Nethermind/Nethermind.JsonRpc.Benchmark/EthModuleBenchmarks.cs +++ b/src/Nethermind/Nethermind.JsonRpc.Benchmark/EthModuleBenchmarks.cs @@ -73,6 +73,7 @@ public void GlobalSetup() new HeaderStore(dbProvider.HeadersDb, dbProvider.BlockNumbersDb), dbProvider.BlockInfosDb, dbProvider.MetadataDb, + new BlockStore(dbProvider.BadBlocksDb), chainLevelInfoRepository, specProvider, NullBloomStorage.Instance, diff --git a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/DebugModuleTests.cs b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/DebugModuleTests.cs index ed059c86e65..8b1a48dd697 100644 --- a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/DebugModuleTests.cs +++ b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/DebugModuleTests.cs @@ -4,17 +4,20 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; using FluentAssertions; +using Nethermind.Blockchain; +using Nethermind.Blockchain.Blocks; using Nethermind.Blockchain.Find; using Nethermind.Config; using Nethermind.Core; using Nethermind.Core.Crypto; using Nethermind.Core.Extensions; using Nethermind.Core.Test.Builders; +using Nethermind.Db; using Nethermind.Evm.Tracing.GethStyle; +using Nethermind.Int256; using Nethermind.JsonRpc.Data; using Nethermind.JsonRpc.Modules.DebugModule; using Nethermind.Logging; @@ -31,6 +34,7 @@ public class DebugModuleTests { private readonly IJsonRpcConfig jsonRpcConfig = new JsonRpcConfig(); private readonly IDebugBridge debugBridge = Substitute.For(); + private MemDb _blocksDb = new(); [Test] public async Task Get_from_db() @@ -39,6 +43,7 @@ public async Task Get_from_db() byte[] value = new byte[] { 4, 5, 6 }; debugBridge.GetDbValue(Arg.Any(), Arg.Any()).Returns(value); + IConfigProvider configProvider = Substitute.For(); DebugRpcModule rpcModule = new(LimboLogs.Instance, debugBridge, jsonRpcConfig); JsonRpcSuccessResponse? response = @@ -221,6 +226,46 @@ public async Task Get_trace_with_options() Assert.That(response, Is.EqualTo("{\"jsonrpc\":\"2.0\",\"result\":{\"gas\":\"0x0\",\"failed\":false,\"returnValue\":\"0xa2\",\"structLogs\":[{\"pc\":0,\"op\":\"STOP\",\"gas\":22000,\"gasCost\":1,\"depth\":1,\"error\":null,\"stack\":[],\"memory\":[\"0000000000000000000000000000000000000000000000000000000000000005\",\"0000000000000000000000000000000000000000000000000000000000000006\"],\"storage\":{\"0000000000000000000000000000000000000000000000000000000000000001\":\"0000000000000000000000000000000000000000000000000000000000000002\",\"0000000000000000000000000000000000000000000000000000000000000003\":\"0000000000000000000000000000000000000000000000000000000000000004\"}}]},\"id\":67}")); } + private BlockTree BuildBlockTree(Func? builderOptions = null) + { + BlockTreeBuilder builder = Build.A.BlockTree().WithBlocksDb(_blocksDb).WithBlockStore(new BlockStore(_blocksDb)); + builder = builderOptions?.Invoke(builder) ?? builder; + return builder.TestObject; + } + + [Test] + public void Debug_getBadBlocks_test() + { + IBlockStore badBlocksStore = null!; + BlockTree blockTree = BuildBlockTree(b => b.WithBadBlockStore(badBlocksStore = new BlockStore(b.BadBlocksDb))); + + Block block0 = Build.A.Block.WithNumber(0).WithDifficulty(1).TestObject; + Block block1 = Build.A.Block.WithNumber(1).WithDifficulty(2).WithParent(block0).TestObject; + Block block2 = Build.A.Block.WithNumber(2).WithDifficulty(3).WithParent(block1).TestObject; + Block block3 = Build.A.Block.WithNumber(2).WithDifficulty(4).WithParent(block2).TestObject; + + blockTree.SuggestBlock(block0); + blockTree.SuggestBlock(block1); + blockTree.SuggestBlock(block2); + blockTree.SuggestBlock(block3); + + blockTree.DeleteInvalidBlock(block1); + + BlockDecoder decoder = new(); + _blocksDb.Set(block1.Hash ?? new Hash256("0x0"), decoder.Encode(block1).Bytes); + + debugBridge.GetBadBlocks().Returns(badBlocksStore.GetAll()); + + AddBlockResult result = blockTree.SuggestBlock(block1); + Assert.That(result, Is.EqualTo(AddBlockResult.InvalidBlock)); + + DebugRpcModule rpcModule = new(LimboLogs.Instance, debugBridge, jsonRpcConfig); + ResultWrapper> blocks = rpcModule.debug_getBadBlocks(); + Assert.That(blocks.Data.Count, Is.EqualTo(1)); + Assert.That(blocks.Data.ElementAt(0).Hash, Is.EqualTo(block1.Hash)); + Assert.That(blocks.Data.ElementAt(0).Difficulty, Is.EqualTo(new UInt256(2))); + } + [Test] public async Task Get_trace_with_javascript_setup() { diff --git a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/SubscribeModuleTests.cs b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/SubscribeModuleTests.cs index 123497a5aa1..e2c033e4925 100644 --- a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/SubscribeModuleTests.cs +++ b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/SubscribeModuleTests.cs @@ -64,7 +64,7 @@ public void Setup() _filterStore = new FilterStore(); _jsonRpcDuplexClient = Substitute.For(); _jsonSerializer = new EthereumJsonSerializer(); - _receiptCanonicalityMonitor = new ReceiptCanonicalityMonitor(_blockTree, _receiptStorage, _logManager); + _receiptCanonicalityMonitor = new ReceiptCanonicalityMonitor(_receiptStorage, _logManager); _syncConfig = new SyncConfig(); IJsonSerializer jsonSerializer = new EthereumJsonSerializer(); @@ -114,6 +114,7 @@ private JsonRpcResult GetBlockAddedToMainResult(BlockReplacementEventArgs blockR })); _blockTree.BlockAddedToMain += Raise.EventWith(new object(), blockReplacementEventArgs); + _receiptStorage.ReceiptsInserted += Raise.EventWith(new object(), blockReplacementEventArgs); manualResetEvent.WaitOne(TimeSpan.FromMilliseconds(1000)).Should().Be(shouldReceiveResult); subscriptionId = newHeadSubscription.Id; @@ -133,6 +134,7 @@ private List GetLogsSubscriptionResult(Filter filter, BlockReplac })); _blockTree.BlockAddedToMain += Raise.EventWith(new object(), blockEventArgs); + _receiptStorage.ReceiptsInserted += Raise.EventWith(new object(), blockEventArgs); semaphoreSlim.Wait(TimeSpan.FromMilliseconds(100)); subscriptionId = logsSubscription.Id; @@ -713,6 +715,7 @@ public void LogsSubscription_should_not_send_logs_of_new_txs_on_ReceiptsInserted BlockReplacementEventArgs blockEventArgs = new(block); _blockTree.BlockAddedToMain += Raise.EventWith(new object(), blockEventArgs); + _receiptStorage.ReceiptsInserted += Raise.EventWith(new object(), blockEventArgs); manualResetEvent.WaitOne(TimeSpan.FromMilliseconds(200)); jsonRpcResults.Count.Should().Be(1); @@ -892,6 +895,7 @@ public async Task MultipleSubscriptions_concurrent_fast_messages(int messages) { BlockReplacementEventArgs eventArgs = new(Build.A.Block.TestObject); blockTree.BlockAddedToMain += Raise.EventWith(eventArgs); + _receiptStorage.ReceiptsInserted += Raise.EventWith(new object(), eventArgs); } }); @@ -1148,6 +1152,7 @@ public void LogsSubscription_can_send_logs_with_removed_txs_when_inserted() })); _blockTree.BlockAddedToMain += Raise.EventWith(new object(), blockEventArgs); + _receiptStorage.ReceiptsInserted += Raise.EventWith(new object(), blockEventArgs); manualResetEvent.WaitOne(TimeSpan.FromMilliseconds(2000)); jsonRpcResults.Count.Should().Be(1); diff --git a/src/Nethermind/Nethermind.JsonRpc/Modules/DebugModule/DebugBridge.cs b/src/Nethermind/Nethermind.JsonRpc/Modules/DebugModule/DebugBridge.cs index c55f8e32c61..c32e3b1f7cd 100644 --- a/src/Nethermind/Nethermind.JsonRpc/Modules/DebugModule/DebugBridge.cs +++ b/src/Nethermind/Nethermind.JsonRpc/Modules/DebugModule/DebugBridge.cs @@ -7,6 +7,7 @@ using System.Threading; using System.Threading.Tasks; using Nethermind.Blockchain; +using Nethermind.Blockchain.Blocks; using Nethermind.Blockchain.Find; using Nethermind.Blockchain.Receipts; using Nethermind.Config; @@ -32,6 +33,7 @@ public class DebugBridge : IDebugBridge private readonly IReceiptsMigration _receiptsMigration; private readonly ISpecProvider _specProvider; private readonly ISyncModeSelector _syncModeSelector; + private readonly IBlockStore _badBlockStore; private readonly Dictionary _dbMappings; public DebugBridge( @@ -42,7 +44,8 @@ public DebugBridge( IReceiptStorage receiptStorage, IReceiptsMigration receiptsMigration, ISpecProvider specProvider, - ISyncModeSelector syncModeSelector) + ISyncModeSelector syncModeSelector, + IBlockStore badBlockStore) { _configProvider = configProvider ?? throw new ArgumentNullException(nameof(configProvider)); _tracer = tracer ?? throw new ArgumentNullException(nameof(tracer)); @@ -51,6 +54,7 @@ public DebugBridge( _receiptsMigration = receiptsMigration ?? throw new ArgumentNullException(nameof(receiptsMigration)); _specProvider = specProvider ?? throw new ArgumentNullException(nameof(specProvider)); _syncModeSelector = syncModeSelector ?? throw new ArgumentNullException(nameof(syncModeSelector)); + _badBlockStore = badBlockStore; dbProvider = dbProvider ?? throw new ArgumentNullException(nameof(dbProvider)); IDb blockInfosDb = dbProvider.BlockInfosDb ?? throw new ArgumentNullException(nameof(dbProvider.BlockInfosDb)); IDb blocksDb = dbProvider.BlocksDb ?? throw new ArgumentNullException(nameof(dbProvider.BlocksDb)); @@ -76,25 +80,15 @@ public DebugBridge( } } - public byte[] GetDbValue(string dbName, byte[] key) - { - return _dbMappings[dbName][key]; - } + public IEnumerable GetBadBlocks() => _badBlockStore.GetAll(); - public ChainLevelInfo GetLevelInfo(long number) - { - return _blockTree.FindLevel(number); - } + public byte[] GetDbValue(string dbName, byte[] key) => _dbMappings[dbName][key]; - public int DeleteChainSlice(long startNumber, bool force = false) - { - return _blockTree.DeleteChainSlice(startNumber, force: force); - } + public ChainLevelInfo GetLevelInfo(long number) => _blockTree.FindLevel(number); - public void UpdateHeadBlock(Hash256 blockHash) - { - _blockTree.UpdateHeadBlock(blockHash); - } + public int DeleteChainSlice(long startNumber, bool force = false) => _blockTree.DeleteChainSlice(startNumber, force: force); + + public void UpdateHeadBlock(Hash256 blockHash) => _blockTree.UpdateHeadBlock(blockHash); public Task MigrateReceipts(long blockNumber) => _receiptsMigration.Run(blockNumber + 1); // add 1 to make go from inclusive (better for API) to exclusive (better for internal) @@ -118,6 +112,8 @@ public void InsertReceipts(BlockParameter blockParameter, TxReceipt[] txReceipts _receiptStorage.Insert(block, txReceipts); } + public GethLikeTxTrace GetTransactionTrace(Hash256 transactionHash, CancellationToken cancellationToken, GethTraceOptions? gethTraceOptions = null) => + _tracer.Trace(transactionHash, gethTraceOptions ?? GethTraceOptions.Default, cancellationToken); public TxReceipt[]? GetReceiptsForBlock(BlockParameter blockParam) { SearchResult searchResult = _blockTree.SearchForBlock(blockParam); @@ -143,41 +139,25 @@ public void InsertReceipts(BlockParameter blockParameter, TxReceipt[] txReceipts return block?.Transactions[txReceipt.Index]; } - public GethLikeTxTrace GetTransactionTrace(Hash256 transactionHash, CancellationToken cancellationToken, GethTraceOptions gethTraceOptions = null) - { - return _tracer.Trace(transactionHash, gethTraceOptions ?? GethTraceOptions.Default, cancellationToken); - } + public GethLikeTxTrace GetTransactionTrace(long blockNumber, int index, CancellationToken cancellationToken, GethTraceOptions? gethTraceOptions = null) => + _tracer.Trace(blockNumber, index, gethTraceOptions ?? GethTraceOptions.Default, cancellationToken); - public GethLikeTxTrace GetTransactionTrace(long blockNumber, int index, CancellationToken cancellationToken, GethTraceOptions gethTraceOptions = null) - { - return _tracer.Trace(blockNumber, index, gethTraceOptions ?? GethTraceOptions.Default, cancellationToken); - } + public GethLikeTxTrace GetTransactionTrace(Hash256 blockHash, int index, CancellationToken cancellationToken, GethTraceOptions? gethTraceOptions = null) => + _tracer.Trace(blockHash, index, gethTraceOptions ?? GethTraceOptions.Default, cancellationToken); - public GethLikeTxTrace GetTransactionTrace(Hash256 blockHash, int index, CancellationToken cancellationToken, GethTraceOptions gethTraceOptions = null) - { - return _tracer.Trace(blockHash, index, gethTraceOptions ?? GethTraceOptions.Default, cancellationToken); - } + public GethLikeTxTrace GetTransactionTrace(Rlp blockRlp, Hash256 transactionHash, CancellationToken cancellationToken, GethTraceOptions? gethTraceOptions = null) => + _tracer.Trace(blockRlp, transactionHash, gethTraceOptions ?? GethTraceOptions.Default, cancellationToken); - public GethLikeTxTrace GetTransactionTrace(Rlp blockRlp, Hash256 transactionHash, CancellationToken cancellationToken, GethTraceOptions gethTraceOptions = null) - { - return _tracer.Trace(blockRlp, transactionHash, gethTraceOptions ?? GethTraceOptions.Default, cancellationToken); - } + public GethLikeTxTrace? GetTransactionTrace(Transaction transaction, BlockParameter blockParameter, CancellationToken cancellationToken, GethTraceOptions? gethTraceOptions = null) => + _tracer.Trace(blockParameter, transaction, gethTraceOptions ?? GethTraceOptions.Default, cancellationToken); - public GethLikeTxTrace? GetTransactionTrace(Transaction transaction, BlockParameter blockParameter, CancellationToken cancellationToken, GethTraceOptions? gethTraceOptions = null) - { - return _tracer.Trace(blockParameter, transaction, gethTraceOptions ?? GethTraceOptions.Default, cancellationToken); - } - - public IReadOnlyCollection GetBlockTrace(BlockParameter blockParameter, CancellationToken cancellationToken, GethTraceOptions gethTraceOptions = null) - { - return _tracer.TraceBlock(blockParameter, gethTraceOptions ?? GethTraceOptions.Default, cancellationToken); - } + public IReadOnlyCollection GetBlockTrace(BlockParameter blockParameter, CancellationToken cancellationToken, GethTraceOptions? gethTraceOptions = null) => + _tracer.TraceBlock(blockParameter, gethTraceOptions ?? GethTraceOptions.Default, cancellationToken); - public IReadOnlyCollection GetBlockTrace(Rlp blockRlp, CancellationToken cancellationToken, GethTraceOptions? gethTraceOptions = null) - { - return _tracer.TraceBlock(blockRlp, gethTraceOptions ?? GethTraceOptions.Default, cancellationToken); - } + public IReadOnlyCollection GetBlockTrace(Rlp blockRlp, CancellationToken cancellationToken, GethTraceOptions? gethTraceOptions = null) => + _tracer.TraceBlock(blockRlp, gethTraceOptions ?? GethTraceOptions.Default, cancellationToken); + public byte[] GetBlockRlp(Hash256 blockHash) => _dbMappings[DbNames.Blocks].Get(blockHash); public byte[]? GetBlockRlp(BlockParameter parameter) { @@ -193,11 +173,6 @@ public IReadOnlyCollection GetBlockTrace(Rlp blockRlp, Cancella return null; } - public byte[] GetBlockRlp(Hash256 blockHash) - { - return _dbMappings[DbNames.Blocks].Get(blockHash); - } - public Block? GetBlock(BlockParameter param) => _blockTree.FindBlock(param); public byte[] GetBlockRlp(long number) @@ -206,10 +181,7 @@ public byte[] GetBlockRlp(long number) return hash is null ? null : _dbMappings[DbNames.Blocks].Get(hash); } - public object GetConfigValue(string category, string name) - { - return _configProvider.GetRawValue(category, name); - } + public object GetConfigValue(string category, string name) => _configProvider.GetRawValue(category, name); public SyncReportSymmary GetCurrentSyncStage() { diff --git a/src/Nethermind/Nethermind.JsonRpc/Modules/DebugModule/DebugModuleFactory.cs b/src/Nethermind/Nethermind.JsonRpc/Modules/DebugModule/DebugModuleFactory.cs index e9664e06f0d..948f48a22ce 100644 --- a/src/Nethermind/Nethermind.JsonRpc/Modules/DebugModule/DebugModuleFactory.cs +++ b/src/Nethermind/Nethermind.JsonRpc/Modules/DebugModule/DebugModuleFactory.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.IO.Abstractions; using Nethermind.Blockchain; +using Nethermind.Blockchain.Blocks; using Nethermind.Blockchain.Receipts; using Nethermind.Config; using Nethermind.Consensus.Processing; @@ -39,6 +40,7 @@ public class DebugModuleFactory : ModuleFactoryBase private readonly IReadOnlyDbProvider _dbProvider; private readonly IReadOnlyBlockTree _blockTree; private readonly ISyncModeSelector _syncModeSelector; + private readonly IBlockStore _badBlockStore; private readonly IFileSystem _fileSystem; private readonly ILogger _logger; @@ -55,6 +57,7 @@ public DebugModuleFactory( IConfigProvider configProvider, ISpecProvider specProvider, ISyncModeSelector syncModeSelector, + IBlockStore badBlockStore, IFileSystem fileSystem, ILogManager logManager) { @@ -71,6 +74,7 @@ public DebugModuleFactory( _specProvider = specProvider ?? throw new ArgumentNullException(nameof(specProvider)); _logManager = logManager ?? throw new ArgumentNullException(nameof(logManager)); _syncModeSelector = syncModeSelector ?? throw new ArgumentNullException(nameof(syncModeSelector)); + _badBlockStore = badBlockStore; _fileSystem = fileSystem ?? throw new ArgumentNullException(nameof(fileSystem)); _logger = logManager.GetClassLogger(); } @@ -112,7 +116,8 @@ public override IDebugRpcModule Create() _receiptStorage, _receiptsMigration, _specProvider, - _syncModeSelector); + _syncModeSelector, + _badBlockStore); return new DebugRpcModule(_logManager, debugBridge, _jsonRpcConfig); } diff --git a/src/Nethermind/Nethermind.JsonRpc/Modules/DebugModule/DebugRpcModule.cs b/src/Nethermind/Nethermind.JsonRpc/Modules/DebugModule/DebugRpcModule.cs index d24f73cb7fc..2816c277070 100644 --- a/src/Nethermind/Nethermind.JsonRpc/Modules/DebugModule/DebugRpcModule.cs +++ b/src/Nethermind/Nethermind.JsonRpc/Modules/DebugModule/DebugRpcModule.cs @@ -321,4 +321,10 @@ public ResultWrapper> debug_standardTraceBlockToFile(Hash256 return ResultWrapper>.Success(files); } + + public ResultWrapper> debug_getBadBlocks() + { + IEnumerable badBlocks = _debugBridge.GetBadBlocks(); + return ResultWrapper>.Success(badBlocks); + } } diff --git a/src/Nethermind/Nethermind.JsonRpc/Modules/DebugModule/IDebugBridge.cs b/src/Nethermind/Nethermind.JsonRpc/Modules/DebugModule/IDebugBridge.cs index 732dcdff7f7..73cc66f74b0 100644 --- a/src/Nethermind/Nethermind.JsonRpc/Modules/DebugModule/IDebugBridge.cs +++ b/src/Nethermind/Nethermind.JsonRpc/Modules/DebugModule/IDebugBridge.cs @@ -35,6 +35,7 @@ public interface IDebugBridge void InsertReceipts(BlockParameter blockParameter, TxReceipt[] receipts); SyncReportSymmary GetCurrentSyncStage(); IEnumerable TraceBlockToFile(Hash256 blockHash, CancellationToken cancellationToken, GethTraceOptions? gethTraceOptions = null); + public IEnumerable GetBadBlocks(); TxReceipt[]? GetReceiptsForBlock(BlockParameter param); Transaction? GetTransactionFromHash(Hash256 hash); } diff --git a/src/Nethermind/Nethermind.JsonRpc/Modules/DebugModule/IDebugRpcModule.cs b/src/Nethermind/Nethermind.JsonRpc/Modules/DebugModule/IDebugRpcModule.cs index 932a1d300da..e17f692779e 100644 --- a/src/Nethermind/Nethermind.JsonRpc/Modules/DebugModule/IDebugRpcModule.cs +++ b/src/Nethermind/Nethermind.JsonRpc/Modules/DebugModule/IDebugRpcModule.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Threading.Tasks; using Nethermind.Blockchain.Find; +using Nethermind.Core; using Nethermind.Core.Crypto; using Nethermind.Evm.Tracing.GethStyle; using Nethermind.JsonRpc.Data; @@ -106,4 +107,7 @@ public interface IDebugRpcModule : IRpcModule [JsonRpcMethod(Description = "Writes to a file the full stack trace of all invoked opcodes of the transaction specified (or all transactions if not specified) that was included in the block specified. The parent of the block must be present or it will fail.", IsImplemented = true, IsSharable = false)] ResultWrapper> debug_standardTraceBlockToFile(Hash256 blockHash, GethTraceOptions options = null); + + [JsonRpcMethod(Description = "Return list of invalid blocks.")] + ResultWrapper> debug_getBadBlocks(); } diff --git a/src/Nethermind/Nethermind.Merge.Plugin.Test/BlockTreeTests.cs b/src/Nethermind/Nethermind.Merge.Plugin.Test/BlockTreeTests.cs index de7f0a7f2ec..f0729dff70a 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin.Test/BlockTreeTests.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin.Test/BlockTreeTests.cs @@ -20,6 +20,7 @@ using Nethermind.Merge.Plugin.Synchronization; using Nethermind.Serialization.Rlp; using Nethermind.Specs; +using Nethermind.Specs.ChainSpecStyle; using Nethermind.Specs.Forks; using Nethermind.Synchronization.Blocks; using Nethermind.Synchronization.Peers; @@ -76,7 +77,7 @@ public void Can_suggest_terminal_block_correctly() .WithSpecProvider(specProvider) .OfChainLength(10) .TestObject; - PoSSwitcher poSSwitcher = new(new MergeConfig(), new SyncConfig(), new MemDb(), tree, specProvider, LimboLogs.Instance); + PoSSwitcher poSSwitcher = new(new MergeConfig(), new SyncConfig(), new MemDb(), tree, specProvider, new ChainSpec(), LimboLogs.Instance); Block? block8 = tree.FindBlock(8, BlockTreeLookupOptions.None); Assert.False(block8!.IsTerminalBlock(specProvider)); @@ -95,7 +96,7 @@ public void Suggest_terminal_block_with_lower_number_and_lower_total_difficulty( .WithSpecProvider(specProvider) .OfChainLength(10) .TestObject; - PoSSwitcher poSSwitcher = new(new MergeConfig(), new SyncConfig(), new MemDb(), tree, specProvider, LimboLogs.Instance); + PoSSwitcher poSSwitcher = new(new MergeConfig(), new SyncConfig(), new MemDb(), tree, specProvider, new ChainSpec(), LimboLogs.Instance); Block? block7 = tree.FindBlock(7, BlockTreeLookupOptions.None); Block newTerminalBlock = Build.A.Block @@ -124,7 +125,7 @@ public void Cannot_change_best_suggested_to_terminal_block_after_merge_block() .OfChainLength(10) .TestObject; - PoSSwitcher poSSwitcher = new(new MergeConfig(), new SyncConfig(), new MemDb(), tree, specProvider, LimboLogs.Instance); + PoSSwitcher poSSwitcher = new(new MergeConfig(), new SyncConfig(), new MemDb(), tree, specProvider, new ChainSpec(), LimboLogs.Instance); Block? block8 = tree.FindBlock(8, BlockTreeLookupOptions.None); Assert.False(block8!.Header.IsTerminalBlock(specProvider)); diff --git a/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.Setup.cs b/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.Setup.cs index 982c5a1741b..8ada5ce1885 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.Setup.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.Setup.cs @@ -20,6 +20,7 @@ using Nethermind.Core.Crypto; using Nethermind.Core.Specs; using Nethermind.Core.Test.Blockchain; +using Nethermind.Core.Test.Builders; using Nethermind.Core.Timers; using Nethermind.Crypto; using Nethermind.Db; @@ -33,6 +34,7 @@ using Nethermind.Merge.Plugin.Handlers; using Nethermind.Merge.Plugin.Synchronization; using Nethermind.Specs; +using Nethermind.Specs.ChainSpecStyle; using Nethermind.Specs.Forks; using Nethermind.State; using Nethermind.Synchronization.ParallelSync; @@ -76,7 +78,7 @@ private IEngineRpcModule CreateEngineModule(MergeTestBlockchain chain, ISyncConf blockCacheService, chain.LogManager); invalidChainTracker.SetupBlockchainProcessorInterceptor(chain.BlockchainProcessor); - chain.BeaconSync = new BeaconSync(chain.BeaconPivot, chain.BlockTree, synchronizationConfig, blockCacheService, chain.LogManager); + chain.BeaconSync = new BeaconSync(chain.BeaconPivot, chain.BlockTree, synchronizationConfig, blockCacheService, chain.PoSSwitcher, chain.LogManager); EngineRpcCapabilitiesProvider capabilitiesProvider = new(chain.SpecProvider); return new EngineRpcModule( new GetPayloadV1Handler( @@ -236,7 +238,7 @@ protected override IBlockProcessor CreateBlockProcessor() protected IBlockValidator CreateBlockValidator() { IBlockCacheService blockCacheService = new BlockCacheService(); - PoSSwitcher = new PoSSwitcher(MergeConfig, SyncConfig.Default, new MemDb(), BlockTree, SpecProvider, LogManager); + PoSSwitcher = new PoSSwitcher(MergeConfig, SyncConfig.Default, new MemDb(), BlockTree, SpecProvider, new ChainSpec() { Genesis = Core.Test.Builders.Build.A.Block.WithDifficulty(0).TestObject }, LogManager); SealValidator = new MergeSealValidator(PoSSwitcher, Always.Valid); HeaderValidator preMergeHeaderValidator = new HeaderValidator(BlockTree, SealValidator, SpecProvider, LogManager); HeaderValidator = new MergeHeaderValidator(PoSSwitcher, preMergeHeaderValidator, BlockTree, SpecProvider, SealValidator, LogManager); diff --git a/src/Nethermind/Nethermind.Merge.Plugin.Test/MergeRewardCalculatorTests.cs b/src/Nethermind/Nethermind.Merge.Plugin.Test/MergeRewardCalculatorTests.cs index 8175a677e5f..3c49333bdaa 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin.Test/MergeRewardCalculatorTests.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin.Test/MergeRewardCalculatorTests.cs @@ -10,6 +10,7 @@ using Nethermind.Logging; using Nethermind.Merge.Plugin.Handlers; using Nethermind.Specs; +using Nethermind.Specs.ChainSpecStyle; using Nethermind.Specs.Forks; using NSubstitute; using NUnit.Framework; @@ -156,7 +157,7 @@ private static PoSSwitcher CreatePosSwitcher() specProvider.TerminalTotalDifficulty = 2; MergeConfig? mergeConfig = new() { }; IBlockCacheService blockCacheService = new BlockCacheService(); - return new PoSSwitcher(mergeConfig, new SyncConfig(), db, blockTree, specProvider, LimboLogs.Instance); + return new PoSSwitcher(mergeConfig, new SyncConfig(), db, blockTree, specProvider, new ChainSpec(), LimboLogs.Instance); } } diff --git a/src/Nethermind/Nethermind.Merge.Plugin.Test/PoSSwitcherTests.cs b/src/Nethermind/Nethermind.Merge.Plugin.Test/PoSSwitcherTests.cs index 9f2992c46ed..1c1b5838b21 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin.Test/PoSSwitcherTests.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin.Test/PoSSwitcherTests.cs @@ -30,7 +30,7 @@ public void Initial_TTD_should_be_null() { UInt256? expectedTtd = null; IBlockTree blockTree = Substitute.For(); - PoSSwitcher poSSwitcher = new(new MergeConfig(), new SyncConfig(), new MemDb(), blockTree, TestSpecProvider.Instance, LimboLogs.Instance); + PoSSwitcher poSSwitcher = new(new MergeConfig(), new SyncConfig(), new MemDb(), blockTree, TestSpecProvider.Instance, new ChainSpec(), LimboLogs.Instance); Assert.That(poSSwitcher.TerminalTotalDifficulty, Is.EqualTo(expectedTtd)); } @@ -45,7 +45,7 @@ public void Read_TTD_from_chainspec_if_not_specified_in_merge_config() ChainSpec chainSpec = loader.Load(File.ReadAllText(path)); ChainSpecBasedSpecProvider specProvider = new(chainSpec); - PoSSwitcher poSSwitcher = new(new MergeConfig(), new SyncConfig(), new MemDb(), blockTree, specProvider, LimboLogs.Instance); + PoSSwitcher poSSwitcher = new(new MergeConfig(), new SyncConfig(), new MemDb(), blockTree, specProvider, new ChainSpec(), LimboLogs.Instance); Assert.That(poSSwitcher.TerminalTotalDifficulty, Is.EqualTo(expectedTtd)); Assert.That(specProvider.MergeBlockNumber?.BlockNumber, Is.EqualTo(101)); @@ -93,7 +93,7 @@ public void Override_TTD_and_number_from_merge_config() IBlockTree blockTree = Substitute.For(); TestSpecProvider specProvider = new(London.Instance); specProvider.UpdateMergeTransitionInfo(100, 20); - PoSSwitcher poSSwitcher = new(new MergeConfig() { TerminalTotalDifficulty = "340", TerminalBlockNumber = 2000 }, new SyncConfig(), new MemDb(), blockTree, specProvider, LimboLogs.Instance); + PoSSwitcher poSSwitcher = new(new MergeConfig() { TerminalTotalDifficulty = "340", TerminalBlockNumber = 2000 }, new SyncConfig(), new MemDb(), blockTree, specProvider, new ChainSpec(), LimboLogs.Instance); Assert.That(poSSwitcher.TerminalTotalDifficulty, Is.EqualTo(expectedTtd)); Assert.That(specProvider.MergeBlockNumber?.BlockNumber, Is.EqualTo(2001)); @@ -106,7 +106,7 @@ public void Can_update_merge_transition_info() IBlockTree blockTree = Substitute.For(); TestSpecProvider specProvider = new(London.Instance); specProvider.UpdateMergeTransitionInfo(2001, expectedTtd); - PoSSwitcher poSSwitcher = new(new MergeConfig() { }, new SyncConfig(), new MemDb(), blockTree, specProvider, LimboLogs.Instance); + PoSSwitcher poSSwitcher = new(new MergeConfig() { }, new SyncConfig(), new MemDb(), blockTree, specProvider, new ChainSpec(), LimboLogs.Instance); Assert.That(poSSwitcher.TerminalTotalDifficulty, Is.EqualTo(expectedTtd)); Assert.That(specProvider.MergeBlockNumber?.BlockNumber, Is.EqualTo(2001)); @@ -254,7 +254,7 @@ private void AssertFinalTotalDifficulty(long ttd, long genesisDifficulty, long? SyncConfig syncConfig = new(); if (pivotTotalDifficulty != null) syncConfig = new SyncConfig() { PivotTotalDifficulty = $"{(UInt256)pivotTotalDifficulty}" }; - PoSSwitcher poSSwitcher = new PoSSwitcher(new MergeConfig(), syncConfig, new MemDb(), blockTree, specProvider, LimboLogs.Instance); + PoSSwitcher poSSwitcher = new PoSSwitcher(new MergeConfig(), syncConfig, new MemDb(), blockTree, specProvider, new ChainSpec() { Genesis = genesisBlock }, LimboLogs.Instance); if (expectedFinalTotalDifficulty != null) poSSwitcher.FinalTotalDifficulty.Should().Be((UInt256)expectedFinalTotalDifficulty); else @@ -266,7 +266,7 @@ private static PoSSwitcher CreatePosSwitcher(IBlockTree blockTree, IDb? db = nul { db ??= new MemDb(); MergeConfig? mergeConfig = new() { }; - return new PoSSwitcher(mergeConfig, new SyncConfig(), db, blockTree, specProvider ?? MainnetSpecProvider.Instance, LimboLogs.Instance); + return new PoSSwitcher(mergeConfig, new SyncConfig(), db, blockTree, specProvider ?? MainnetSpecProvider.Instance, new ChainSpec(), LimboLogs.Instance); } } } diff --git a/src/Nethermind/Nethermind.Merge.Plugin.Test/Synchronization/BeaconHeadersSyncTests.cs b/src/Nethermind/Nethermind.Merge.Plugin.Test/Synchronization/BeaconHeadersSyncTests.cs index 8006941d498..3e7d4dadbee 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin.Test/Synchronization/BeaconHeadersSyncTests.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin.Test/Synchronization/BeaconHeadersSyncTests.cs @@ -18,6 +18,7 @@ using Nethermind.Merge.Plugin.InvalidChainTracker; using Nethermind.Merge.Plugin.Synchronization; using Nethermind.Specs; +using Nethermind.Specs.ChainSpecStyle; using Nethermind.State.Repositories; using Nethermind.Synchronization; using Nethermind.Synchronization.FastBlocks; @@ -64,14 +65,14 @@ public IBeaconPivot BeaconPivot } private BeaconSync? _beaconSync; - public BeaconSync BeaconSync => _beaconSync ??= new(BeaconPivot, BlockTree, SyncConfig, BlockCacheService, LimboLogs.Instance); + public BeaconSync BeaconSync => _beaconSync ??= new(BeaconPivot, BlockTree, SyncConfig, BlockCacheService, PoSSwitcher, LimboLogs.Instance); private IDb? _metadataDb; public IDb MetadataDb => _metadataDb ??= new MemDb(); private PoSSwitcher? _poSSwitcher; public PoSSwitcher PoSSwitcher => _poSSwitcher ??= new(MergeConfig, SyncConfig, MetadataDb, BlockTree, - MainnetSpecProvider.Instance, LimboLogs.Instance); + MainnetSpecProvider.Instance, new ChainSpec(), LimboLogs.Instance); private IInvalidChainTracker? _invalidChainTracker; diff --git a/src/Nethermind/Nethermind.Merge.Plugin/GC/GCKeeper.cs b/src/Nethermind/Nethermind.Merge.Plugin/GC/GCKeeper.cs index 17d736dd280..5e22b0d1fe7 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin/GC/GCKeeper.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin/GC/GCKeeper.cs @@ -28,22 +28,16 @@ public GCKeeper(IGCStrategy gcStrategy, ILogManager logManager) public IDisposable TryStartNoGCRegion(long? size = null) { - // SustainedLowLatency is used rather than NoGCRegion - // due to runtime bug https://github.com/dotnet/runtime/issues/84096 - // The code is left in as comments so it can be reverted when the bug is fixed size ??= _defaultSize; - var priorLatencyMode = System.Runtime.GCSettings.LatencyMode; - //if (_gcStrategy.CanStartNoGCRegion()) - if (priorLatencyMode != GCLatencyMode.SustainedLowLatency) + if (_gcStrategy.CanStartNoGCRegion()) { FailCause failCause = FailCause.None; try { - GCSettings.LatencyMode = GCLatencyMode.SustainedLowLatency; - //if (!System.GC.TryStartNoGCRegion(size.Value, true)) - //{ - // failCause = FailCause.GCFailedToStartNoGCRegion; - //} + if (!System.GC.TryStartNoGCRegion(size.Value, true)) + { + failCause = FailCause.GCFailedToStartNoGCRegion; + } } catch (ArgumentOutOfRangeException) { @@ -60,10 +54,10 @@ public IDisposable TryStartNoGCRegion(long? size = null) if (_logger.IsError) _logger.Error($"{nameof(System.GC.TryStartNoGCRegion)} failed with exception.", e); } - return new NoGCRegion(this, priorLatencyMode, failCause, size, _logger); + return new NoGCRegion(this, failCause, size, _logger); } - return new NoGCRegion(this, priorLatencyMode, FailCause.StrategyDisallowed, size, _logger); + return new NoGCRegion(this, FailCause.StrategyDisallowed, size, _logger); } private enum FailCause @@ -79,15 +73,13 @@ private enum FailCause private class NoGCRegion : IDisposable { private readonly GCKeeper _gcKeeper; - private readonly GCLatencyMode _priorMode; private readonly FailCause _failCause; private readonly long? _size; private readonly ILogger _logger; - internal NoGCRegion(GCKeeper gcKeeper, GCLatencyMode priorMode, FailCause failCause, long? size, ILogger logger) + internal NoGCRegion(GCKeeper gcKeeper, FailCause failCause, long? size, ILogger logger) { _gcKeeper = gcKeeper; - _priorMode = priorMode; _failCause = failCause; _size = size; _logger = logger; @@ -95,19 +87,13 @@ internal NoGCRegion(GCKeeper gcKeeper, GCLatencyMode priorMode, FailCause failCa public void Dispose() { - // SustainedLowLatency is used rather than NoGCRegion - // due to runtime bug https://github.com/dotnet/runtime/issues/84096 - // The code is left in as comments so it can be reverted when the bug is fixed if (_failCause == FailCause.None) { - //if (GCSettings.LatencyMode == GCLatencyMode.NoGCRegion) - if (GCSettings.LatencyMode == GCLatencyMode.SustainedLowLatency && - _priorMode != GCLatencyMode.SustainedLowLatency) + if (GCSettings.LatencyMode == GCLatencyMode.NoGCRegion) { try { - GCSettings.LatencyMode = _priorMode; - //System.GC.EndNoGCRegion(); + System.GC.EndNoGCRegion(); _gcKeeper.ScheduleGC(); } catch (InvalidOperationException) diff --git a/src/Nethermind/Nethermind.Merge.Plugin/Handlers/BlockCacheService.cs b/src/Nethermind/Nethermind.Merge.Plugin/Handlers/BlockCacheService.cs index e411bcc211f..ad5bfdda95b 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin/Handlers/BlockCacheService.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin/Handlers/BlockCacheService.cs @@ -10,5 +10,5 @@ namespace Nethermind.Merge.Plugin.Handlers; public class BlockCacheService : IBlockCacheService { public ConcurrentDictionary BlockCache { get; } = new(); - public Hash256 FinalizedHash { get; set; } = Keccak.Zero; + public Hash256? FinalizedHash { get; set; } } diff --git a/src/Nethermind/Nethermind.Merge.Plugin/Handlers/IBlockCacheService.cs b/src/Nethermind/Nethermind.Merge.Plugin/Handlers/IBlockCacheService.cs index 77b5979cec5..191318bb5d7 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin/Handlers/IBlockCacheService.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin/Handlers/IBlockCacheService.cs @@ -10,5 +10,5 @@ namespace Nethermind.Merge.Plugin.Handlers; public interface IBlockCacheService { public ConcurrentDictionary BlockCache { get; } - Hash256 FinalizedHash { get; set; } + Hash256? FinalizedHash { get; set; } } diff --git a/src/Nethermind/Nethermind.Merge.Plugin/MergeGossipPolicy.cs b/src/Nethermind/Nethermind.Merge.Plugin/MergeGossipPolicy.cs index a3983e90070..28db239cf26 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin/MergeGossipPolicy.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin/MergeGossipPolicy.cs @@ -36,7 +36,8 @@ public MergeGossipPolicy( // According to spec (https://github.com/ethereum/EIPs/blob/d896145678bd65d3eafd8749690c1b5228875c39/EIPS/eip-3675.md#network) // We MUST discard NewBlock/NewBlockHash messages after receiving FIRST_FINALIZED_BLOCK. public bool ShouldDiscardBlocks => _poSSwitcher.TransitionFinished || - _blockCacheService.FinalizedHash != Keccak.Zero; /* _blockCacheService.FinalizedHash != Keccak.Zero - this condition was added for edge case situation. + (_blockCacheService.FinalizedHash != null && _blockCacheService.FinalizedHash != Keccak.Zero); /* _blockCacheService.FinalizedHash != null && _blockCacheService.FinalizedHash != Keccak.Zero + This condition was added for edge case situation. We started beacon sync, and we hadn't reached transition yet. If CL sent us non zero finalization hash, it would mean that network reached transition. However, in edge case situation (verified by merge hive tests), our node needs to be reorged to PoW again, so we can't add this condition _blockCacheService.FinalizedHash != Keccak.Zero to PoSSwitcher.TransitionFinished. On the other hand, we don't want to receive any blocks from the network, so we want to discard blocks. */ diff --git a/src/Nethermind/Nethermind.Merge.Plugin/MergePlugin.cs b/src/Nethermind/Nethermind.Merge.Plugin/MergePlugin.cs index 2213acad4e9..e1ac8dd4c12 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin/MergePlugin.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin/MergePlugin.cs @@ -92,6 +92,7 @@ public virtual Task Init(INethermindApi nethermindApi) _api.DbProvider.GetDb(DbNames.Metadata), _api.BlockTree, _api.SpecProvider, + _api.ChainSpec, _api.LogManager); _invalidChainTracker = new InvalidChainTracker.InvalidChainTracker( _poSSwitcher, @@ -406,7 +407,7 @@ public Task InitSynchronization() _api.LogManager), _invalidChainTracker, _api.LogManager); - _beaconSync = new BeaconSync(_beaconPivot, _api.BlockTree, _syncConfig, _blockCacheService, _api.LogManager); + _beaconSync = new BeaconSync(_beaconPivot, _api.BlockTree, _syncConfig, _blockCacheService, _poSSwitcher, _api.LogManager); _api.BetterPeerStrategy = new MergeBetterPeerStrategy(_api.BetterPeerStrategy, _poSSwitcher, _beaconPivot, _api.LogManager); diff --git a/src/Nethermind/Nethermind.Merge.Plugin/PoSSwitcher.cs b/src/Nethermind/Nethermind.Merge.Plugin/PoSSwitcher.cs index fe860873b6c..632d4716a8f 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin/PoSSwitcher.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin/PoSSwitcher.cs @@ -12,6 +12,7 @@ using Nethermind.Db; using Nethermind.Logging; using Nethermind.Serialization.Rlp; +using Nethermind.Specs.ChainSpecStyle; namespace Nethermind.Merge.Plugin { @@ -39,6 +40,7 @@ public class PoSSwitcher : IPoSSwitcher private readonly IDb _metadataDb; private readonly IBlockTree _blockTree; private readonly ISpecProvider _specProvider; + private readonly ChainSpec _chainSpec; private readonly ILogger _logger; private Hash256? _terminalBlockHash; @@ -55,6 +57,7 @@ public PoSSwitcher( IDb metadataDb, IBlockTree blockTree, ISpecProvider specProvider, + ChainSpec chainSpec, ILogManager logManager) { _mergeConfig = mergeConfig; @@ -62,6 +65,7 @@ public PoSSwitcher( _metadataDb = metadataDb; _blockTree = blockTree; _specProvider = specProvider; + _chainSpec = chainSpec; _logger = logManager.GetClassLogger(); Initialize(); @@ -98,7 +102,9 @@ private void LoadFinalTotalDifficulty() } else { - UInt256 genesisDifficulty = _blockTree.Genesis?.Difficulty ?? 0; + if (_chainSpec?.Genesis == null) return; + + UInt256 genesisDifficulty = _chainSpec.Genesis.Difficulty; if (genesisDifficulty >= TerminalTotalDifficulty) // networks with the merge in genesis { _finalTotalDifficulty = genesisDifficulty; diff --git a/src/Nethermind/Nethermind.Merge.Plugin/Synchronization/BeaconSync.cs b/src/Nethermind/Nethermind.Merge.Plugin/Synchronization/BeaconSync.cs index 1591dbc18af..368c5d11516 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin/Synchronization/BeaconSync.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin/Synchronization/BeaconSync.cs @@ -3,6 +3,7 @@ using Nethermind.Blockchain; using Nethermind.Blockchain.Synchronization; +using Nethermind.Consensus; using Nethermind.Core; using Nethermind.Core.Crypto; using Nethermind.Crypto; @@ -18,6 +19,7 @@ public class BeaconSync : IMergeSyncController, IBeaconSyncStrategy private readonly IBlockTree _blockTree; private readonly ISyncConfig _syncConfig; private readonly IBlockCacheService _blockCacheService; + private readonly IPoSSwitcher _poSSwitcher; private bool _isInBeaconModeControl = false; private readonly ILogger _logger; @@ -26,12 +28,14 @@ public BeaconSync( IBlockTree blockTree, ISyncConfig syncConfig, IBlockCacheService blockCacheService, + IPoSSwitcher poSSwitcher, ILogManager logManager) { _beaconPivot = beaconPivot; _blockTree = blockTree; _syncConfig = syncConfig; _blockCacheService = blockCacheService; + _poSSwitcher = poSSwitcher; _logger = logManager.GetClassLogger(); } @@ -105,6 +109,8 @@ lowestInsertedBeaconHeader is not null && /// public bool IsBeaconSyncFinished(BlockHeader? blockHeader) => !_beaconPivot.BeaconPivotExists() || (blockHeader is not null && _blockTree.WasProcessed(blockHeader.Number, blockHeader.GetOrCalculateHash())); + public bool MergeTransitionFinished => _poSSwitcher.TransitionFinished; + public long? GetTargetBlockHeight() { if (_beaconPivot.BeaconPivotExists()) @@ -114,7 +120,7 @@ lowestInsertedBeaconHeader is not null && return null; } - public Hash256 GetFinalizedHash() + public Hash256? GetFinalizedHash() { return _blockCacheService.FinalizedHash; } diff --git a/src/Nethermind/Nethermind.Mev/MevBlockProductionTransactionsExecutor.cs b/src/Nethermind/Nethermind.Mev/MevBlockProductionTransactionsExecutor.cs index add5367424e..a12e997e876 100644 --- a/src/Nethermind/Nethermind.Mev/MevBlockProductionTransactionsExecutor.cs +++ b/src/Nethermind/Nethermind.Mev/MevBlockProductionTransactionsExecutor.cs @@ -70,7 +70,7 @@ public override TxReceipt[] ProcessTransactions(Block block, ProcessingOptions p else { // otherwise process transaction as usual - TxAction action = ProcessTransaction(block, blkCtx, currentTx, transactionsInBlock.Count, receiptsTracer, processingOptions, transactionsInBlock); + TxAction action = ProcessTransaction(block, in blkCtx, currentTx, transactionsInBlock.Count, receiptsTracer, processingOptions, transactionsInBlock); if (action == TxAction.Stop) break; } } @@ -90,7 +90,7 @@ public override TxReceipt[] ProcessTransactions(Block block, ProcessingOptions p else { // process accumulated bundle - TxAction action = ProcessBundle(block, blkCtx, bundleTransactions, transactionsInBlock, receiptsTracer, processingOptions); + TxAction action = ProcessBundle(block, in blkCtx, bundleTransactions, transactionsInBlock, receiptsTracer, processingOptions); if (action == TxAction.Stop) break; // start accumulating new bundle @@ -103,11 +103,11 @@ public override TxReceipt[] ProcessTransactions(Block block, ProcessingOptions p { // process the bundle and stop accumulating it bundleHash = null; - TxAction action = ProcessBundle(block, blkCtx, bundleTransactions, transactionsInBlock, receiptsTracer, processingOptions); + TxAction action = ProcessBundle(block, in blkCtx, bundleTransactions, transactionsInBlock, receiptsTracer, processingOptions); if (action == TxAction.Stop) break; // process normal transaction - action = ProcessTransaction(block, blkCtx, currentTx, transactionsInBlock.Count, receiptsTracer, processingOptions, transactionsInBlock); + action = ProcessTransaction(block, in blkCtx, currentTx, transactionsInBlock.Count, receiptsTracer, processingOptions, transactionsInBlock); if (action == TxAction.Stop) break; } } @@ -115,7 +115,7 @@ public override TxReceipt[] ProcessTransactions(Block block, ProcessingOptions p // if we ended with accumulated bundle, lets process it if (bundleTransactions.Count > 0) { - ProcessBundle(block, blkCtx, bundleTransactions, transactionsInBlock, receiptsTracer, processingOptions); + ProcessBundle(block, in blkCtx, bundleTransactions, transactionsInBlock, receiptsTracer, processingOptions); } _stateProvider.Commit(spec, receiptsTracer); @@ -125,7 +125,7 @@ public override TxReceipt[] ProcessTransactions(Block block, ProcessingOptions p } private TxAction ProcessBundle(Block block, - BlockExecutionContext blkCtx, + in BlockExecutionContext blkCtx, List bundleTransactions, LinkedHashSet transactionsInBlock, BlockReceiptsTracer receiptsTracer, @@ -149,7 +149,7 @@ bool CheckFeeNotManipulated() TxAction txAction = TxAction.Skip; for (int index = 0; index < bundleTransactions.Count && bundleSucceeded; index++) { - txAction = ProcessBundleTransaction(block, blkCtx, bundleTransactions[index], index, receiptsTracer, processingOptions, transactionsInBlock); + txAction = ProcessBundleTransaction(block, in blkCtx, bundleTransactions[index], index, receiptsTracer, processingOptions, transactionsInBlock); bundleSucceeded &= txAction == TxAction.Add; // if we need to stop on not first tx in the bundle, we actually want to skip the bundle @@ -188,14 +188,14 @@ bool CheckFeeNotManipulated() private TxAction ProcessBundleTransaction( Block block, - BlockExecutionContext blkCtx, + in BlockExecutionContext blkCtx, BundleTransaction currentTx, int index, BlockReceiptsTracer receiptsTracer, ProcessingOptions processingOptions, LinkedHashSet transactionsInBlock) { - TxAction action = ProcessTransaction(block, blkCtx, currentTx, index, receiptsTracer, processingOptions, transactionsInBlock, false); + TxAction action = ProcessTransaction(block, in blkCtx, currentTx, index, receiptsTracer, processingOptions, transactionsInBlock, false); if (action == TxAction.Add) { string? error = receiptsTracer.LastReceipt.Error; diff --git a/src/Nethermind/Nethermind.Mining.Test/MinGasPriceTests.cs b/src/Nethermind/Nethermind.Mining.Test/MinGasPriceTests.cs index 2e613d8c8e9..bd1e9e4db65 100644 --- a/src/Nethermind/Nethermind.Mining.Test/MinGasPriceTests.cs +++ b/src/Nethermind/Nethermind.Mining.Test/MinGasPriceTests.cs @@ -54,6 +54,19 @@ public void Test1559(long minimum, long maxFeePerGas, long maxPriorityFeePerGas, specProvider.GetSpec(Arg.Any(), Arg.Any()).IsEip1559Enabled.Returns(true); specProvider.GetSpec(Arg.Any()).IsEip1559Enabled.Returns(true); specProvider.GetSpec(Arg.Any()).IsEip1559Enabled.Returns(true); + + specProvider.GetSpec(Arg.Any()).ForkBaseFee.Returns(Eip1559Constants.DefaultForkBaseFee); + specProvider.GetSpec(Arg.Any()).BaseFeeMaxChangeDenominator.Returns(Eip1559Constants.DefaultBaseFeeMaxChangeDenominator); + specProvider.GetSpec(Arg.Any()).ElasticityMultiplier.Returns(Eip1559Constants.DefaultElasticityMultiplier); + + specProvider.GetSpec(Arg.Any(), Arg.Any()).ForkBaseFee.Returns(Eip1559Constants.DefaultForkBaseFee); + specProvider.GetSpec(Arg.Any(), Arg.Any()).BaseFeeMaxChangeDenominator.Returns(Eip1559Constants.DefaultBaseFeeMaxChangeDenominator); + specProvider.GetSpec(Arg.Any(), Arg.Any()).ElasticityMultiplier.Returns(Eip1559Constants.DefaultElasticityMultiplier); + + specProvider.GetSpec(Arg.Any()).ForkBaseFee.Returns(Eip1559Constants.DefaultForkBaseFee); + specProvider.GetSpec(Arg.Any()).BaseFeeMaxChangeDenominator.Returns(Eip1559Constants.DefaultBaseFeeMaxChangeDenominator); + specProvider.GetSpec(Arg.Any()).ElasticityMultiplier.Returns(Eip1559Constants.DefaultElasticityMultiplier); + BlocksConfig blocksConfig = new() { MinGasPrice = (UInt256)minimum diff --git a/src/Nethermind/Nethermind.Optimism/Create2DeployerContractRewriter.cs b/src/Nethermind/Nethermind.Optimism/Create2DeployerContractRewriter.cs new file mode 100644 index 00000000000..5485998ec55 --- /dev/null +++ b/src/Nethermind/Nethermind.Optimism/Create2DeployerContractRewriter.cs @@ -0,0 +1,34 @@ +// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using Nethermind.Blockchain; +using Nethermind.Blockchain.Find; +using Nethermind.Core; +using Nethermind.Core.Specs; +using Nethermind.State; + +namespace Nethermind.Optimism; + +public class Create2DeployerContractRewriter +{ + private IOPConfigHelper _opConfigHelper; + private ISpecProvider _specProvider; + private IBlockTree _blockTree; + + public Create2DeployerContractRewriter(IOPConfigHelper opConfigHelper, ISpecProvider specProvider, IBlockTree blockTree) + { + _opConfigHelper = opConfigHelper; + _specProvider = specProvider; + _blockTree = blockTree; + } + + 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)) + { + worldState.InsertCode(_opConfigHelper.Create2DeployerAddress!, _opConfigHelper.Create2DeployerCode, spec); + } + } +} diff --git a/src/Nethermind/Nethermind.Optimism/IOPConfigHelper.cs b/src/Nethermind/Nethermind.Optimism/IOPConfigHelper.cs index 2875a2b7e9a..e59e591d4b4 100644 --- a/src/Nethermind/Nethermind.Optimism/IOPConfigHelper.cs +++ b/src/Nethermind/Nethermind.Optimism/IOPConfigHelper.cs @@ -11,4 +11,7 @@ public interface IOPConfigHelper bool IsBedrock(BlockHeader header); bool IsRegolith(BlockHeader header); + bool IsCanyon(BlockHeader header); + Address? Create2DeployerAddress { get; } + byte[]? Create2DeployerCode { get; } } diff --git a/src/Nethermind/Nethermind.Optimism/InitializeBlockchainOptimism.cs b/src/Nethermind/Nethermind.Optimism/InitializeBlockchainOptimism.cs index 6920765a0dc..fb7b53726ff 100644 --- a/src/Nethermind/Nethermind.Optimism/InitializeBlockchainOptimism.cs +++ b/src/Nethermind/Nethermind.Optimism/InitializeBlockchainOptimism.cs @@ -5,6 +5,7 @@ using Nethermind.Api; using Nethermind.Blockchain.Services; using Nethermind.Config; +using Nethermind.Consensus.Processing; using Nethermind.Consensus.Producers; using Nethermind.Consensus.Validators; using Nethermind.Evm; @@ -27,11 +28,7 @@ public InitializeBlockchainOptimism(OptimismNethermindApi api) : base(api) protected override Task InitBlockchain() { - _api.SpecHelper = new( - _api.ChainSpec.Optimism.RegolithTimestamp, - _api.ChainSpec.Optimism.BedrockBlockNumber, - _api.ChainSpec.Optimism.L1FeeRecipient - ); + _api.SpecHelper = new(_api.ChainSpec.Optimism); _api.L1CostHelper = new(_api.SpecHelper, _api.ChainSpec.Optimism.L1BlockAddress); return base.InitBlockchain(); @@ -84,6 +81,32 @@ protected override IBlockValidator CreateBlockValidator() return new InvalidBlockInterceptor(blockValidator, _api.InvalidChainTracker, _api.LogManager); } + protected override BlockProcessor CreateBlockProcessor() + { + if (_api.DbProvider is null) throw new StepDependencyException(nameof(_api.DbProvider)); + if (_api.RewardCalculatorSource is null) throw new StepDependencyException(nameof(_api.RewardCalculatorSource)); + if (_api.TransactionProcessor is null) throw new StepDependencyException(nameof(_api.TransactionProcessor)); + if (_api.SpecHelper is null) throw new StepDependencyException(nameof(_api.SpecHelper)); + if (_api.SpecProvider is null) throw new StepDependencyException(nameof(_api.SpecProvider)); + if (_api.BlockTree is null) throw new StepDependencyException(nameof(_api.BlockTree)); + if (_api.WorldState is null) throw new StepDependencyException(nameof(_api.WorldState)); + + Create2DeployerContractRewriter contractRewriter = + new(_api.SpecHelper, _api.SpecProvider, _api.BlockTree); + + return new OptimismBlockProcessor( + _api.SpecProvider, + _api.BlockValidator, + _api.RewardCalculatorSource.Get(_api.TransactionProcessor!), + new BlockProcessor.BlockValidationTransactionsExecutor(_api.TransactionProcessor, _api.WorldState), + _api.WorldState, + _api.ReceiptStorage, + _api.WitnessCollector, + _api.LogManager, + _api.SpecHelper, + contractRewriter); + } + protected override IUnclesValidator CreateUnclesValidator() => Always.Valid; protected override IHealthHintService CreateHealthHintService() => diff --git a/src/Nethermind/Nethermind.Optimism/OPConfigHelper.cs b/src/Nethermind/Nethermind.Optimism/OPConfigHelper.cs index d9c56cf389c..3902d88b024 100644 --- a/src/Nethermind/Nethermind.Optimism/OPConfigHelper.cs +++ b/src/Nethermind/Nethermind.Optimism/OPConfigHelper.cs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LGPL-3.0-only using Nethermind.Core; +using Nethermind.Specs.ChainSpecStyle; namespace Nethermind.Optimism; @@ -9,14 +10,18 @@ public class OPSpecHelper : IOPConfigHelper { private readonly ulong _regolithTimestamp; private readonly long _bedrockBlockNumber; + private readonly ulong? _canyonTimestamp; public Address L1FeeReceiver { get; init; } - public OPSpecHelper(ulong regolithTimestamp, long bedrockBlockNumber, Address l1FeeReceiver) + public OPSpecHelper(OptimismParameters parameters) { - _regolithTimestamp = regolithTimestamp; - _bedrockBlockNumber = bedrockBlockNumber; - L1FeeReceiver = l1FeeReceiver; + _regolithTimestamp = parameters.RegolithTimestamp; + _bedrockBlockNumber = parameters.BedrockBlockNumber; + _canyonTimestamp = parameters.CanyonTimestamp; + L1FeeReceiver = parameters.L1FeeRecipient; + Create2DeployerCode = parameters.Create2DeployerCode; + Create2DeployerAddress = parameters.Create2DeployerAddress; } public bool IsRegolith(BlockHeader header) @@ -28,4 +33,12 @@ public bool IsBedrock(BlockHeader header) { return header.Number >= _bedrockBlockNumber; } + + public bool IsCanyon(BlockHeader header) + { + return header.Timestamp >= (_canyonTimestamp ?? long.MaxValue); + } + + public Address? Create2DeployerAddress { get; } + public byte[]? Create2DeployerCode { get; } } diff --git a/src/Nethermind/Nethermind.Optimism/OptimismBlockProcessor.cs b/src/Nethermind/Nethermind.Optimism/OptimismBlockProcessor.cs new file mode 100644 index 00000000000..50389d91351 --- /dev/null +++ b/src/Nethermind/Nethermind.Optimism/OptimismBlockProcessor.cs @@ -0,0 +1,47 @@ +// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using System; +using Nethermind.Blockchain.Receipts; +using Nethermind.Consensus.Processing; +using Nethermind.Consensus.Rewards; +using Nethermind.Consensus.Validators; +using Nethermind.Consensus.Withdrawals; +using Nethermind.Core; +using Nethermind.Core.Specs; +using Nethermind.Evm.Tracing; +using Nethermind.Logging; +using Nethermind.State; + +namespace Nethermind.Optimism; + +public class OptimismBlockProcessor : BlockProcessor +{ + private Create2DeployerContractRewriter? _contractRewriter; + + public OptimismBlockProcessor( + ISpecProvider? specProvider, + IBlockValidator? blockValidator, + IRewardCalculator? rewardCalculator, + IBlockProcessor.IBlockTransactionsExecutor? blockTransactionsExecutor, + IWorldState? stateProvider, + IReceiptStorage? receiptStorage, + IWitnessCollector? witnessCollector, + ILogManager? logManager, + IOPConfigHelper opConfigHelper, + Create2DeployerContractRewriter contractRewriter, + IWithdrawalProcessor? withdrawalProcessor = null) + : base(specProvider, blockValidator, rewardCalculator, blockTransactionsExecutor, + stateProvider, receiptStorage, witnessCollector, logManager, withdrawalProcessor) + { + ArgumentNullException.ThrowIfNull(stateProvider); + _contractRewriter = contractRewriter; + ReceiptsTracer = new OptimismBlockReceiptTracer(opConfigHelper, stateProvider); + } + + protected override TxReceipt[] ProcessBlock(Block block, IBlockTracer blockTracer, ProcessingOptions options) + { + _contractRewriter?.RewriteContract(block.Header, _stateProvider); + return base.ProcessBlock(block, blockTracer, options); + } +} diff --git a/src/Nethermind/Nethermind.Optimism/OptimismBlockProducerEnvFactory.cs b/src/Nethermind/Nethermind.Optimism/OptimismBlockProducerEnvFactory.cs index 7393e7fdfa8..42df6a18aa3 100644 --- a/src/Nethermind/Nethermind.Optimism/OptimismBlockProducerEnvFactory.cs +++ b/src/Nethermind/Nethermind.Optimism/OptimismBlockProducerEnvFactory.cs @@ -10,14 +10,11 @@ using Nethermind.Consensus.Rewards; using Nethermind.Consensus.Transactions; using Nethermind.Consensus.Validators; -using Nethermind.Core; +using Nethermind.Consensus.Withdrawals; using Nethermind.Core.Specs; -using Nethermind.Db; -using Nethermind.Evm.TransactionProcessing; using Nethermind.Logging; using Nethermind.Specs.ChainSpecStyle; using Nethermind.State; -using Nethermind.Trie.Pruning; using Nethermind.TxPool; namespace Nethermind.Optimism; @@ -74,4 +71,26 @@ protected override ITxSource CreateTxSourceForProducer(ITxSource? additionalTxSo return new OptimismTxPoolTxSource(baseTxSource); } + + protected override BlockProcessor CreateBlockProcessor( + ReadOnlyTxProcessingEnv readOnlyTxProcessingEnv, + ISpecProvider specProvider, + IBlockValidator blockValidator, + IRewardCalculatorSource rewardCalculatorSource, + IReceiptStorage receiptStorage, + ILogManager logManager, + IBlocksConfig blocksConfig) + { + return new OptimismBlockProcessor(specProvider, + blockValidator, + rewardCalculatorSource.Get(readOnlyTxProcessingEnv.TransactionProcessor), + TransactionsExecutorFactory.Create(readOnlyTxProcessingEnv), + readOnlyTxProcessingEnv.StateProvider, + receiptStorage, + NullWitnessCollector.Instance, + logManager, + _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 new file mode 100644 index 00000000000..95048f27080 --- /dev/null +++ b/src/Nethermind/Nethermind.Optimism/OptimismBlockReceiptTracer.cs @@ -0,0 +1,50 @@ +// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using System; +using Nethermind.Core; +using Nethermind.Core.Crypto; +using Nethermind.Evm.Tracing; +using Nethermind.State; + +namespace Nethermind.Optimism; + +public class OptimismBlockReceiptTracer : BlockReceiptsTracer +{ + private IOPConfigHelper _opConfigHelper; + private IWorldState _worldState; + + public OptimismBlockReceiptTracer(IOPConfigHelper opConfigHelper, IWorldState worldState) + { + _opConfigHelper = opConfigHelper; + _worldState = worldState; + } + + private (ulong?, ulong?) GetDepositReceiptData(BlockHeader header) + { + ArgumentNullException.ThrowIfNull(CurrentTx); + + ulong? depositNonce = null; + ulong? version = null; + + if (CurrentTx.IsDeposit()) + { + depositNonce = _worldState.GetNonce(CurrentTx.SenderAddress!).ToUInt64(null); + if (_opConfigHelper.IsCanyon(header)) + { + version = 1; + } + } + + return (depositNonce == 0 ? 0 : depositNonce - 1, version); + } + + protected override TxReceipt BuildReceipt(Address recipient, long spentGas, byte statusCode, LogEntry[] logEntries, Hash256? stateRoot) + { + (ulong? depositNonce, ulong? version) = GetDepositReceiptData(Block.Header); + TxReceipt receipt = base.BuildReceipt(recipient, spentGas, statusCode, logEntries, stateRoot); + receipt.DepositNonce = depositNonce; + receipt.DepositReceiptVersion = version; + return receipt; + } +} diff --git a/src/Nethermind/Nethermind.Optimism/OptimismPlugin.cs b/src/Nethermind/Nethermind.Optimism/OptimismPlugin.cs index d95345a7fbb..c1897641cc1 100644 --- a/src/Nethermind/Nethermind.Optimism/OptimismPlugin.cs +++ b/src/Nethermind/Nethermind.Optimism/OptimismPlugin.cs @@ -136,7 +136,7 @@ public Task InitSynchronization() _api.DisposeStack.Push((PeerRefresher)_peerRefresher); _beaconPivot = new BeaconPivot(_syncConfig, _api.DbProvider.MetadataDb, _api.BlockTree, _api.LogManager); - _beaconSync = new BeaconSync(_beaconPivot, _api.BlockTree, _syncConfig, _blockCacheService, _api.LogManager); + _beaconSync = new BeaconSync(_beaconPivot, _api.BlockTree, _syncConfig, _blockCacheService, _api.PoSSwitcher, _api.LogManager); _api.BetterPeerStrategy = new MergeBetterPeerStrategy(null!, _api.PoSSwitcher, _beaconPivot, _api.LogManager); _api.Pivot = _beaconPivot; diff --git a/src/Nethermind/Nethermind.Optimism/OptimismTransactionProcessor.cs b/src/Nethermind/Nethermind.Optimism/OptimismTransactionProcessor.cs index b58391a4317..1af53687a9e 100644 --- a/src/Nethermind/Nethermind.Optimism/OptimismTransactionProcessor.cs +++ b/src/Nethermind/Nethermind.Optimism/OptimismTransactionProcessor.cs @@ -31,20 +31,19 @@ public OptimismTransactionProcessor( private UInt256? _currentTxL1Cost; - protected override void Execute(Transaction tx, BlockExecutionContext blCtx, ITxTracer tracer, ExecutionOptions opts) + protected override void Execute(Transaction tx, in BlockExecutionContext blCtx, ITxTracer tracer, ExecutionOptions opts) { + IReleaseSpec spec = SpecProvider.GetSpec(blCtx.Header); _currentTxL1Cost = null; if (tx.IsDeposit()) { - IReleaseSpec spec = SpecProvider.GetSpec(blCtx.Header); - WorldState.AddToBalanceAndCreateIfNotExists(tx.SenderAddress!, tx.Mint, spec); if (opts.HasFlag(ExecutionOptions.Commit) || !spec.IsEip658Enabled) WorldState.Commit(spec); } - base.Execute(tx, blCtx, tracer, opts); + base.Execute(tx, in blCtx, tracer, opts); } protected override bool ValidateStatic(Transaction tx, BlockHeader header, IReleaseSpec spec, ITxTracer tracer, ExecutionOptions opts, diff --git a/src/Nethermind/Nethermind.Runner.Test/Ethereum/ContextWithMocks.cs b/src/Nethermind/Nethermind.Runner.Test/Ethereum/ContextWithMocks.cs index 0550a49d49f..6d8f3484754 100644 --- a/src/Nethermind/Nethermind.Runner.Test/Ethereum/ContextWithMocks.cs +++ b/src/Nethermind/Nethermind.Runner.Test/Ethereum/ContextWithMocks.cs @@ -44,6 +44,7 @@ using Nethermind.Specs; using Nethermind.Synchronization.SnapSync; using NSubstitute; +using Nethermind.Blockchain.Blocks; namespace Nethermind.Runner.Test.Ethereum { @@ -117,7 +118,8 @@ public static NethermindApi ContextWithMocks() SyncProgressResolver = Substitute.For(), BetterPeerStrategy = Substitute.For(), ReceiptMonitor = Substitute.For(), - WitnessRepository = Substitute.For() + WitnessRepository = Substitute.For(), + BadBlocksStore = Substitute.For() }; api.WorldStateManager = new ReadOnlyWorldStateManager(api.DbProvider, Substitute.For(), LimboLogs.Instance); diff --git a/src/Nethermind/Nethermind.Runner.Test/Ethereum/Steps/Migrations/ReceiptMigrationTests.cs b/src/Nethermind/Nethermind.Runner.Test/Ethereum/Steps/Migrations/ReceiptMigrationTests.cs index 8762884e529..fe452fb0691 100644 --- a/src/Nethermind/Nethermind.Runner.Test/Ethereum/Steps/Migrations/ReceiptMigrationTests.cs +++ b/src/Nethermind/Nethermind.Runner.Test/Ethereum/Steps/Migrations/ReceiptMigrationTests.cs @@ -161,7 +161,9 @@ public void EnsureCanonical(Block block) { } - public event EventHandler ReceiptsInserted { add { } remove { } } +#pragma warning disable CS0067 + public event EventHandler ReceiptsInserted; +#pragma warning restore CS0067 } } } diff --git a/src/Nethermind/Nethermind.Runner/configs/base-goerli.cfg b/src/Nethermind/Nethermind.Runner/configs/base-goerli.cfg index 938b91d8dab..641271bc3ac 100644 --- a/src/Nethermind/Nethermind.Runner/configs/base-goerli.cfg +++ b/src/Nethermind/Nethermind.Runner/configs/base-goerli.cfg @@ -9,9 +9,6 @@ "Sync": { "NetworkingEnabled": false }, - "Sync": { - "NetworkingEnabled": false - }, "JsonRpc" : { "Enabled" : true, "Port" : 8545, diff --git a/src/Nethermind/Nethermind.Runner/configs/chiado.cfg b/src/Nethermind/Nethermind.Runner/configs/chiado.cfg index 9f17bd7fb82..bf562a4a091 100644 --- a/src/Nethermind/Nethermind.Runner/configs/chiado.cfg +++ b/src/Nethermind/Nethermind.Runner/configs/chiado.cfg @@ -13,8 +13,8 @@ "Sync": { "FastSync": true, "FastBlocks": true, - "PivotNumber": 7480000, - "PivotHash": "0x5f05365bfc54de3c1410c33354f4a6ec3f3d99d88992760a7a0b5bfedecc1439", + "PivotNumber": 7580000, + "PivotHash": "0xf23063619522a038100cb2fc66e7947294e6dd6da0422ff769f2833729f7d6fb", "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 94bf9cf92ab..4d49d044dbb 100644 --- a/src/Nethermind/Nethermind.Runner/configs/energyweb.cfg +++ b/src/Nethermind/Nethermind.Runner/configs/energyweb.cfg @@ -8,9 +8,9 @@ }, "Sync": { "FastSync": true, - "PivotNumber": 27600000, - "PivotHash": "0x823ba12746ec06d8b717ebb17506083786b2d09ed94ef6a123808178e4e65b29", - "PivotTotalDifficulty": "9391793327017901591589139165116802635817474057", + "PivotNumber": 27710000, + "PivotHash": "0xf5f417b63a2a43ba7fcc610017f23380db4969600a8f7f2672ad774713247cd2", + "PivotTotalDifficulty": "9429224387379204822570110371934297139077403490", "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 36f8d2e062d..81c11ed694a 100644 --- a/src/Nethermind/Nethermind.Runner/configs/exosama.cfg +++ b/src/Nethermind/Nethermind.Runner/configs/exosama.cfg @@ -8,9 +8,9 @@ }, "Sync": { "FastSync": true, - "PivotNumber": 7380000, - "PivotHash": "0x713965cd5f7dfcf3222f01363f9e47424ae80e730aa7a4c0b93c282b8001d21c", - "PivotTotalDifficulty": "2511283867876525860359704602846449400197373288", + "PivotNumber": 7510000, + "PivotHash": "0x77046fb443f3c3f0d3a168a35800fb1fe577100b41965f579b658e9c70e6a0a1", + "PivotTotalDifficulty": "2555520575576247860609943301812579267686393288", "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 37b3677f820..6ded43f6d74 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": 31580000, - "PivotHash": "0xa9d5fe3742935569f98e381cfbb8f479fdb4d4367a3b4c71eca31313326d67bd", + "PivotNumber": 31690000, + "PivotHash": "0xb1c5f676cb85d4794c0ee949bc44adbee925da08d982136c2813c4e5f4b56768", "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 b641647308e..5a2153deff0 100644 --- a/src/Nethermind/Nethermind.Runner/configs/joc-mainnet.cfg +++ b/src/Nethermind/Nethermind.Runner/configs/joc-mainnet.cfg @@ -9,9 +9,9 @@ "FastSync": true, "SnapSync": true, "FastBlocks": true, - "PivotNumber": 8750000, - "PivotHash": "0x0ca157493b30e4911bfd6f5531f3ff9f5950731bfb0a4a562a65a70e0866b9cf", - "PivotTotalDifficulty": "17499036" + "PivotNumber": 8870000, + "PivotHash": "0x3d8c071530dd409324d5b74916f94f1553afb850051ae6143dd9bdbd4ad2b866", + "PivotTotalDifficulty": "17734268" }, "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 ef9b162b106..b78abb7f41b 100644 --- a/src/Nethermind/Nethermind.Runner/configs/joc-testnet.cfg +++ b/src/Nethermind/Nethermind.Runner/configs/joc-testnet.cfg @@ -9,9 +9,9 @@ "FastSync": true, "SnapSync": true, "FastBlocks": true, - "PivotNumber": 2350000, - "PivotHash": "0xbade98eea2f7239e920c1ac8d37a4cf76eaa1e33f62dfbab1a968d4585ce0ca6", - "PivotTotalDifficulty": "4699812" + "PivotNumber": 2470000, + "PivotHash": "0x457e4a8f96f002fd503c380c8b45b077a9280b3f00b6198cf80cd69f22c67b59", + "PivotTotalDifficulty": "4939802" }, "Metrics": { "NodeName": "JOC-Testnet" diff --git a/src/Nethermind/Nethermind.Runner/configs/mainnet.cfg b/src/Nethermind/Nethermind.Runner/configs/mainnet.cfg index 66832e806bf..1c5a8cca358 100644 --- a/src/Nethermind/Nethermind.Runner/configs/mainnet.cfg +++ b/src/Nethermind/Nethermind.Runner/configs/mainnet.cfg @@ -12,8 +12,8 @@ "Sync": { "FastSync": true, "SnapSync": true, - "PivotNumber": 18850000, - "PivotHash": "0x60968426404bd84733406475bb2c2bc9a550cc02ec8565f71d246d5c69a83bd9", + "PivotNumber": 18900000, + "PivotHash": "0x84bd4976f299d9343a18a1088f1cec0dbcac72b6d51a6fc9b901921a55449fc6", "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 475b632fe37..c0aff1477e2 100644 --- a/src/Nethermind/Nethermind.Runner/configs/sepolia.cfg +++ b/src/Nethermind/Nethermind.Runner/configs/sepolia.cfg @@ -18,8 +18,8 @@ "FastBlocks": true, "SnapSync": true, "UseGethLimitsInFastBlocks": true, - "PivotNumber": 4944000, - "PivotHash": "0xb470476a2c4c811cb136d6e88e3c3b2fc9463bdeb3e8187228b6d8d4d37f8280", + "PivotNumber": 4988000, + "PivotHash": "0xfa0e1cff9cf2ad67171d4c4b2e19b09f411f79756fd99d861744607dd88e9131", "PivotTotalDifficulty": "17000018015853232", "FastSyncCatchUpHeightDelta": "10000000000" }, diff --git a/src/Nethermind/Nethermind.Runner/configs/volta.cfg b/src/Nethermind/Nethermind.Runner/configs/volta.cfg index ce6195d8911..f6685fcce6b 100644 --- a/src/Nethermind/Nethermind.Runner/configs/volta.cfg +++ b/src/Nethermind/Nethermind.Runner/configs/volta.cfg @@ -12,9 +12,9 @@ }, "Sync": { "FastSync": true, - "PivotNumber": 26010000, - "PivotHash": "0xf4866dd804892fab476209a7780101c66f8d77585475f46e1145d19dc66545f8", - "PivotTotalDifficulty": "8850744363613609434682373539300291179604019546", + "PivotNumber": 26100000, + "PivotHash": "0xbd8ddbf4f3677a4e959f961478f56a971816f275b443a51387ba68e623cc4aec", + "PivotTotalDifficulty": "8881369776636493896394077253969150318634850916", "FastBlocks": true, "UseGethLimitsInFastBlocks": false, "FastSyncCatchUpHeightDelta": 10000000000 diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/ReceiptMessageDecoder.cs b/src/Nethermind/Nethermind.Serialization.Rlp/ReceiptMessageDecoder.cs index 052a6e766b1..ce58b0c0c95 100644 --- a/src/Nethermind/Nethermind.Serialization.Rlp/ReceiptMessageDecoder.cs +++ b/src/Nethermind/Nethermind.Serialization.Rlp/ReceiptMessageDecoder.cs @@ -57,8 +57,14 @@ public TxReceipt Decode(RlpStream rlpStream, RlpBehaviors rlpBehaviors = RlpBeha { entries[i] = Rlp.Decode(rlpStream, RlpBehaviors.AllowExtraBytes); } - txReceipt.Logs = entries; + + if (txReceipt.TxType == TxType.DepositTx && rlpStream.Position != lastCheck) + { + txReceipt.DepositNonce = rlpStream.DecodeUlong(); + txReceipt.DepositReceiptVersion = rlpStream.DecodeUlong(); + } + return txReceipt; } @@ -85,6 +91,12 @@ private static (int Total, int Logs) GetContentLength(TxReceipt item, RlpBehavio : Rlp.LengthOf(item.PostTransactionState); } + if (item.TxType == TxType.DepositTx && item.DepositReceiptVersion is not null) + { + contentLength += Rlp.LengthOf(item.DepositNonce ?? 0); + contentLength += Rlp.LengthOf(item.DepositReceiptVersion.Value); + } + return (contentLength, logsLength); } @@ -173,6 +185,12 @@ public void Encode(RlpStream rlpStream, TxReceipt item, RlpBehaviors rlpBehavior { rlpStream.Encode(item.Logs[i]); } + + if (item.TxType == TxType.DepositTx && item.DepositReceiptVersion is not null) + { + rlpStream.Encode(item.DepositNonce!.Value); + rlpStream.Encode(item.DepositReceiptVersion.Value); + } } } } diff --git a/src/Nethermind/Nethermind.Specs.Test/OverridableReleaseSpec.cs b/src/Nethermind/Nethermind.Specs.Test/OverridableReleaseSpec.cs index 225168c5b1d..b36a57071d0 100644 --- a/src/Nethermind/Nethermind.Specs.Test/OverridableReleaseSpec.cs +++ b/src/Nethermind/Nethermind.Specs.Test/OverridableReleaseSpec.cs @@ -157,5 +157,8 @@ public ulong Eip4844TransitionTimestamp public bool IsEip6780Enabled => _spec.IsEip6780Enabled; public bool IsEip4788Enabled => _spec.IsEip4788Enabled; public Address Eip4788ContractAddress => _spec.Eip4788ContractAddress; + public UInt256 ForkBaseFee => _spec.ForkBaseFee; + public UInt256 BaseFeeMaxChangeDenominator => _spec.BaseFeeMaxChangeDenominator; + public long ElasticityMultiplier => _spec.ElasticityMultiplier; } } diff --git a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainParameters.cs b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainParameters.cs index 2b5f645602b..817250bc01e 100644 --- a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainParameters.cs +++ b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainParameters.cs @@ -54,11 +54,11 @@ public class ChainParameters public long? Eip3541Transition { get; set; } public long? Eip3607Transition { get; set; } - public UInt256 Eip1559BaseFeeInitialValue { get; set; } + public UInt256? Eip1559BaseFeeInitialValue { get; set; } - public UInt256 Eip1559BaseFeeMaxChangeDenominator { get; set; } + public UInt256? Eip1559BaseFeeMaxChangeDenominator { get; set; } - public long Eip1559ElasticityMultiplier { get; set; } + public long? Eip1559ElasticityMultiplier { get; set; } /// /// Transaction permission managing contract address. diff --git a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpecBasedSpecProvider.cs b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpecBasedSpecProvider.cs index 4e94afb5f12..7aad4bac04f 100644 --- a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpecBasedSpecProvider.cs +++ b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpecBasedSpecProvider.cs @@ -6,6 +6,7 @@ using System.Linq; using System.Numerics; using System.Reflection; +using Nethermind.Core; using Nethermind.Core.Specs; using Nethermind.Int256; using Nethermind.Logging; @@ -205,8 +206,18 @@ private static ReleaseSpec CreateReleaseSpec(ChainSpec chainSpec, long releaseSt releaseSpec.IsEip3607Enabled = (chainSpec.Parameters.Eip3607Transition ?? long.MaxValue) <= releaseStartBlock; releaseSpec.ValidateChainId = (chainSpec.Parameters.ValidateChainIdTransition ?? 0) <= releaseStartBlock; releaseSpec.ValidateReceipts = ((chainSpec.Parameters.ValidateReceiptsTransition > 0) ? Math.Max(chainSpec.Parameters.ValidateReceiptsTransition ?? 0, chainSpec.Parameters.Eip658Transition ?? 0) : 0) <= releaseStartBlock; + releaseSpec.Eip1559FeeCollector = releaseSpec.IsEip1559Enabled && (chainSpec.Parameters.Eip1559FeeCollectorTransition ?? long.MaxValue) <= releaseStartBlock ? chainSpec.Parameters.Eip1559FeeCollector : null; releaseSpec.Eip1559BaseFeeMinValue = releaseSpec.IsEip1559Enabled && (chainSpec.Parameters.Eip1559BaseFeeMinValueTransition ?? long.MaxValue) <= releaseStartBlock ? chainSpec.Parameters.Eip1559BaseFeeMinValue : null; + releaseSpec.ElasticityMultiplier = chainSpec.Parameters.Eip1559ElasticityMultiplier ?? Eip1559Constants.DefaultElasticityMultiplier; + releaseSpec.ForkBaseFee = chainSpec.Parameters.Eip1559BaseFeeInitialValue ?? Eip1559Constants.DefaultForkBaseFee; + releaseSpec.BaseFeeMaxChangeDenominator = chainSpec.Parameters.Eip1559BaseFeeMaxChangeDenominator ?? Eip1559Constants.DefaultBaseFeeMaxChangeDenominator; + + if (chainSpec.Optimism?.CanyonTimestamp <= releaseStartTimestamp) + { + releaseSpec.BaseFeeMaxChangeDenominator = chainSpec.Optimism.CanyonBaseFeeChangeDenominator; + } + if (chainSpec.Ethash is not null) { diff --git a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpecLoader.cs b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpecLoader.cs index 163834c1a40..ec649bbda53 100644 --- a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpecLoader.cs +++ b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpecLoader.cs @@ -157,10 +157,10 @@ bool GetForInnerPathExistence(KeyValuePair o) TransactionPermissionContractTransition = chainSpecJson.Params.TransactionPermissionContractTransition, ValidateChainIdTransition = chainSpecJson.Params.ValidateChainIdTransition, ValidateReceiptsTransition = chainSpecJson.Params.ValidateReceiptsTransition, - Eip1559ElasticityMultiplier = chainSpecJson.Params.Eip1559ElasticityMultiplier ?? Eip1559Constants.ElasticityMultiplier, - Eip1559BaseFeeInitialValue = chainSpecJson.Params.Eip1559BaseFeeInitialValue ?? Eip1559Constants.ForkBaseFee, + Eip1559ElasticityMultiplier = chainSpecJson.Params.Eip1559ElasticityMultiplier ?? Eip1559Constants.DefaultElasticityMultiplier, + Eip1559BaseFeeInitialValue = chainSpecJson.Params.Eip1559BaseFeeInitialValue ?? Eip1559Constants.DefaultForkBaseFee, Eip1559BaseFeeMaxChangeDenominator = chainSpecJson.Params.Eip1559BaseFeeMaxChangeDenominator ?? - Eip1559Constants.BaseFeeMaxChangeDenominator, + Eip1559Constants.DefaultBaseFeeMaxChangeDenominator, Eip1559FeeCollector = chainSpecJson.Params.Eip1559FeeCollector, Eip1559FeeCollectorTransition = chainSpecJson.Params.Eip1559FeeCollectorTransition, Eip1559BaseFeeMinValueTransition = chainSpecJson.Params.Eip1559BaseFeeMinValueTransition, @@ -180,10 +180,6 @@ bool GetForInnerPathExistence(KeyValuePair o) ?? GetTransitionForExpectedPricing("alt_bn128_pairing", "price.alt_bn128_pairing.base", 45000); chainSpec.Parameters.Eip2565Transition ??= GetTransitionIfInnerPathExists("modexp", "price.modexp2565"); - Eip1559Constants.ElasticityMultiplier = chainSpec.Parameters.Eip1559ElasticityMultiplier; - Eip1559Constants.ForkBaseFee = chainSpec.Parameters.Eip1559BaseFeeInitialValue; - Eip1559Constants.BaseFeeMaxChangeDenominator = chainSpec.Parameters.Eip1559BaseFeeMaxChangeDenominator; - Eip4844Constants.OverrideIfAny( chainSpec.Parameters.Eip4844BlobGasPriceUpdateFraction, chainSpec.Parameters.Eip4844MaxBlobGasPerBlock, @@ -347,8 +343,12 @@ static AuRaParameters.Validator LoadValidator(ChainSpecJson.AuRaValidatorJson va { RegolithTimestamp = chainSpecJson.Engine.Optimism.RegolithTimestamp, BedrockBlockNumber = chainSpecJson.Engine.Optimism.BedrockBlockNumber, + CanyonTimestamp = chainSpecJson.Engine.Optimism.CanyonTimestamp, L1FeeRecipient = chainSpecJson.Engine.Optimism.L1FeeRecipient, - L1BlockAddress = chainSpecJson.Engine.Optimism.L1BlockAddress + L1BlockAddress = chainSpecJson.Engine.Optimism.L1BlockAddress, + CanyonBaseFeeChangeDenominator = chainSpecJson.Engine.Optimism.CanyonBaseFeeChangeDenominator, + Create2DeployerAddress = chainSpecJson.Engine.Optimism.Create2DeployerAddress, + Create2DeployerCode = chainSpecJson.Engine.Optimism.Create2DeployerCode }; } else if (chainSpecJson.Engine?.NethDev is not null) diff --git a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/Json/ChainSpecGenesisJson.cs b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/Json/ChainSpecGenesisJson.cs index c04038cafe0..a72fb549b86 100644 --- a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/Json/ChainSpecGenesisJson.cs +++ b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/Json/ChainSpecGenesisJson.cs @@ -24,8 +24,8 @@ internal class ChainSpecGenesisJson public bool StateUnavailable { get; set; } = false; public Hash256 StateRoot { get; set; } - public ulong? BlobGasUsed { get; set; } - public ulong? ExcessBlobGas { get; set; } + public ulong BlobGasUsed { get; set; } + public ulong ExcessBlobGas { get; set; } public Hash256 ParentBeaconBlockRoot { get; set; } } } diff --git a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/Json/ChainSpecJson.cs b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/Json/ChainSpecJson.cs index 4bf9b38fe2f..d819732c34f 100644 --- a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/Json/ChainSpecJson.cs +++ b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/Json/ChainSpecJson.cs @@ -7,6 +7,7 @@ using System.Text.Json; using System.Text.Json.Serialization; using Nethermind.Core; +using Nethermind.Core.Crypto; using Nethermind.Int256; namespace Nethermind.Specs.ChainSpecStyle.Json @@ -171,8 +172,12 @@ internal class OptimismEngineJson { public ulong RegolithTimestamp => Params.RegolithTimestamp; public long BedrockBlockNumber => Params.BedrockBlockNumber; + public ulong? CanyonTimestamp => Params.CanyonTimestamp; public Address L1FeeRecipient => Params.L1FeeRecipient; public Address L1BlockAddress => Params.L1BlockAddress; + public UInt256 CanyonBaseFeeChangeDenominator => Params.CanyonBaseFeeChangeDenominator; + public Address Create2DeployerAddress => Params.Create2DeployerAddress; + public byte[] Create2DeployerCode => Params.Create2DeployerCode; public OptimismEngineParamsJson Params { get; set; } } @@ -180,8 +185,12 @@ internal class OptimismEngineParamsJson { public ulong RegolithTimestamp { get; set; } public long BedrockBlockNumber { get; set; } + public ulong? CanyonTimestamp { get; set; } public Address L1FeeRecipient { get; set; } public Address L1BlockAddress { get; set; } + public UInt256 CanyonBaseFeeChangeDenominator { get; set; } + public Address Create2DeployerAddress { get; set; } + public byte[] Create2DeployerCode { get; set; } } internal class NethDevJson diff --git a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/OptimismParameters.cs b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/OptimismParameters.cs index 586481dbc96..b2439224257 100644 --- a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/OptimismParameters.cs +++ b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/OptimismParameters.cs @@ -1,7 +1,6 @@ // SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only -using System.Collections.Generic; using Nethermind.Core; using Nethermind.Int256; @@ -13,8 +12,16 @@ public class OptimismParameters public long BedrockBlockNumber { get; set; } + public ulong? CanyonTimestamp { get; set; } + public Address L1FeeRecipient { get; set; } public Address L1BlockAddress { get; set; } + + public UInt256 CanyonBaseFeeChangeDenominator { get; set; } + + public Address Create2DeployerAddress { get; set; } + + public byte[] Create2DeployerCode { get; set; } } } diff --git a/src/Nethermind/Nethermind.Specs/ReleaseSpec.cs b/src/Nethermind/Nethermind.Specs/ReleaseSpec.cs index fa886f82fa6..5de83c8356b 100644 --- a/src/Nethermind/Nethermind.Specs/ReleaseSpec.cs +++ b/src/Nethermind/Nethermind.Specs/ReleaseSpec.cs @@ -72,6 +72,9 @@ public ReleaseSpec Clone() public ulong Eip4844TransitionTimestamp { get; set; } public Address Eip1559FeeCollector { get; set; } public UInt256? Eip1559BaseFeeMinValue { get; set; } + public UInt256 ForkBaseFee { get; set; } = Eip1559Constants.DefaultForkBaseFee; + public UInt256 BaseFeeMaxChangeDenominator { get; set; } = Eip1559Constants.DefaultBaseFeeMaxChangeDenominator; + public long ElasticityMultiplier { get; set; } = Eip1559Constants.DefaultElasticityMultiplier; public bool IsEip1153Enabled { get; set; } public bool IsEip3651Enabled { get; set; } public bool IsEip3855Enabled { get; set; } diff --git a/src/Nethermind/Nethermind.Specs/SystemTransactionReleaseSpec.cs b/src/Nethermind/Nethermind.Specs/SystemTransactionReleaseSpec.cs index b4c0c4d29e8..8774d7a03ae 100644 --- a/src/Nethermind/Nethermind.Specs/SystemTransactionReleaseSpec.cs +++ b/src/Nethermind/Nethermind.Specs/SystemTransactionReleaseSpec.cs @@ -130,5 +130,8 @@ public bool IsEip158IgnoredAccount(Address address) public bool IsEip6780Enabled => _spec.IsEip6780Enabled; public bool IsEip4788Enabled => _spec.IsEip4788Enabled; public Address Eip4788ContractAddress => _spec.Eip4788ContractAddress; + public UInt256 ForkBaseFee => _spec.ForkBaseFee; + public UInt256 BaseFeeMaxChangeDenominator => _spec.BaseFeeMaxChangeDenominator; + public long ElasticityMultiplier => _spec.ElasticityMultiplier; } } diff --git a/src/Nethermind/Nethermind.State/StateProvider.cs b/src/Nethermind/Nethermind.State/StateProvider.cs index 1d0cfa2ac28..4ecaff55d2a 100644 --- a/src/Nethermind/Nethermind.State/StateProvider.cs +++ b/src/Nethermind/Nethermind.State/StateProvider.cs @@ -26,6 +26,7 @@ internal class StateProvider private const int StartCapacity = Resettable.StartCapacity; private readonly ResettableDictionary> _intraBlockCache = new(); private readonly ResettableHashSet
_committedThisRound = new(); + private readonly HashSet
_nullAccountReads = new(); // Only guarding against hot duplicates so filter doesn't need to be too big // Note: // False negatives are fine as they will just result in a overwrite set @@ -508,7 +509,7 @@ public void Commit(IReleaseSpec releaseSpec, IWorldStateTracer stateTracer, bool // because it was not committed yet it means that the just cache is the only state (so it was read only) if (isTracing && change.ChangeType == ChangeType.JustCache) { - _readsForTracing.Add(change.Address); + _nullAccountReads.Add(change.Address); continue; } @@ -597,7 +598,7 @@ public void Commit(IReleaseSpec releaseSpec, IWorldStateTracer stateTracer, bool if (isTracing) { - foreach (Address nullRead in _readsForTracing) + foreach (Address nullRead in _nullAccountReads) { // // this may be enough, let us write tests stateTracer.ReportAccountRead(nullRead); @@ -606,7 +607,7 @@ public void Commit(IReleaseSpec releaseSpec, IWorldStateTracer stateTracer, bool Resettable.Reset(ref _changes, ref _capacity, ref _currentPosition, StartCapacity); _committedThisRound.Reset(); - _readsForTracing.Clear(); + _nullAccountReads.Clear(); _intraBlockCache.Reset(); if (isTracing) @@ -687,10 +688,10 @@ private void SetState(Address address, Account? account) _tree.Set(address, account); } - private readonly HashSet
_readsForTracing = new(); - private Account? GetAndAddToCache(Address address) { + if (_nullAccountReads.Contains(address)) return null; + Account? account = GetState(address); if (account is not null) { @@ -699,7 +700,7 @@ private void SetState(Address address, Account? account) else { // just for tracing - potential perf hit, maybe a better solution? - _readsForTracing.Add(address); + _nullAccountReads.Add(address); } return account; @@ -803,7 +804,7 @@ public void Reset() if (_logger.IsTrace) _logger.Trace("Clearing state provider caches"); _intraBlockCache.Reset(); _committedThisRound.Reset(); - _readsForTracing.Clear(); + _nullAccountReads.Clear(); _currentPosition = Resettable.EmptyPosition; Array.Clear(_changes, 0, _changes.Length); _needsStateRootUpdate = false; diff --git a/src/Nethermind/Nethermind.Synchronization.Test/BlockDownloaderTests.Merge.cs b/src/Nethermind/Nethermind.Synchronization.Test/BlockDownloaderTests.Merge.cs index 2800d2910bd..10ae29c0c92 100644 --- a/src/Nethermind/Nethermind.Synchronization.Test/BlockDownloaderTests.Merge.cs +++ b/src/Nethermind/Nethermind.Synchronization.Test/BlockDownloaderTests.Merge.cs @@ -20,6 +20,7 @@ using Nethermind.Merge.Plugin.Synchronization; using Nethermind.Merge.Plugin.Test; using Nethermind.Specs; +using Nethermind.Specs.ChainSpecStyle; using Nethermind.Stats; using Nethermind.Stats.Model; using Nethermind.Synchronization.Blocks; @@ -456,6 +457,7 @@ public MergeConfig MergeConfig MetadataDb, BlockTree, SpecProvider, + new ChainSpec(), LimboLogs.Instance); protected override IBetterPeerStrategy BetterPeerStrategy => _betterPeerStrategy ??= diff --git a/src/Nethermind/Nethermind.Synchronization.Test/ParallelSync/MultiSyncModeSelectorTests.Scenario.cs b/src/Nethermind/Nethermind.Synchronization.Test/ParallelSync/MultiSyncModeSelectorTests.Scenario.cs index b7cc95c5442..6e4e327bbe6 100644 --- a/src/Nethermind/Nethermind.Synchronization.Test/ParallelSync/MultiSyncModeSelectorTests.Scenario.cs +++ b/src/Nethermind/Nethermind.Synchronization.Test/ParallelSync/MultiSyncModeSelectorTests.Scenario.cs @@ -884,7 +884,7 @@ public ScenarioBuilder WhenMergeSyncPivotNotResolvedYet() { SyncConfig.MaxAttemptsToUpdatePivot = 3; BeaconSyncStrategy = Substitute.For(); - BeaconSyncStrategy.GetFinalizedHash().Returns(TestItem.KeccakA); + BeaconSyncStrategy.MergeTransitionFinished.Returns(true); return "merge sync pivot not resolved yet"; } ); diff --git a/src/Nethermind/Nethermind.Synchronization.Test/SnapSync/ProgressTrackerTests.cs b/src/Nethermind/Nethermind.Synchronization.Test/SnapSync/ProgressTrackerTests.cs index f702e409258..921b5baa7df 100644 --- a/src/Nethermind/Nethermind.Synchronization.Test/SnapSync/ProgressTrackerTests.cs +++ b/src/Nethermind/Nethermind.Synchronization.Test/SnapSync/ProgressTrackerTests.cs @@ -6,6 +6,7 @@ using FluentAssertions; using Nethermind.Blockchain; using Nethermind.Core.Crypto; +using Nethermind.Core.Test; using Nethermind.Core.Test.Builders; using Nethermind.Db; using Nethermind.Logging; @@ -135,4 +136,24 @@ public void Will_deque_storage_request_if_high() request.CodesRequest.Should().BeNull(); request.StorageRangeRequest.Should().NotBeNull(); } + + [Test] + public void Will_mark_progress_and_flush_when_finished() + { + BlockTree blockTree = Build.A.BlockTree().WithBlocks(Build.A.Block + .WithStateRoot(Keccak.EmptyTreeHash) + .TestObject).TestObject; + TestMemDb memDb = new TestMemDb(); + ProgressTracker progressTracker = new ProgressTracker(blockTree, memDb, LimboLogs.Instance, 1); + + (SnapSyncBatch request, bool finished) = progressTracker.GetNextRequest(); + request.AccountRangeRequest.Should().NotBeNull(); + progressTracker.UpdateAccountRangePartitionProgress(request.AccountRangeRequest!.LimitHash!.Value, Keccak.MaxValue, false); + progressTracker.ReportAccountRangePartitionFinished(request.AccountRangeRequest!.LimitHash!.Value); + (_, finished) = progressTracker.GetNextRequest(); + finished.Should().BeTrue(); + + memDb.WasFlushed.Should().BeTrue(); + memDb[ProgressTracker.ACC_PROGRESS_KEY].Should().BeEquivalentTo(Keccak.MaxValue.BytesToArray()); + } } diff --git a/src/Nethermind/Nethermind.Synchronization.Test/SyncServerTests.cs b/src/Nethermind/Nethermind.Synchronization.Test/SyncServerTests.cs index 5394cd8e754..8ecab27bc76 100644 --- a/src/Nethermind/Nethermind.Synchronization.Test/SyncServerTests.cs +++ b/src/Nethermind/Nethermind.Synchronization.Test/SyncServerTests.cs @@ -22,6 +22,7 @@ using Nethermind.Merge.Plugin.Handlers; using Nethermind.Merge.Plugin.InvalidChainTracker; using Nethermind.Specs; +using Nethermind.Specs.ChainSpecStyle; using Nethermind.Specs.Forks; using Nethermind.State; using Nethermind.Stats.Model; @@ -180,6 +181,7 @@ public void Terminal_block_with_lower_td_should_not_change_best_suggested_but_sh new MemDb(), localBlockTree, testSpecProvider, + new ChainSpec(), LimboLogs.Instance); HeaderValidator headerValidator = new( localBlockTree, @@ -389,6 +391,7 @@ private Context CreateMergeContext(int blockTreeChainLength, UInt256 ttd) new MemDb(), localBlockTree, testSpecProvider, + new ChainSpec(), LimboLogs.Instance); MergeSealEngine sealEngine = new( new SealEngine(new NethDevSealEngine(), Always.Valid), diff --git a/src/Nethermind/Nethermind.Synchronization.Test/SynchronizerTests.cs b/src/Nethermind/Nethermind.Synchronization.Test/SynchronizerTests.cs index a1ed58c7617..3d2cfd28eef 100644 --- a/src/Nethermind/Nethermind.Synchronization.Test/SynchronizerTests.cs +++ b/src/Nethermind/Nethermind.Synchronization.Test/SynchronizerTests.cs @@ -324,7 +324,7 @@ ISyncConfig GetSyncConfig() => { mergeConfig.TerminalTotalDifficulty = UInt256.MaxValue.ToString(CultureInfo.InvariantCulture); } - PoSSwitcher poSSwitcher = new(mergeConfig, syncConfig, dbProvider.MetadataDb, BlockTree, new TestSingleReleaseSpecProvider(Constantinople.Instance), _logManager); + PoSSwitcher poSSwitcher = new(mergeConfig, syncConfig, dbProvider.MetadataDb, BlockTree, new TestSingleReleaseSpecProvider(Constantinople.Instance), new ChainSpec(), _logManager); IBeaconPivot beaconPivot = new BeaconPivot(syncConfig, dbProvider.MetadataDb, BlockTree, _logManager); TrieStore trieStore = new(stateDb, LimboLogs.Instance); diff --git a/src/Nethermind/Nethermind.Synchronization/IBeaconSyncStrategy.cs b/src/Nethermind/Nethermind.Synchronization/IBeaconSyncStrategy.cs index 264369d4ac7..9043437fe28 100644 --- a/src/Nethermind/Nethermind.Synchronization/IBeaconSyncStrategy.cs +++ b/src/Nethermind/Nethermind.Synchronization/IBeaconSyncStrategy.cs @@ -17,6 +17,7 @@ private No() { } public bool ShouldBeInBeaconModeControl() => false; public bool IsBeaconSyncFinished(BlockHeader? blockHeader) => true; + public bool MergeTransitionFinished => false; public long? GetTargetBlockHeight() => null; public Hash256? GetFinalizedHash() => null; } @@ -27,6 +28,8 @@ public interface IBeaconSyncStrategy bool ShouldBeInBeaconModeControl(); bool IsBeaconSyncFinished(BlockHeader? blockHeader); + public bool MergeTransitionFinished { get; } + public long? GetTargetBlockHeight(); public Hash256? GetFinalizedHash(); } diff --git a/src/Nethermind/Nethermind.Synchronization/ParallelSync/MultiSyncModeSelector.cs b/src/Nethermind/Nethermind.Synchronization/ParallelSync/MultiSyncModeSelector.cs index f7f7c40fcd0..8dc3378cbde 100644 --- a/src/Nethermind/Nethermind.Synchronization/ParallelSync/MultiSyncModeSelector.cs +++ b/src/Nethermind/Nethermind.Synchronization/ParallelSync/MultiSyncModeSelector.cs @@ -356,7 +356,7 @@ private bool ShouldBeInBeaconHeaders(bool shouldBeInUpdatingPivot) private bool ShouldBeInUpdatingPivot() { bool updateRequestedAndNotFinished = _syncConfig.MaxAttemptsToUpdatePivot > 0; - bool isPostMerge = _beaconSyncStrategy.GetFinalizedHash() != null; + bool isPostMerge = _beaconSyncStrategy.MergeTransitionFinished; bool stateSyncNotFinished = _syncProgressResolver.FindBestFullState() == 0; bool result = updateRequestedAndNotFinished && diff --git a/src/Nethermind/Nethermind.Synchronization/SnapSync/ProgressTracker.cs b/src/Nethermind/Nethermind.Synchronization/SnapSync/ProgressTracker.cs index 15b99c6c7f8..f73edf4c79c 100644 --- a/src/Nethermind/Nethermind.Synchronization/SnapSync/ProgressTracker.cs +++ b/src/Nethermind/Nethermind.Synchronization/SnapSync/ProgressTracker.cs @@ -24,7 +24,7 @@ public class ProgressTracker public const int HIGH_STORAGE_QUEUE_SIZE = STORAGE_BATCH_SIZE * 100; private const int CODES_BATCH_SIZE = 1_000; public const int HIGH_CODES_QUEUE_SIZE = CODES_BATCH_SIZE * 5; - private readonly byte[] ACC_PROGRESS_KEY = Encoding.ASCII.GetBytes("AccountProgressKey"); + internal static readonly byte[] ACC_PROGRESS_KEY = Encoding.ASCII.GetBytes("AccountProgressKey"); // This does not need to be a lot as it spawn other requests. In fact 8 is probably too much. It is severely // bottlenecked by _syncCommit lock in SnapProviderHelper, which in turns is limited by the IO. @@ -416,7 +416,8 @@ private void GetSyncProgress() private void FinishRangePhase() { - _db.PutSpan(ACC_PROGRESS_KEY, ValueKeccak.MaxValue.Bytes); + _db.PutSpan(ACC_PROGRESS_KEY, ValueKeccak.MaxValue.Bytes, WriteFlags.DisableWAL); + _db.Flush(); } private void LogRequest(string reqType) diff --git a/src/Nethermind/Nethermind.Trie/PatriciaTree.cs b/src/Nethermind/Nethermind.Trie/PatriciaTree.cs index a66779f4a97..1cedadc144e 100644 --- a/src/Nethermind/Nethermind.Trie/PatriciaTree.cs +++ b/src/Nethermind/Nethermind.Trie/PatriciaTree.cs @@ -53,6 +53,9 @@ public class PatriciaTree private readonly bool _allowCommits; + private readonly bool _isTrace; + private readonly bool _isDebug; + private Hash256 _rootHash = Keccak.EmptyTreeHash; public TrieNode? RootRef { get; set; } @@ -116,6 +119,8 @@ public PatriciaTree( ICappedArrayPool? bufferPool = null) { _logger = logManager?.GetClassLogger() ?? throw new ArgumentNullException(nameof(logManager)); + _isTrace = _logger.IsTrace; + _isDebug = _logger.IsDebug; TrieStore = trieStore ?? throw new ArgumentNullException(nameof(trieStore)); _parallelBranches = parallelBranches; _allowCommits = allowCommits; @@ -137,13 +142,12 @@ public void Commit(long blockNumber, bool skipRoot = false, WriteFlags writeFlag { if (_currentCommit is null) { - throw new InvalidAsynchronousStateException( - $"{nameof(_currentCommit)} is NULL when calling {nameof(Commit)}"); + ThrowInvalidAsynchronousStateException(); } if (!_allowCommits) { - throw new TrieException("Commits are not allowed on this trie."); + ThrowTrieException(); } if (RootRef is not null && RootRef.IsDirty) @@ -151,7 +155,7 @@ public void Commit(long blockNumber, bool skipRoot = false, WriteFlags writeFlag Commit(new NodeCommitInfo(RootRef), skipSelf: skipRoot); while (_currentCommit.TryDequeue(out NodeCommitInfo node)) { - if (_logger.IsTrace) _logger.Trace($"Committing {node} in {blockNumber}"); + if (_isTrace) Trace(blockNumber, node); TrieStore.CommitNode(blockNumber, node, writeFlags: writeFlags); } @@ -161,21 +165,46 @@ public void Commit(long blockNumber, bool skipRoot = false, WriteFlags writeFlag } TrieStore.FinishBlockCommit(TrieType, blockNumber, RootRef, writeFlags); - if (_logger.IsDebug) _logger.Debug($"Finished committing block {blockNumber}"); + + if (_isDebug) Debug(blockNumber); + + [MethodImpl(MethodImplOptions.NoInlining)] + void Trace(long blockNumber, in NodeCommitInfo node) + { + _logger.Trace($"Committing {node} in {blockNumber}"); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + void Debug(long blockNumber) + { + _logger.Debug($"Finished committing block {blockNumber}"); + } + + [DoesNotReturn] + [StackTraceHidden] + static void ThrowInvalidAsynchronousStateException() + { + throw new InvalidAsynchronousStateException($"{nameof(_currentCommit)} is NULL when calling {nameof(Commit)}"); + } + + [DoesNotReturn] + [StackTraceHidden] + static void ThrowTrieException() + { + throw new TrieException("Commits are not allowed on this trie."); + } } private void Commit(NodeCommitInfo nodeCommitInfo, bool skipSelf = false) { if (_currentCommit is null) { - throw new InvalidAsynchronousStateException( - $"{nameof(_currentCommit)} is NULL when calling {nameof(Commit)}"); + ThrowInvalidAsynchronousStateException(nameof(_currentCommit)); } if (_commitExceptions is null) { - throw new InvalidAsynchronousStateException( - $"{nameof(_commitExceptions)} is NULL when calling {nameof(Commit)}"); + ThrowInvalidAsynchronousStateException(nameof(_commitExceptions)); } TrieNode node = nodeCommitInfo.Node; @@ -192,20 +221,16 @@ private void Commit(NodeCommitInfo nodeCommitInfo, bool skipSelf = false) } else { - if (_logger.IsTrace) + if (_isTrace) { - TrieNode child = node.GetChild(TrieStore, i); - if (child is not null) - { - _logger.Trace($"Skipping commit of {child}"); - } + Trace(node, i); } } } } else { - List nodesToCommit = new(); + List nodesToCommit = new(16); for (int i = 0; i < 16; i++) { if (node.IsChildDirty(i)) @@ -214,13 +239,9 @@ private void Commit(NodeCommitInfo nodeCommitInfo, bool skipSelf = false) } else { - if (_logger.IsTrace) + if (_isTrace) { - TrieNode child = node.GetChild(TrieStore, i); - if (child is not null) - { - _logger.Trace($"Skipping commit of {child}"); - } + Trace(node, i); } } } @@ -242,7 +263,7 @@ private void Commit(NodeCommitInfo nodeCommitInfo, bool skipSelf = false) if (!_commitExceptions.IsEmpty) { - throw new AggregateException(_commitExceptions); + ThrowAggregateExceptions(); } } else @@ -259,7 +280,7 @@ private void Commit(NodeCommitInfo nodeCommitInfo, bool skipSelf = false) TrieNode extensionChild = node.GetChild(TrieStore, 0); if (extensionChild is null) { - throw new InvalidOperationException("An attempt to store an extension without a child."); + ThrowInvalidExtension(); } if (extensionChild.IsDirty) @@ -268,7 +289,7 @@ private void Commit(NodeCommitInfo nodeCommitInfo, bool skipSelf = false) } else { - if (_logger.IsTrace) _logger.Trace($"Skipping commit of {extensionChild}"); + if (_isTrace) TraceExtensionSkip(extensionChild); } } @@ -284,7 +305,50 @@ private void Commit(NodeCommitInfo nodeCommitInfo, bool skipSelf = false) } else { - if (_logger.IsTrace) _logger.Trace($"Skipping commit of an inlined {node}"); + if (_isTrace) TraceSkipInlineNode(node); + } + + [DoesNotReturn] + [StackTraceHidden] + void ThrowAggregateExceptions() + { + throw new AggregateException(_commitExceptions); + } + + [DoesNotReturn] + [StackTraceHidden] + static void ThrowInvalidExtension() + { + throw new InvalidOperationException("An attempt to store an extension without a child."); + } + + [DoesNotReturn] + [StackTraceHidden] + static void ThrowInvalidAsynchronousStateException(string param) + { + throw new InvalidAsynchronousStateException($"{param} is NULL when calling {nameof(Commit)}"); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + void Trace(TrieNode node, int i) + { + TrieNode child = node.GetChild(TrieStore, i); + if (child is not null) + { + _logger.Trace($"Skipping commit of {child}"); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + void TraceExtensionSkip(TrieNode extensionChild) + { + _logger.Trace($"Skipping commit of {extensionChild}"); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + void TraceSkipInlineNode(TrieNode node) + { + _logger.Trace($"Skipping commit of an inlined {node}"); } } @@ -320,15 +384,11 @@ private void SetRootHash(Hash256? value, bool resetObjects) : array = ArrayPool.Shared.Rent(nibblesCount)) [..nibblesCount]; // Slice to exact size; - try - { - Nibbles.BytesToNibbleBytes(rawKey, nibbles); - return Run(nibbles, nibblesCount, new CappedArray(Array.Empty()), false, startRootHash: rootHash).ToArray(); - } - finally - { - if (array is not null) ArrayPool.Shared.Return(array); - } + Nibbles.BytesToNibbleBytes(rawKey, nibbles); + var result = Run(nibbles, nibblesCount, new CappedArray(Array.Empty()), false, startRootHash: rootHash).ToArray(); + if (array is not null) ArrayPool.Shared.Return(array); + + return result; } catch (TrieException e) { @@ -337,6 +397,7 @@ private void SetRootHash(Hash256? value, bool resetObjects) } } + [MethodImpl(MethodImplOptions.NoInlining)] private static void EnhanceException(ReadOnlySpan rawKey, ValueHash256 rootHash, TrieException baseException) { static TrieNodeException? GetTrieNodeException(TrieException? exception) => @@ -367,8 +428,7 @@ public virtual void Set(ReadOnlySpan rawKey, byte[] value) [DebuggerStepThrough] public virtual void Set(ReadOnlySpan rawKey, CappedArray value) { - if (_logger.IsTrace) - _logger.Trace($"{(value.Length == 0 ? $"Deleting {rawKey.ToHexString()}" : $"Setting {rawKey.ToHexString()} = {value.AsSpan().ToHexString()}")}"); + if (_isTrace) Trace(in rawKey, in value); int nibblesCount = 2 * rawKey.Length; byte[] array = null; @@ -377,14 +437,14 @@ public virtual void Set(ReadOnlySpan rawKey, CappedArray value) : array = ArrayPool.Shared.Rent(nibblesCount)) [..nibblesCount]; // Slice to exact size - try - { - Nibbles.BytesToNibbleBytes(rawKey, nibbles); - Run(nibbles, nibblesCount, value, true); - } - finally + Nibbles.BytesToNibbleBytes(rawKey, nibbles); + Run(nibbles, nibblesCount, value, true); + + if (array is not null) ArrayPool.Shared.Return(array); + + void Trace(in ReadOnlySpan rawKey, in CappedArray value) { - if (array is not null) ArrayPool.Shared.Return(array); + _logger.Trace($"{(value.Length == 0 ? $"Deleting {rawKey.ToHexString()}" : $"Setting {rawKey.ToHexString()} = {value.AsSpan().ToHexString()}")}"); } } @@ -404,7 +464,7 @@ private CappedArray Run( { if (isUpdate && startRootHash is not null) { - throw new InvalidOperationException("Only reads can be done in parallel on the Patricia tree"); + ThrowNonConcurrentWrites(); } #if DEBUG @@ -426,7 +486,7 @@ private CappedArray Run( CappedArray result; if (startRootHash is not null) { - if (_logger.IsTrace) _logger.Trace($"Starting from {startRootHash} - {traverseContext.ToString()}"); + if (_isTrace) TraceStart(startRootHash, in traverseContext); TrieNode startNode = TrieStore.FindCachedOrUnknown(startRootHash); ResolveNode(startNode, in traverseContext); result = TraverseNode(startNode, in traverseContext); @@ -438,23 +498,50 @@ private CappedArray Run( { if (traverseContext.UpdateValue.IsNotNull) { - if (_logger.IsTrace) _logger.Trace($"Setting new leaf node with value {traverseContext.UpdateValue}"); + if (_isTrace) TraceNewLeaf(in traverseContext); byte[] key = updatePath[..nibblesCount].ToArray(); RootRef = TrieNodeFactory.CreateLeaf(key, traverseContext.UpdateValue); } - if (_logger.IsTrace) _logger.Trace($"Keeping the root as null in {traverseContext.ToString()}"); + if (_isTrace) TraceNull(in traverseContext); result = traverseContext.UpdateValue; } else { ResolveNode(RootRef, in traverseContext); - if (_logger.IsTrace) _logger.Trace($"{traverseContext.ToString()}"); + if (_isTrace) TraceNode(in traverseContext); result = TraverseNode(RootRef, in traverseContext); } } return result; + + [DoesNotReturn] + [StackTraceHidden] + static void ThrowNonConcurrentWrites() + { + throw new InvalidOperationException("Only reads can be done in parallel on the Patricia tree"); + } + + void TraceStart(Hash256 startRootHash, in TraverseContext traverseContext) + { + _logger.Trace($"Starting from {startRootHash} - {traverseContext.ToString()}"); + } + + void TraceNewLeaf(in TraverseContext traverseContext) + { + _logger.Trace($"Setting new leaf node with value {traverseContext.UpdateValue}"); + } + + void TraceNull(in TraverseContext traverseContext) + { + _logger.Trace($"Keeping the root as null in {traverseContext.ToString()}"); + } + + void TraceNode(in TraverseContext traverseContext) + { + _logger.Trace($"{traverseContext.ToString()}"); + } } private void ResolveNode(TrieNode node, in TraverseContext traverseContext) @@ -471,20 +558,36 @@ private void ResolveNode(TrieNode node, in TraverseContext traverseContext) private CappedArray TraverseNode(TrieNode node, in TraverseContext traverseContext) { - if (_logger.IsTrace) - _logger.Trace( - $"Traversing {node} to {(traverseContext.IsRead ? "READ" : traverseContext.IsDelete ? "DELETE" : "UPDATE")}"); + if (_isTrace) Trace(node, traverseContext); return node.NodeType switch { NodeType.Branch => TraverseBranch(node, in traverseContext), NodeType.Extension => TraverseExtension(node, in traverseContext), NodeType.Leaf => TraverseLeaf(node, in traverseContext), - NodeType.Unknown => throw new InvalidOperationException( - $"Cannot traverse unresolved node {node.Keccak}"), - _ => throw new NotSupportedException( - $"Unknown node type {node.NodeType}") + NodeType.Unknown => TraverseUnknown(node), + _ => ThrowNotSupported(node) }; + + [MethodImpl(MethodImplOptions.NoInlining)] + void Trace(TrieNode node, in TraverseContext traverseContext) + { + _logger.Trace($"Traversing {node} to {(traverseContext.IsRead ? "READ" : traverseContext.IsDelete ? "DELETE" : "UPDATE")}"); + } + + [DoesNotReturn] + [StackTraceHidden] + static CappedArray TraverseUnknown(TrieNode node) + { + throw new InvalidOperationException($"Cannot traverse unresolved node {node.Keccak}"); + } + + [DoesNotReturn] + [StackTraceHidden] + static CappedArray ThrowNotSupported(TrieNode node) + { + throw new NotSupportedException($"Unknown node type {node.NodeType}"); + } } private void ConnectNodes(TrieNode? node, in TraverseContext traverseContext) @@ -525,7 +628,7 @@ private void ConnectNodes(TrieNode? node, in TraverseContext traverseContext) // which is not possible in the Ethereum protocol where keys are of equal lengths // (it is possible in the more general trie definition) TrieNode leafFromBranch = TrieNodeFactory.CreateLeaf(Array.Empty(), node.Value); - if (_logger.IsTrace) _logger.Trace($"Converting {node} into {leafFromBranch}"); + if (_isTrace) _logger.Trace($"Converting {node} into {leafFromBranch}"); nextNode = leafFromBranch; } else @@ -567,7 +670,7 @@ L X - - - - - - - - - - - - - - */ { TrieNode extensionFromBranch = TrieNodeFactory.CreateExtension(new[] { (byte)childNodeIndex }, childNode); - if (_logger.IsTrace) + if (_isTrace) _logger.Trace( $"Extending child {childNodeIndex} {childNode} of {node} into {extensionFromBranch}"); @@ -603,7 +706,7 @@ L L - - - - - - - - - - - - - - */ byte[] newKey = Bytes.Concat((byte)childNodeIndex, childNode.Key); TrieNode extendedExtension = childNode.CloneWithChangedKey(newKey); - if (_logger.IsTrace) + if (_isTrace) _logger.Trace( $"Extending child {childNodeIndex} {childNode} of {node} into {extendedExtension}"); nextNode = extendedExtension; @@ -613,14 +716,14 @@ L L - - - - - - - - - - - - - - */ byte[] newKey = Bytes.Concat((byte)childNodeIndex, childNode.Key); TrieNode extendedLeaf = childNode.CloneWithChangedKey(newKey); - if (_logger.IsTrace) + if (_isTrace) _logger.Trace( $"Extending branch child {childNodeIndex} {childNode} into {extendedLeaf}"); - if (_logger.IsTrace) _logger.Trace($"Decrementing ref on a leaf extended up to eat a branch {childNode}"); + if (_isTrace) _logger.Trace($"Decrementing ref on a leaf extended up to eat a branch {childNode}"); if (node.IsSealed) { - if (_logger.IsTrace) _logger.Trace($"Decrementing ref on a branch replaced by a leaf {node}"); + if (_isTrace) _logger.Trace($"Decrementing ref on a branch replaced by a leaf {node}"); } nextNode = extendedLeaf; @@ -644,7 +747,7 @@ L L - - - - - - - - - - - - - - */ { byte[] newKey = Bytes.Concat(node.Key, nextNode.Key); TrieNode extendedLeaf = nextNode.CloneWithChangedKey(newKey); - if (_logger.IsTrace) + if (_isTrace) _logger.Trace($"Combining {node} and {nextNode} into {extendedLeaf}"); nextNode = extendedLeaf; @@ -678,7 +781,7 @@ L L - - - - - - - - - - - - - - */ byte[] newKey = Bytes.Concat(node.Key, nextNode.Key); TrieNode extendedExtension = nextNode.CloneWithChangedKey(newKey); - if (_logger.IsTrace) + if (_isTrace) _logger.Trace($"Combining {node} and {nextNode} into {extendedExtension}"); nextNode = extendedExtension; @@ -690,7 +793,7 @@ L L - - - - - - - - - - - - - - */ node = node.Clone(); } - if (_logger.IsTrace) _logger.Trace($"Connecting {node} with {nextNode}"); + if (_isTrace) _logger.Trace($"Connecting {node} with {nextNode}"); node.SetChild(0, nextNode); nextNode = node; } @@ -815,7 +918,7 @@ private CappedArray TraverseLeaf(TrieNode node, in TraverseContext travers longerPathValue = node.Value; } - int extensionLength = FindCommonPrefixLength(shorterPath, longerPath); + int extensionLength = shorterPath.CommonPrefixLength(longerPath); if (extensionLength == shorterPath.Length && extensionLength == longerPath.Length) { if (traverseContext.IsRead) @@ -893,7 +996,7 @@ private CappedArray TraverseExtension(TrieNode node, in TraverseContext tr TrieNode originalNode = node; ReadOnlySpan remaining = traverseContext.GetRemainingUpdatePath(); - int extensionLength = FindCommonPrefixLength(remaining, node.Key); + int extensionLength = remaining.CommonPrefixLength(node.Key); if (extensionLength == node.Key.Length) { if (traverseContext.IsUpdate) @@ -978,18 +1081,6 @@ private CappedArray TraverseNext(in TraverseContext traverseContext, int e return TraverseNode(next, in newContext); } - private static int FindCommonPrefixLength(ReadOnlySpan shorterPath, ReadOnlySpan longerPath) - { - int commonPrefixLength = 0; - int maxLength = Math.Min(shorterPath.Length, longerPath.Length); - for (int i = 0; i < maxLength && shorterPath[i] == longerPath[i]; i++, commonPrefixLength++) - { - // just finding the common part of the path - } - - return commonPrefixLength; - } - private readonly ref struct TraverseContext { public CappedArray UpdateValue { get; } diff --git a/src/Nethermind/Nethermind.Trie/TrieNode.Decoder.cs b/src/Nethermind/Nethermind.Trie/TrieNode.Decoder.cs index a8bf54f78ba..5a87b3c1e1c 100644 --- a/src/Nethermind/Nethermind.Trie/TrieNode.Decoder.cs +++ b/src/Nethermind/Nethermind.Trie/TrieNode.Decoder.cs @@ -4,7 +4,7 @@ using System; using System.Buffers; using System.Diagnostics; -using System.Linq; +using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using Nethermind.Core.Buffers; using Nethermind.Core.Crypto; @@ -29,7 +29,7 @@ public static CappedArray Encode(ITrieNodeResolver tree, TrieNode? item, I if (item is null) { - throw new TrieException("An attempt was made to RLP encode a null node."); + ThrowNullNode(); } return item.NodeType switch @@ -37,8 +37,22 @@ public static CappedArray Encode(ITrieNodeResolver tree, TrieNode? item, I NodeType.Branch => RlpEncodeBranch(tree, item, bufferPool), NodeType.Extension => EncodeExtension(tree, item, bufferPool), NodeType.Leaf => EncodeLeaf(item, bufferPool), - _ => throw new TrieException($"An attempt was made to encode a trie node of type {item.NodeType}") + _ => ThrowUnhandledNodeType(item) }; + + [DoesNotReturn] + [StackTraceHidden] + static void ThrowNullNode() + { + throw new TrieException("An attempt was made to RLP encode a null node."); + } + + [DoesNotReturn] + [StackTraceHidden] + static CappedArray ThrowUnhandledNodeType(TrieNode item) + { + throw new TrieException($"An attempt was made to encode a trie node of type {item.NodeType}"); + } } [SkipLocalsInit] @@ -101,7 +115,7 @@ private static CappedArray EncodeLeaf(TrieNode node, ICappedArrayPool? poo { if (node.Key is null) { - throw new TrieException($"Hex prefix of a leaf node is null at node {node.Keccak}"); + ThrowNullKey(node); } byte[] hexPrefix = node.Key; @@ -130,6 +144,13 @@ private static CappedArray EncodeLeaf(TrieNode node, ICappedArrayPool? poo return data; } + [DoesNotReturn] + [StackTraceHidden] + private static void ThrowNullKey(TrieNode node) + { + throw new TrieException($"Hex prefix of a leaf node is null at node {node.Keccak}"); + } + private static CappedArray RlpEncodeBranch(ITrieNodeResolver tree, TrieNode item, ICappedArrayPool? pool) { int valueRlpLength = AllowBranchValues ? Rlp.LengthOf(item.Value.AsSpan()) : 1; diff --git a/src/Nethermind/Nethermind.Trie/TrieNode.cs b/src/Nethermind/Nethermind.Trie/TrieNode.cs index bb229a48678..281c326fca1 100644 --- a/src/Nethermind/Nethermind.Trie/TrieNode.cs +++ b/src/Nethermind/Nethermind.Trie/TrieNode.cs @@ -3,6 +3,8 @@ using System; using System.ComponentModel; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using System.Threading; using Nethermind.Core; @@ -73,13 +75,19 @@ internal set { if (IsSealed) { - throw new InvalidOperationException( - $"{nameof(TrieNode)} {this} is already sealed when setting {nameof(Key)}."); + ThrowAlreadySealed(); } InitData(); _data![0] = value; Keccak = null; + + [DoesNotReturn] + [StackTraceHidden] + void ThrowAlreadySealed() + { + throw new InvalidOperationException($"{nameof(TrieNode)} {this} is already sealed when setting {nameof(Key)}."); + } } } @@ -144,8 +152,7 @@ public CappedArray Value { if (IsSealed) { - throw new InvalidOperationException( - $"{nameof(TrieNode)} {this} is already sealed when setting {nameof(Value)}."); + ThrowAlreadySealed(); } InitData(); @@ -170,6 +177,13 @@ public CappedArray Value } _data![IsLeaf ? 1 : BranchesCount] = value; + + [DoesNotReturn] + [StackTraceHidden] + void ThrowAlreadySealed() + { + throw new InvalidOperationException($"{nameof(TrieNode)} {this} is already sealed when setting {nameof(Value)}."); + } } } @@ -262,10 +276,17 @@ public void Seal() { if (IsSealed) { - throw new InvalidOperationException($"{nameof(TrieNode)} {this} is already sealed."); + ThrowAlreadySealed(); } IsDirty = false; + + [DoesNotReturn] + [StackTraceHidden] + void ThrowAlreadySealed() + { + throw new InvalidOperationException($"{nameof(TrieNode)} {this} is already sealed."); + } } /// @@ -281,7 +302,7 @@ public void ResolveNode(ITrieNodeResolver tree, ReadFlags readFlags = ReadFlags. { if (Keccak is null) { - throw new TrieException("Unable to resolve node without Keccak"); + ThrowMissingKeccak(); } FullRlp = tree.LoadRlp(Keccak, readFlags); @@ -289,7 +310,7 @@ public void ResolveNode(ITrieNodeResolver tree, ReadFlags readFlags = ReadFlags. if (FullRlp.IsNull) { - throw new TrieException($"Trie returned a NULL RLP for node {Keccak}"); + ThrowNullRlp(); } } } @@ -301,15 +322,51 @@ public void ResolveNode(ITrieNodeResolver tree, ReadFlags readFlags = ReadFlags. _rlpStream = FullRlp.AsRlpStream(); if (_rlpStream is null) { - throw new InvalidAsynchronousStateException($"{nameof(_rlpStream)} is null when {nameof(NodeType)} is {NodeType}"); + ThrowInvalidStateException(); + return; } if (!DecodeRlp(bufferPool, out int numberOfItems)) { - throw new TrieNodeException($"Unexpected number of items = {numberOfItems} when decoding a node from RLP ({FullRlp.AsSpan().ToHexString()})", Keccak ?? Nethermind.Core.Crypto.Keccak.Zero); + ThrowUnexpectedNumberOfItems(numberOfItems); } } catch (RlpException rlpException) + { + ThrowDecodingError(rlpException); + } + + [DoesNotReturn] + [StackTraceHidden] + static void ThrowMissingKeccak() + { + throw new TrieException("Unable to resolve node without Keccak"); + } + + [DoesNotReturn] + [StackTraceHidden] + void ThrowNullRlp() + { + throw new TrieException($"Trie returned a NULL RLP for node {Keccak}"); + } + + [DoesNotReturn] + [StackTraceHidden] + void ThrowInvalidStateException() + { + throw new InvalidAsynchronousStateException($"{nameof(_rlpStream)} is null when {nameof(NodeType)} is {NodeType}"); + } + + [DoesNotReturn] + [StackTraceHidden] + void ThrowUnexpectedNumberOfItems(int numberOfItems) + { + throw new TrieNodeException($"Unexpected number of items = {numberOfItems} when decoding a node from RLP ({FullRlp.AsSpan().ToHexString()})", Keccak ?? Nethermind.Core.Crypto.Keccak.Zero); + } + + [DoesNotReturn] + [StackTraceHidden] + void ThrowDecodingError(RlpException rlpException) { throw new TrieNodeException($"Error when decoding node {Keccak}", Keccak ?? Nethermind.Core.Crypto.Keccak.Zero, rlpException); } @@ -348,7 +405,7 @@ public bool TryResolveNode(ITrieNodeResolver tree, ReadFlags readFlags = ReadFla _rlpStream = FullRlp.AsRlpStream(); if (_rlpStream is null) { - throw new InvalidAsynchronousStateException($"{nameof(_rlpStream)} is null when {nameof(NodeType)} is {NodeType}"); + ThrowInvalidStateException(); } return DecodeRlp(bufferPool, out _); @@ -357,6 +414,13 @@ public bool TryResolveNode(ITrieNodeResolver tree, ReadFlags readFlags = ReadFla { return false; } + + [DoesNotReturn] + [StackTraceHidden] + void ThrowInvalidStateException() + { + throw new InvalidAsynchronousStateException($"{nameof(_rlpStream)} is null when {nameof(NodeType)} is {NodeType}"); + } } private bool DecodeRlp(ICappedArrayPool bufferPool, out int itemsCount) @@ -529,8 +593,7 @@ public bool IsChildNull(int i) { if (!IsBranch) { - throw new TrieException( - "An attempt was made to ask about whether a child is null on a non-branch node."); + ThrowNotABranch(); } if (_rlpStream is not null && _data?[i] is null) @@ -540,6 +603,13 @@ public bool IsChildNull(int i) } return _data?[i] is null || ReferenceEquals(_data[i], _nullNode); + + [DoesNotReturn] + [StackTraceHidden] + static void ThrowNotABranch() + { + throw new TrieException("An attempt was made to ask about whether a child is null on a non-branch node."); + } } public bool IsChildDirty(int i) @@ -598,9 +668,7 @@ public TrieNode? this[int i] { // we expect this to happen as a Trie traversal error (please see the stack trace above) // we need to investigate this case when it happens again - bool isKeccakCalculated = Keccak is not null && FullRlp.IsNotNull; - bool isKeccakCorrect = isKeccakCalculated && Keccak == Nethermind.Core.Crypto.Keccak.Compute(FullRlp.AsSpan()); - throw new TrieException($"Unexpected type found at position {childIndex} of {this} with {nameof(_data)} of length {_data?.Length}. Expected a {nameof(TrieNode)} or {nameof(Keccak)} but found {childOrRef?.GetType()} with a value of {childOrRef}. Keccak calculated? : {isKeccakCalculated}; Keccak correct? : {isKeccakCorrect}"); + ThrowUnexpectedTypeException(childIndex, childOrRef); } // pruning trick so we never store long persisted paths @@ -610,6 +678,15 @@ public TrieNode? this[int i] } return child; + + [DoesNotReturn] + [StackTraceHidden] + void ThrowUnexpectedTypeException(int childIndex, object childOrRef) + { + bool isKeccakCalculated = Keccak is not null && FullRlp.IsNotNull; + bool isKeccakCorrect = isKeccakCalculated && Keccak == Nethermind.Core.Crypto.Keccak.Compute(FullRlp.AsSpan()); + throw new TrieException($"Unexpected type found at position {childIndex} of {this} with {nameof(_data)} of length {_data?.Length}. Expected a {nameof(TrieNode)} or {nameof(Keccak)} but found {childOrRef?.GetType()} with a value of {childOrRef}. Keccak calculated? : {isKeccakCalculated}; Keccak correct? : {isKeccakCorrect}"); + } } public void ReplaceChildRef(int i, TrieNode child) @@ -628,14 +705,20 @@ public void SetChild(int i, TrieNode? node) { if (IsSealed) { - throw new InvalidOperationException( - $"{nameof(TrieNode)} {this} is already sealed when setting a child."); + ThrowAlreadySealed(); } InitData(); int index = IsExtension ? i + 1 : i; _data![index] = node ?? _nullNode; Keccak = null; + + [DoesNotReturn] + [StackTraceHidden] + void ThrowAlreadySealed() + { + throw new InvalidOperationException($"{nameof(TrieNode)} {this} is already sealed when setting a child."); + } } public long GetMemorySize(bool recursive) @@ -857,8 +940,6 @@ public void PrunePersistedRecursively(int maxLevelsDeep) // } } - #region private - private bool TryResolveStorageRoot(ITrieNodeResolver resolver, out TrieNode? storageRoot) { bool hasStorage = false; @@ -891,8 +972,8 @@ private void InitData() switch (NodeType) { case NodeType.Unknown: - throw new InvalidOperationException( - $"Cannot resolve children of an {nameof(NodeType.Unknown)} node"); + ThrowCannotResolveException(); + return; case NodeType.Branch: _data = new object[AllowBranchValues ? BranchesCount + 1 : BranchesCount]; break; @@ -901,6 +982,13 @@ private void InitData() break; } } + + [DoesNotReturn] + [StackTraceHidden] + static void ThrowCannotResolveException() + { + throw new InvalidOperationException($"Cannot resolve children of an {nameof(NodeType.Unknown)} node"); + } } private void SeekChild(int itemToSetOn) @@ -999,7 +1087,7 @@ private void UnresolveChild(int i) { if (!childNode.IsPersisted) { - throw new InvalidOperationException("Cannot unresolve a child that is not persisted yet."); + ThrowNotPersisted(); } else if (childNode.Keccak is not null) // if not by value node { @@ -1007,8 +1095,13 @@ private void UnresolveChild(int i) } } } - } - #endregion + [DoesNotReturn] + [StackTraceHidden] + static void ThrowNotPersisted() + { + throw new InvalidOperationException("Cannot unresolve a child that is not persisted yet."); + } + } } } diff --git a/src/Nethermind/Nethermind.TxPool/BlobTxStorage.cs b/src/Nethermind/Nethermind.TxPool/BlobTxStorage.cs index 4ba704d7c54..e05f726d6e1 100644 --- a/src/Nethermind/Nethermind.TxPool/BlobTxStorage.cs +++ b/src/Nethermind/Nethermind.TxPool/BlobTxStorage.cs @@ -65,7 +65,7 @@ public void Add(Transaction transaction) Span txHashPrefixed = stackalloc byte[64]; GetHashPrefixedByTimestamp(transaction.Timestamp, transaction.Hash, txHashPrefixed); - _fullBlobTxsDb.PutSpan(txHashPrefixed, EncodeTx(transaction)); + EncodeAndSaveTx(transaction, _fullBlobTxsDb, txHashPrefixed); _lightBlobTxsDb.Set(transaction.Hash, LightTxDecoder.Encode(transaction)); } @@ -85,7 +85,7 @@ public void AddBlobTransactionsFromBlock(long blockNumber, IList bl return; } - _processedBlobTxsDb.Set(blockNumber, EncodeTxs(blockBlobTransactions)); + EncodeAndSaveTxs(blockBlobTransactions, _processedBlobTxsDb, blockNumber); } public bool TryGetBlobTransactionsFromBlock(long blockNumber, out Transaction[]? blockBlobTransactions) @@ -138,17 +138,17 @@ private static void GetHashPrefixedByTimestamp(UInt256 timestamp, ValueHash256 h hash.Bytes.CopyTo(txHashPrefixed[32..]); } - private Span EncodeTx(Transaction transaction) + private void EncodeAndSaveTx(Transaction transaction, IDb db, Span txHashPrefixed) { int length = _txDecoder.GetLength(transaction, RlpBehaviors.InMempoolForm); IByteBuffer byteBuffer = PooledByteBufferAllocator.Default.Buffer(length); using NettyRlpStream rlpStream = new(byteBuffer); rlpStream.Encode(transaction, RlpBehaviors.InMempoolForm); - return byteBuffer.AsSpan(); + db.PutSpan(txHashPrefixed, byteBuffer.AsSpan()); } - private byte[] EncodeTxs(IList blockBlobTransactions) + private void EncodeAndSaveTxs(IList blockBlobTransactions, IDb db, long blockNumber) { int contentLength = GetLength(blockBlobTransactions); @@ -160,7 +160,7 @@ private byte[] EncodeTxs(IList blockBlobTransactions) _txDecoder.Encode(rlpStream, transaction, RlpBehaviors.InMempoolForm); } - return byteBuffer.Array; + db.Set(blockNumber, byteBuffer.Array); } private int GetLength(IList blockBlobTransactions)