diff --git a/src/Nethermind/Nethermind.Api/IApiWithBlockchain.cs b/src/Nethermind/Nethermind.Api/IApiWithBlockchain.cs index da24eaa918b..ffd5934f56d 100644 --- a/src/Nethermind/Nethermind.Api/IApiWithBlockchain.cs +++ b/src/Nethermind/Nethermind.Api/IApiWithBlockchain.cs @@ -23,6 +23,7 @@ using Nethermind.JsonRpc; using Nethermind.JsonRpc.Modules.Eth.GasPrice; using Nethermind.State; +using Nethermind.Synchronization.FastSync; using Nethermind.Trie; using Nethermind.Trie.Pruning; using Nethermind.TxPool; @@ -63,6 +64,7 @@ public interface IApiWithBlockchain : IApiWithStores, IBlockchainBridgeFactory /// DO NOT USE OUTSIDE OF PROCESSING BLOCK CONTEXT! /// IWorldState? WorldState { get; set; } + IBlockingVerifyTrie? BlockingVerifyTrie { get; set; } IReadOnlyStateProvider? ChainHeadStateProvider { get; set; } IStateReader? StateReader { get; set; } IWorldStateManager? WorldStateManager { get; set; } diff --git a/src/Nethermind/Nethermind.Api/NethermindApi.cs b/src/Nethermind/Nethermind.Api/NethermindApi.cs index 1e7ad8cfdd4..3abc9a2dc5b 100644 --- a/src/Nethermind/Nethermind.Api/NethermindApi.cs +++ b/src/Nethermind/Nethermind.Api/NethermindApi.cs @@ -58,6 +58,7 @@ using Nethermind.Trie; using Nethermind.Consensus.Processing.CensorshipDetector; using Nethermind.Facade.Find; +using Nethermind.Synchronization.FastSync; namespace Nethermind.Api { @@ -196,6 +197,7 @@ public ISealEngine SealEngine public IPeerDifficultyRefreshPool? PeerDifficultyRefreshPool => ApiWithNetworkServiceContainer?.Resolve(); public ISynchronizer? Synchronizer => ApiWithNetworkServiceContainer?.Resolve(); public ISyncServer? SyncServer => ApiWithNetworkServiceContainer?.Resolve(); + public IBlockingVerifyTrie? BlockingVerifyTrie { get; set; } public IWorldState? WorldState { get; set; } public IReadOnlyStateProvider? ChainHeadStateProvider { get; set; } public IWorldStateManager? WorldStateManager { get; set; } diff --git a/src/Nethermind/Nethermind.Init/InitializeStateDb.cs b/src/Nethermind/Nethermind.Init/InitializeStateDb.cs index 4fd09fe8e97..261bc3ecdaa 100644 --- a/src/Nethermind/Nethermind.Init/InitializeStateDb.cs +++ b/src/Nethermind/Nethermind.Init/InitializeStateDb.cs @@ -22,6 +22,7 @@ using Nethermind.Logging; using Nethermind.Serialization.Json; using Nethermind.State; +using Nethermind.Synchronization.FastSync; using Nethermind.Synchronization.Trie; using Nethermind.Trie; using Nethermind.Trie.Pruning; @@ -87,7 +88,7 @@ public Task Execute(CancellationToken cancellationToken) syncConfig.DownloadBodiesInFastSync = true; } - IKeyValueStore codeDb = getApi.DbProvider.CodeDb; + IDb codeDb = getApi.DbProvider.CodeDb; IKeyValueStoreWithBatching stateDb = getApi.DbProvider.StateDb; IPersistenceStrategy persistenceStrategy; IPruningStrategy pruningStrategy; @@ -185,6 +186,8 @@ public Task Execute(CancellationToken cancellationToken) getApi.DbProvider, getApi.LogManager); + setApi.BlockingVerifyTrie = new BlockingVerifyTrie(mainWorldTrieStore, stateManager.GlobalStateReader, codeDb!, getApi.ProcessExit!, getApi.LogManager); + // TODO: Don't forget this TrieStoreBoundaryWatcher trieStoreBoundaryWatcher = new(stateManager, _api.BlockTree!, _api.LogManager); getApi.DisposeStack.Push(trieStoreBoundaryWatcher); @@ -199,9 +202,12 @@ public Task Execute(CancellationToken cancellationToken) if (_api.Config().DiagnosticMode == DiagnosticMode.VerifyTrie) { _logger!.Info("Collecting trie stats and verifying that no nodes are missing..."); - Hash256 stateRoot = getApi.BlockTree!.Head?.StateRoot ?? Keccak.EmptyTreeHash; - TrieStats stats = stateManager.GlobalStateReader.CollectStats(stateRoot, getApi.DbProvider.CodeDb, _api.LogManager, _api.ProcessExit!.Token); - _logger.Info($"Starting from {getApi.BlockTree.Head?.Number} {getApi.BlockTree.Head?.StateRoot}{Environment.NewLine}" + stats); + BlockHeader? head = getApi.BlockTree!.Head?.Header; + if (head is not null) + { + setApi.BlockingVerifyTrie.TryStartVerifyTrie(head); + _logger.Info($"Starting from {head.Number} {head.StateRoot}{Environment.NewLine}"); + } } // Init state if we need system calls before actual processing starts diff --git a/src/Nethermind/Nethermind.Init/Steps/RegisterRpcModules.cs b/src/Nethermind/Nethermind.Init/Steps/RegisterRpcModules.cs index daa7ce6fc7d..8f15d15d8e2 100644 --- a/src/Nethermind/Nethermind.Init/Steps/RegisterRpcModules.cs +++ b/src/Nethermind/Nethermind.Init/Steps/RegisterRpcModules.cs @@ -127,11 +127,14 @@ public virtual async Task Execute(CancellationToken cancellationToken) ManualPruningTrigger pruningTrigger = new(); _api.PruningTrigger.Add(pruningTrigger); (IApiWithStores getFromApi, IApiWithBlockchain setInApi) = _api.ForInit; + AdminRpcModule adminRpcModule = new( _api.BlockTree, networkConfig, _api.PeerPool, _api.StaticNodesManager, + _api.BlockingVerifyTrie!, + _api.WorldStateManager.GlobalStateReader, _api.Enode, initConfig.BaseDbPath, pruningTrigger, diff --git a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/AdminModuleTests.cs b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/AdminModuleTests.cs index c3d123f4a53..fdada32f4d1 100644 --- a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/AdminModuleTests.cs +++ b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/AdminModuleTests.cs @@ -18,7 +18,9 @@ using Nethermind.Network.Config; using Nethermind.Serialization.Json; using Nethermind.Specs.ChainSpecStyle; +using Nethermind.State; using Nethermind.Stats.Model; +using Nethermind.Synchronization.FastSync; using NSubstitute; using NUnit.Framework; @@ -32,6 +34,8 @@ public class AdminModuleTests private EthereumJsonSerializer _serializer = null!; private NetworkConfig _networkConfig = null!; private IBlockTree _blockTree = null!; + private IBlockingVerifyTrie _blockingVerifyTrie = null!; + private IStateReader _stateReader = null!; private const string _enodeString = "enode://e1b7e0dc09aae610c9dec8a0bee62bab9946cc27ebdd2f9e3571ed6d444628f99e91e43f4a14d42d498217608bb3e1d1bc8ec2aa27d7f7e423413b851bae02bc@127.0.0.1:30303"; private const string _exampleDataDir = "/example/dbdir"; @@ -39,6 +43,8 @@ public class AdminModuleTests public void Setup() { _blockTree = Build.A.BlockTree().OfChainLength(5).TestObject; + _blockingVerifyTrie = Substitute.For(); + _stateReader = Substitute.For(); _networkConfig = new NetworkConfig(); IPeerPool peerPool = Substitute.For(); ConcurrentDictionary dict = new(); @@ -57,6 +63,8 @@ public void Setup() _networkConfig, peerPool, staticNodesManager, + _blockingVerifyTrie, + _stateReader, enode, _exampleDataDir, new ManualPruningTrigger(), @@ -110,6 +118,23 @@ public async Task Test_admin_dataDir() response.Result!.ToString().Should().Be(_exampleDataDir); } + [Test] + public async Task Test_admin_verifyTrie() + { + (await RpcTest.TestSerializedRequest(_adminRpcModule, "admin_verifyTrie", "latest")).Should().Contain("Unable to start verify trie"); + _stateReader.HasStateForRoot(Arg.Any()).Returns(true); + _blockingVerifyTrie.TryStartVerifyTrie(Arg.Any()).Returns(true); + (await RpcTest.TestSerializedRequest(_adminRpcModule, "admin_verifyTrie", "latest")).Should().Contain("Starting"); + } + + [Test] + public async Task Test_hasStateForBlock() + { + (await RpcTest.TestSerializedRequest(_adminRpcModule, "admin_isStateRootAvailable", "latest")).Should().Contain("false"); + _stateReader.HasStateForRoot(Arg.Any()).Returns(true); + (await RpcTest.TestSerializedRequest(_adminRpcModule, "admin_isStateRootAvailable", "latest")).Should().Contain("true"); + } + [Test] public async Task Smoke_solc() { diff --git a/src/Nethermind/Nethermind.JsonRpc/Modules/Admin/AdminRpcModule.cs b/src/Nethermind/Nethermind.JsonRpc/Modules/Admin/AdminRpcModule.cs index a6c501da755..6ccd648c721 100644 --- a/src/Nethermind/Nethermind.JsonRpc/Modules/Admin/AdminRpcModule.cs +++ b/src/Nethermind/Nethermind.JsonRpc/Modules/Admin/AdminRpcModule.cs @@ -5,6 +5,7 @@ using System.Linq; using System.Threading.Tasks; using Nethermind.Blockchain; +using Nethermind.Blockchain.Find; using Nethermind.Blockchain.FullPruning; using Nethermind.Config; using Nethermind.Core; @@ -12,7 +13,9 @@ using Nethermind.Network; using Nethermind.Network.Config; using Nethermind.Specs.ChainSpecStyle; +using Nethermind.State; using Nethermind.Stats.Model; +using Nethermind.Synchronization.FastSync; namespace Nethermind.JsonRpc.Modules.Admin; @@ -26,6 +29,8 @@ public class AdminRpcModule : IAdminRpcModule private readonly IEnode _enode; private readonly string _dataDir; private readonly ManualPruningTrigger _pruningTrigger; + private readonly IBlockingVerifyTrie _blockingVerifyTrie; + private readonly IStateReader _stateReader; private NodeInfo _nodeInfo = null!; public AdminRpcModule( @@ -33,6 +38,8 @@ public AdminRpcModule( INetworkConfig networkConfig, IPeerPool peerPool, IStaticNodesManager staticNodesManager, + IBlockingVerifyTrie blockingVerifyTrie, + IStateReader stateReader, IEnode enode, string dataDir, ManualPruningTrigger pruningTrigger, @@ -44,6 +51,8 @@ public AdminRpcModule( _peerPool = peerPool ?? throw new ArgumentNullException(nameof(peerPool)); _networkConfig = networkConfig ?? throw new ArgumentNullException(nameof(networkConfig)); _staticNodesManager = staticNodesManager ?? throw new ArgumentNullException(nameof(staticNodesManager)); + _blockingVerifyTrie = blockingVerifyTrie ?? throw new ArgumentNullException(nameof(blockingVerifyTrie)); + _stateReader = stateReader ?? throw new ArgumentNullException(nameof(stateReader)); _pruningTrigger = pruningTrigger; _parameters = parameters ?? throw new ArgumentNullException(nameof(parameters)); @@ -135,8 +144,40 @@ public ResultWrapper admin_setSolc() return ResultWrapper.Success(true); } + public ResultWrapper admin_isStateRootAvailable(BlockParameter block) + { + BlockHeader? header = _blockTree.FindHeader(block); + if (header is null) + { + return ResultWrapper.Fail("Unable to find block. Unable to know state root to verify."); + } + + return ResultWrapper.Success(_stateReader.HasStateForBlock(header)); + } + public ResultWrapper admin_prune() { return ResultWrapper.Success(_pruningTrigger.Trigger()); } + + public ResultWrapper admin_verifyTrie(BlockParameter block) + { + BlockHeader? header = _blockTree.FindHeader(block); + if (header is null) + { + return ResultWrapper.Fail("Unable to find block. Unable to know state root to verify."); + } + + if (!_stateReader.HasStateForBlock(header)) + { + return ResultWrapper.Fail("Unable to start verify trie. State for block missing."); + } + + if (!_blockingVerifyTrie.TryStartVerifyTrie(header)) + { + return ResultWrapper.Fail("Unable to start verify trie. Verify trie already running."); + } + + return ResultWrapper.Success("Starting."); + } } diff --git a/src/Nethermind/Nethermind.JsonRpc/Modules/Admin/IAdminRpcModule.cs b/src/Nethermind/Nethermind.JsonRpc/Modules/Admin/IAdminRpcModule.cs index ecfa719bf8b..f9a338e95db 100644 --- a/src/Nethermind/Nethermind.JsonRpc/Modules/Admin/IAdminRpcModule.cs +++ b/src/Nethermind/Nethermind.JsonRpc/Modules/Admin/IAdminRpcModule.cs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LGPL-3.0-only using System.Threading.Tasks; +using Nethermind.Blockchain.Find; using Nethermind.Blockchain.FullPruning; namespace Nethermind.JsonRpc.Modules.Admin; @@ -57,14 +58,19 @@ ResultWrapper admin_peers( IsImplemented = true)] ResultWrapper admin_dataDir(); - [JsonRpcMethod(Description = "[DEPRECATED]", IsImplemented = false)] ResultWrapper admin_setSolc(); - [JsonRpcMethod(Description = "Runs full pruning if enabled.", + [JsonRpcMethod(Description = "True if state root for the block is available", + EdgeCaseHint = "", + ExampleResponse = "\"Starting\"", + IsImplemented = true)] + ResultWrapper admin_isStateRootAvailable(BlockParameter block); + + [JsonRpcMethod(Description = "Runs VerifyTrie.", EdgeCaseHint = "", ExampleResponse = "\"Starting\"", IsImplemented = true)] - ResultWrapper admin_prune(); + ResultWrapper admin_verifyTrie(BlockParameter block); } diff --git a/src/Nethermind/Nethermind.Runner.Test/Ethereum/ContextWithMocks.cs b/src/Nethermind/Nethermind.Runner.Test/Ethereum/ContextWithMocks.cs index bc7560cb850..00fcaf0ff35 100644 --- a/src/Nethermind/Nethermind.Runner.Test/Ethereum/ContextWithMocks.cs +++ b/src/Nethermind/Nethermind.Runner.Test/Ethereum/ContextWithMocks.cs @@ -47,6 +47,7 @@ using Nethermind.Blockchain.Blocks; using Nethermind.Core; using Nethermind.Facade.Find; +using Nethermind.Synchronization.FastSync; namespace Nethermind.Runner.Test.Ethereum { @@ -94,6 +95,7 @@ public static NethermindApi ContextWithMocks() SealValidator = Substitute.For(), SessionMonitor = Substitute.For(), WorldState = Substitute.For(), + BlockingVerifyTrie = Substitute.For(), StateReader = Substitute.For(), TransactionProcessor = Substitute.For(), TxSender = Substitute.For(), diff --git a/src/Nethermind/Nethermind.Synchronization.Test/SynchronizerModuleTests.cs b/src/Nethermind/Nethermind.Synchronization.Test/SynchronizerModuleTests.cs index 10e0481d5fe..a444fbef96e 100644 --- a/src/Nethermind/Nethermind.Synchronization.Test/SynchronizerModuleTests.cs +++ b/src/Nethermind/Nethermind.Synchronization.Test/SynchronizerModuleTests.cs @@ -38,63 +38,27 @@ public IContainer CreateTestContainer() .AddSingleton(stateReader) .AddSingleton(treeSync) .AddSingleton(blockQueue) + .AddSingleton(Substitute.For()) .AddSingleton(Substitute.For()) .AddSingleton(LimboLogs.Instance) .Build(); } [Test] - public void TestOnTreeSyncFinish_CallVisit() + public async Task TestOnTreeSyncFinish_CallVisit() { IContainer ctx = CreateTestContainer(); ITreeSync treeSync = ctx.Resolve(); - IStateReader stateReader = ctx.Resolve(); + IBlockingVerifyTrie verifyTrie = ctx.Resolve(); - treeSync.SyncCompleted += Raise.EventWith(null, new ITreeSync.SyncCompletedEventArgs(TestItem.KeccakA)); - treeSync.SyncCompleted += Raise.EventWith(null, new ITreeSync.SyncCompletedEventArgs(TestItem.KeccakA)); - - stateReader - .Received(1) - .RunTreeVisitor(Arg.Any(), Arg.Is(TestItem.KeccakA), Arg.Any()); - } - - [Test] - public async Task TestOnTreeSyncFinish_BlockProcessingQueue_UntilFinished() - { - IContainer ctx = CreateTestContainer(); - ITreeSync treeSync = ctx.Resolve(); - IStateReader stateReader = ctx.Resolve(); - IBlockProcessingQueue blockQueue = ctx.Resolve(); - - ManualResetEvent treeVisitorBlocker = new ManualResetEvent(false); - - stateReader - .When(sr => sr.RunTreeVisitor(Arg.Any(), Arg.Is(TestItem.KeccakA), Arg.Any())) - .Do((ci) => - { - treeVisitorBlocker.WaitOne(); - }); - - Task triggerTask = Task.Run(() => - { - treeSync.SyncCompleted += Raise.EventWith(null, new ITreeSync.SyncCompletedEventArgs(TestItem.KeccakA)); - }); - - await Task.Delay(100); - - Task blockQueueTask = Task.Run(() => - { - blockQueue.BlockRemoved += - Raise.EventWith(null, new BlockRemovedEventArgs(null!, ProcessingResult.Success)); - }); + BlockHeader header = Build.A.BlockHeader.WithStateRoot(TestItem.KeccakA).TestObject; + treeSync.SyncCompleted += Raise.EventWith(null, new ITreeSync.SyncCompletedEventArgs(header)); + treeSync.SyncCompleted += Raise.EventWith(null, new ITreeSync.SyncCompletedEventArgs(header)); await Task.Delay(100); - blockQueueTask.IsCompleted.Should().BeFalse(); - treeVisitorBlocker.Set(); - - await triggerTask; - await blockQueueTask; - blockQueue.BlockRemoved += Raise.EventWith(null, new BlockRemovedEventArgs(null!, ProcessingResult.Success)); + verifyTrie + .Received(1) + .TryStartVerifyTrie(Arg.Any()); } } diff --git a/src/Nethermind/Nethermind.Synchronization/FastSync/BlockingVerifyTrie.cs b/src/Nethermind/Nethermind.Synchronization/FastSync/BlockingVerifyTrie.cs new file mode 100644 index 00000000000..eb14dca75dd --- /dev/null +++ b/src/Nethermind/Nethermind.Synchronization/FastSync/BlockingVerifyTrie.cs @@ -0,0 +1,69 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using System; +using System.Threading; +using System.Threading.Tasks; +using Autofac.Features.AttributeFilters; +using Nethermind.Config; +using Nethermind.Consensus.Processing; +using Nethermind.Core; +using Nethermind.Core.Crypto; +using Nethermind.Db; +using Nethermind.Logging; +using Nethermind.State; +using Nethermind.Trie; +using Nethermind.Trie.Pruning; + +namespace Nethermind.Synchronization.FastSync; + +public class BlockingVerifyTrie( + ITrieStore trieStore, + IStateReader stateReader, + [KeyFilter(DbNames.Code)] IDb codeDb, + IProcessExitSource exitSource, + ILogManager logManager) : IBlockingVerifyTrie +{ + private readonly ILogger _logger = logManager.GetClassLogger(); + + private bool _alreadyRunning = false; + + public bool TryStartVerifyTrie(BlockHeader stateAtBlock) + { + if (Interlocked.CompareExchange(ref _alreadyRunning, true, false)) + { + return false; + } + + Task.Factory.StartNew(() => + { + try + { + _logger!.Info("Collecting trie stats and verifying that no nodes are missing..."); + + Hash256 rootNode = stateAtBlock.StateRoot; + + // This is to block processing as with halfpath old nodes will be removed + using IBlockCommitter? _ = trieStore.BeginBlockCommit(stateAtBlock.Number + 1); + + TrieStats stats = stateReader.CollectStats(rootNode, codeDb, logManager, exitSource.Token); + if (stats.MissingNodes > 0) + { + _logger.Error($"Missing node found!"); + } + + _logger.Info($"Stats after finishing state \n" + stats); + } + catch (OperationCanceledException) + { + } + catch (Exception e) + { + _logger.Error($"Error in verify trie", e); + } + + }, TaskCreationOptions.LongRunning); + + return true; + } +} diff --git a/src/Nethermind/Nethermind.Synchronization/FastSync/IBlockingVerifyTrie.cs b/src/Nethermind/Nethermind.Synchronization/FastSync/IBlockingVerifyTrie.cs new file mode 100644 index 00000000000..a47d33dd466 --- /dev/null +++ b/src/Nethermind/Nethermind.Synchronization/FastSync/IBlockingVerifyTrie.cs @@ -0,0 +1,11 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using Nethermind.Core; + +namespace Nethermind.Synchronization.FastSync; + +public interface IBlockingVerifyTrie +{ + bool TryStartVerifyTrie(BlockHeader stateAtBlock); +} diff --git a/src/Nethermind/Nethermind.Synchronization/FastSync/ITreeSync.cs b/src/Nethermind/Nethermind.Synchronization/FastSync/ITreeSync.cs index 3dc7ca4450e..20995559577 100644 --- a/src/Nethermind/Nethermind.Synchronization/FastSync/ITreeSync.cs +++ b/src/Nethermind/Nethermind.Synchronization/FastSync/ITreeSync.cs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LGPL-3.0-only using System; +using Nethermind.Core; using Nethermind.Core.Crypto; namespace Nethermind.Synchronization.FastSync; @@ -10,8 +11,8 @@ public interface ITreeSync { public event EventHandler SyncCompleted; - public class SyncCompletedEventArgs(Hash256 root) : EventArgs + public class SyncCompletedEventArgs(BlockHeader header) : EventArgs { - public Hash256 Root => root; + public BlockHeader Pivot => header; } } diff --git a/src/Nethermind/Nethermind.Synchronization/FastSync/TreeSync.cs b/src/Nethermind/Nethermind.Synchronization/FastSync/TreeSync.cs index 4266b6e6aa5..8e8e520944b 100644 --- a/src/Nethermind/Nethermind.Synchronization/FastSync/TreeSync.cs +++ b/src/Nethermind/Nethermind.Synchronization/FastSync/TreeSync.cs @@ -765,7 +765,10 @@ private void VerifyPostSyncCleanUp() CleanupMemory(); - SyncCompleted?.Invoke(this, new ITreeSync.SyncCompletedEventArgs(_rootNode)); + if (_stateSyncPivot.GetPivotHeader() is { } pivotHeader) + { + SyncCompleted?.Invoke(this, new ITreeSync.SyncCompletedEventArgs(pivotHeader)); + } } private void CleanupMemory() diff --git a/src/Nethermind/Nethermind.Synchronization/FastSync/VerifyStateOnStateSyncFinished.cs b/src/Nethermind/Nethermind.Synchronization/FastSync/VerifyStateOnStateSyncFinished.cs index 1331350810f..67ccc96a969 100644 --- a/src/Nethermind/Nethermind.Synchronization/FastSync/VerifyStateOnStateSyncFinished.cs +++ b/src/Nethermind/Nethermind.Synchronization/FastSync/VerifyStateOnStateSyncFinished.cs @@ -1,30 +1,12 @@ // SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only -using System; -using System.Threading; using Autofac; -using Autofac.Features.AttributeFilters; -using Nethermind.Config; -using Nethermind.Consensus.Processing; -using Nethermind.Core.Crypto; -using Nethermind.Db; -using Nethermind.Logging; -using Nethermind.State; -using Nethermind.Trie; namespace Nethermind.Synchronization.FastSync; -public class VerifyStateOnStateSyncFinished( - IBlockProcessingQueue processingQueue, - ITreeSync treeSync, - IStateReader stateReader, - [KeyFilter(DbNames.Code)] IDb codeDb, - IProcessExitSource exitSource, - ILogManager logManager) : IStartable +public class VerifyStateOnStateSyncFinished(IBlockingVerifyTrie blockingVerifyTrie, ITreeSync treeSync) : IStartable { - private readonly ILogger _logger = logManager.GetClassLogger(); - public void Start() { treeSync.SyncCompleted += TreeSyncOnOnVerifyPostSyncCleanup; @@ -34,36 +16,6 @@ private void TreeSyncOnOnVerifyPostSyncCleanup(object? sender, ITreeSync.SyncCom { treeSync.SyncCompleted -= TreeSyncOnOnVerifyPostSyncCleanup; - ManualResetEvent processingBlocker = new ManualResetEvent(false); - - processingQueue.BlockRemoved += ProcessingQueueOnBlockRemoved; - - try - { - Hash256 rootNode = evt.Root; - _logger!.Info("Collecting trie stats and verifying that no nodes are missing..."); - TrieStats stats = stateReader.CollectStats(rootNode, codeDb, logManager, exitSource.Token); - if (stats.MissingNodes > 0) - { - _logger.Error($"Missing node found!"); - } - _logger.Info($"Stats after finishing state \n" + stats); - } - catch (Exception e) - { - _logger.Error($"Error in verify trie", e); - } - finally - { - processingBlocker.Set(); - processingQueue.BlockRemoved -= ProcessingQueueOnBlockRemoved; - } - - return; - - void ProcessingQueueOnBlockRemoved(object? o, BlockRemovedEventArgs blockRemovedEventArgs) - { - processingBlocker.WaitOne(); - } + blockingVerifyTrie.TryStartVerifyTrie(evt.Pivot); } } diff --git a/src/Nethermind/Nethermind.Trie/Pruning/TrieStore.cs b/src/Nethermind/Nethermind.Trie/Pruning/TrieStore.cs index 629ff50b54d..af3eb1ff028 100644 --- a/src/Nethermind/Nethermind.Trie/Pruning/TrieStore.cs +++ b/src/Nethermind/Nethermind.Trie/Pruning/TrieStore.cs @@ -323,12 +323,15 @@ public IBlockCommitter BeginBlockCommit(long blockNumber) { if (_pruningStrategy.PruningEnabled) { + while (!Monitor.TryEnter(_dirtyNodesLock, TimeSpan.FromSeconds(10))) + { + if (_logger.IsInfo) _logger.Info("Waiting for state to be unlocked."); + } + if (_currentBlockCommitter is not null) { throw new InvalidOperationException("Cannot start a new block commit when an existing one is still not closed"); } - - Monitor.Enter(_dirtyNodesLock); } _currentBlockCommitter = new BlockCommitter(this, CreateCommitSet(blockNumber));