From 5b61319a213d8d92d65f6f9c5b8fe231eca9cdac Mon Sep 17 00:00:00 2001 From: Amirul Ashraf Date: Mon, 23 Dec 2024 10:14:37 +0800 Subject: [PATCH 01/11] Admin verify trie --- .../Nethermind.Api/IApiWithNetwork.cs | 2 + .../Nethermind.Api/NethermindApi.cs | 2 + .../Steps/RegisterRpcModules.cs | 2 + .../Modules/AdminModuleTests.cs | 12 ++++ .../Modules/Admin/AdminRpcModule.cs | 19 +++++ .../Modules/Admin/IAdminRpcModule.cs | 6 ++ .../FastSync/BlockingVerifyTrie.cs | 72 +++++++++++++++++++ .../VerifyStateOnStateSyncFinished.cs | 52 +------------- .../Synchronizer.cs | 1 + 9 files changed, 118 insertions(+), 50 deletions(-) create mode 100644 src/Nethermind/Nethermind.Synchronization/FastSync/BlockingVerifyTrie.cs diff --git a/src/Nethermind/Nethermind.Api/IApiWithNetwork.cs b/src/Nethermind/Nethermind.Api/IApiWithNetwork.cs index 5abb6d545e6..a9ca7119a5e 100644 --- a/src/Nethermind/Nethermind.Api/IApiWithNetwork.cs +++ b/src/Nethermind/Nethermind.Api/IApiWithNetwork.cs @@ -18,6 +18,7 @@ using Nethermind.Synchronization; using Nethermind.Synchronization.Peers; using Nethermind.Sockets; +using Nethermind.Synchronization.FastSync; using Nethermind.Synchronization.ParallelSync; namespace Nethermind.Api @@ -56,6 +57,7 @@ public interface IApiWithNetwork : IApiWithBlockchain ISubscriptionFactory? SubscriptionFactory { get; set; } IContainer? ApiWithNetworkServiceContainer { get; set; } + IBlockingVerifyTrie BlockingVerifyTrie { get; } public ContainerBuilder ConfigureContainerBuilderFromApiWithNetwork(ContainerBuilder builder) { diff --git a/src/Nethermind/Nethermind.Api/NethermindApi.cs b/src/Nethermind/Nethermind.Api/NethermindApi.cs index 5e9e0618b91..00184b6255d 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 { @@ -197,6 +198,7 @@ public ISealEngine SealEngine public IPeerDifficultyRefreshPool? PeerDifficultyRefreshPool => ApiWithNetworkServiceContainer?.Resolve(); public ISynchronizer? Synchronizer => ApiWithNetworkServiceContainer?.Resolve(); public ISyncServer? SyncServer => ApiWithNetworkServiceContainer?.Resolve(); + public IBlockingVerifyTrie BlockingVerifyTrie => ApiWithNetworkServiceContainer?.Resolve()!; public IWorldState? WorldState { get; set; } public IReadOnlyStateProvider? ChainHeadStateProvider { get; set; } public IWorldStateManager? WorldStateManager { get; set; } diff --git a/src/Nethermind/Nethermind.Init/Steps/RegisterRpcModules.cs b/src/Nethermind/Nethermind.Init/Steps/RegisterRpcModules.cs index 6bfc89b87e6..98653df1267 100644 --- a/src/Nethermind/Nethermind.Init/Steps/RegisterRpcModules.cs +++ b/src/Nethermind/Nethermind.Init/Steps/RegisterRpcModules.cs @@ -127,11 +127,13 @@ 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.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..bb4a2eafc38 100644 --- a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/AdminModuleTests.cs +++ b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/AdminModuleTests.cs @@ -19,6 +19,7 @@ using Nethermind.Serialization.Json; using Nethermind.Specs.ChainSpecStyle; using Nethermind.Stats.Model; +using Nethermind.Synchronization.FastSync; using NSubstitute; using NUnit.Framework; @@ -32,6 +33,7 @@ public class AdminModuleTests private EthereumJsonSerializer _serializer = null!; private NetworkConfig _networkConfig = null!; private IBlockTree _blockTree = null!; + private IBlockingVerifyTrie _blockingVerifyTrie = null!; private const string _enodeString = "enode://e1b7e0dc09aae610c9dec8a0bee62bab9946cc27ebdd2f9e3571ed6d444628f99e91e43f4a14d42d498217608bb3e1d1bc8ec2aa27d7f7e423413b851bae02bc@127.0.0.1:30303"; private const string _exampleDataDir = "/example/dbdir"; @@ -39,6 +41,7 @@ public class AdminModuleTests public void Setup() { _blockTree = Build.A.BlockTree().OfChainLength(5).TestObject; + _blockingVerifyTrie = Substitute.For(); _networkConfig = new NetworkConfig(); IPeerPool peerPool = Substitute.For(); ConcurrentDictionary dict = new(); @@ -57,6 +60,7 @@ public void Setup() _networkConfig, peerPool, staticNodesManager, + _blockingVerifyTrie, enode, _exampleDataDir, new ManualPruningTrigger(), @@ -110,6 +114,14 @@ 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")).Should().Contain("Unable to start verify trie"); + _blockingVerifyTrie.TryStartVerifyTrie(Arg.Any()).Returns(true); + (await RpcTest.TestSerializedRequest(_adminRpcModule, "admin_verifyTrie")).Should().Contain("Starting"); + } + [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..e1ab03d6918 100644 --- a/src/Nethermind/Nethermind.JsonRpc/Modules/Admin/AdminRpcModule.cs +++ b/src/Nethermind/Nethermind.JsonRpc/Modules/Admin/AdminRpcModule.cs @@ -13,6 +13,7 @@ using Nethermind.Network.Config; using Nethermind.Specs.ChainSpecStyle; using Nethermind.Stats.Model; +using Nethermind.Synchronization.FastSync; namespace Nethermind.JsonRpc.Modules.Admin; @@ -26,6 +27,7 @@ public class AdminRpcModule : IAdminRpcModule private readonly IEnode _enode; private readonly string _dataDir; private readonly ManualPruningTrigger _pruningTrigger; + private readonly IBlockingVerifyTrie _blockingVerifyTrie; private NodeInfo _nodeInfo = null!; public AdminRpcModule( @@ -33,6 +35,7 @@ public AdminRpcModule( INetworkConfig networkConfig, IPeerPool peerPool, IStaticNodesManager staticNodesManager, + IBlockingVerifyTrie blockingVerifyTrie, IEnode enode, string dataDir, ManualPruningTrigger pruningTrigger, @@ -44,6 +47,7 @@ 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)); _pruningTrigger = pruningTrigger; _parameters = parameters ?? throw new ArgumentNullException(nameof(parameters)); @@ -139,4 +143,19 @@ public ResultWrapper admin_prune() { return ResultWrapper.Success(_pruningTrigger.Trigger()); } + + public ResultWrapper admin_verifyTrie() + { + if (_blockTree.Head is null) + { + return ResultWrapper.Fail("Head is null. Unable to know state root to verify."); + } + + if (!_blockingVerifyTrie.TryStartVerifyTrie(_blockTree.Head!.StateRoot!)) + { + 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..a4ab1e9ca30 100644 --- a/src/Nethermind/Nethermind.JsonRpc/Modules/Admin/IAdminRpcModule.cs +++ b/src/Nethermind/Nethermind.JsonRpc/Modules/Admin/IAdminRpcModule.cs @@ -67,4 +67,10 @@ ResultWrapper admin_peers( ExampleResponse = "\"Starting\"", IsImplemented = true)] ResultWrapper admin_prune(); + + [JsonRpcMethod(Description = "Runs VerifyTrie.", + EdgeCaseHint = "", + ExampleResponse = "\"Starting\"", + IsImplemented = true)] + ResultWrapper admin_verifyTrie(); } diff --git a/src/Nethermind/Nethermind.Synchronization/FastSync/BlockingVerifyTrie.cs b/src/Nethermind/Nethermind.Synchronization/FastSync/BlockingVerifyTrie.cs new file mode 100644 index 00000000000..cafd3794800 --- /dev/null +++ b/src/Nethermind/Nethermind.Synchronization/FastSync/BlockingVerifyTrie.cs @@ -0,0 +1,72 @@ +// 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.Crypto; +using Nethermind.Db; +using Nethermind.Logging; +using Nethermind.State; +using Nethermind.Trie; + +namespace Nethermind.Synchronization.FastSync; + +public class BlockingVerifyTrie( + IBlockProcessingQueue processingQueue, + 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(Hash256 rootNode) + { + if (Interlocked.CompareExchange(ref _alreadyRunning, true, false)) + { + return false; + } + + ManualResetEvent processingBlocker = new ManualResetEvent(false); + + processingQueue.BlockRemoved += ProcessingQueueOnBlockRemoved; + + Task.Factory.StartNew(() => + { + try + { + _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; + } + + }, TaskCreationOptions.LongRunning); + + return true; + + void ProcessingQueueOnBlockRemoved(object? o, BlockRemovedEventArgs blockRemovedEventArgs) + { + processingBlocker.WaitOne(); + } + } +} diff --git a/src/Nethermind/Nethermind.Synchronization/FastSync/VerifyStateOnStateSyncFinished.cs b/src/Nethermind/Nethermind.Synchronization/FastSync/VerifyStateOnStateSyncFinished.cs index 1331350810f..7cc5cbbd573 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.Root); } } diff --git a/src/Nethermind/Nethermind.Synchronization/Synchronizer.cs b/src/Nethermind/Nethermind.Synchronization/Synchronizer.cs index 6da08fbf902..6cd541e487b 100644 --- a/src/Nethermind/Nethermind.Synchronization/Synchronizer.cs +++ b/src/Nethermind/Nethermind.Synchronization/Synchronizer.cs @@ -299,6 +299,7 @@ protected override void Load(ContainerBuilder builder) .AddSingleton() .AddSingleton() .AddSingleton() + .AddSingleton() // For blocks. There are two block scope, Fast and Full .AddScoped>() From 105ea5598709b0fc046f25c76f02b88b234daffe Mon Sep 17 00:00:00 2001 From: Amirul Ashraf Date: Mon, 23 Dec 2024 10:17:40 +0800 Subject: [PATCH 02/11] Don't log on cancelled --- .../Nethermind.Synchronization/FastSync/BlockingVerifyTrie.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Nethermind/Nethermind.Synchronization/FastSync/BlockingVerifyTrie.cs b/src/Nethermind/Nethermind.Synchronization/FastSync/BlockingVerifyTrie.cs index cafd3794800..bc703c7334d 100644 --- a/src/Nethermind/Nethermind.Synchronization/FastSync/BlockingVerifyTrie.cs +++ b/src/Nethermind/Nethermind.Synchronization/FastSync/BlockingVerifyTrie.cs @@ -50,6 +50,9 @@ public bool TryStartVerifyTrie(Hash256 rootNode) _logger.Info($"Stats after finishing state \n" + stats); } + catch (OperationCanceledException) + { + } catch (Exception e) { _logger.Error($"Error in verify trie", e); From 90623763a54e5da4168d616021890a383784aae6 Mon Sep 17 00:00:00 2001 From: Amirul Ashraf Date: Mon, 23 Dec 2024 10:17:59 +0800 Subject: [PATCH 03/11] Missed file --- .../FastSync/IBlockingVerifyTrie.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 src/Nethermind/Nethermind.Synchronization/FastSync/IBlockingVerifyTrie.cs diff --git a/src/Nethermind/Nethermind.Synchronization/FastSync/IBlockingVerifyTrie.cs b/src/Nethermind/Nethermind.Synchronization/FastSync/IBlockingVerifyTrie.cs new file mode 100644 index 00000000000..def9b1f7fb7 --- /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.Crypto; + +namespace Nethermind.Synchronization.FastSync; + +public interface IBlockingVerifyTrie +{ + bool TryStartVerifyTrie(Hash256 rootNode); +} From a70e79732e7c82a19c6ed2d2b6de9ea200393d75 Mon Sep 17 00:00:00 2001 From: Amirul Ashraf Date: Mon, 23 Dec 2024 10:26:37 +0800 Subject: [PATCH 04/11] Fix test --- .../Nethermind.Runner.Test/Ethereum/ContextWithMocks.cs | 2 ++ .../SynchronizerModuleTests.cs | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Nethermind/Nethermind.Runner.Test/Ethereum/ContextWithMocks.cs b/src/Nethermind/Nethermind.Runner.Test/Ethereum/ContextWithMocks.cs index bc7560cb850..8c00c187dd5 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 { @@ -122,6 +123,7 @@ public static NethermindApi ContextWithMocks() .AddSingleton(Substitute.For()) .AddSingleton(Substitute.For()) .AddSingleton(Substitute.For()) + .AddSingleton(Substitute.For()) .AddSingleton(Substitute.For()) .AddSingleton(Substitute.For()) .Build(), diff --git a/src/Nethermind/Nethermind.Synchronization.Test/SynchronizerModuleTests.cs b/src/Nethermind/Nethermind.Synchronization.Test/SynchronizerModuleTests.cs index 10e0481d5fe..a63e8aa97fb 100644 --- a/src/Nethermind/Nethermind.Synchronization.Test/SynchronizerModuleTests.cs +++ b/src/Nethermind/Nethermind.Synchronization.Test/SynchronizerModuleTests.cs @@ -44,7 +44,7 @@ public IContainer CreateTestContainer() } [Test] - public void TestOnTreeSyncFinish_CallVisit() + public async Task TestOnTreeSyncFinish_CallVisit() { IContainer ctx = CreateTestContainer(); ITreeSync treeSync = ctx.Resolve(); @@ -53,6 +53,8 @@ public void TestOnTreeSyncFinish_CallVisit() treeSync.SyncCompleted += Raise.EventWith(null, new ITreeSync.SyncCompletedEventArgs(TestItem.KeccakA)); treeSync.SyncCompleted += Raise.EventWith(null, new ITreeSync.SyncCompletedEventArgs(TestItem.KeccakA)); + await Task.Delay(100); + stateReader .Received(1) .RunTreeVisitor(Arg.Any(), Arg.Is(TestItem.KeccakA), Arg.Any()); From dd05ee93c338cef2e7f380d54f8c73b724bbc5e3 Mon Sep 17 00:00:00 2001 From: Amirul Ashraf Date: Mon, 23 Dec 2024 12:44:39 +0800 Subject: [PATCH 05/11] Move to state --- .../Nethermind.Api/IApiWithBlockchain.cs | 2 ++ .../Nethermind.Api/IApiWithNetwork.cs | 1 - .../Nethermind.Api/NethermindApi.cs | 2 +- .../Nethermind.Init/InitializeStateDb.cs | 14 +++++++--- .../Steps/RegisterRpcModules.cs | 2 +- .../Modules/AdminModuleTests.cs | 2 +- .../Modules/Admin/AdminRpcModule.cs | 2 +- .../SynchronizerModuleTests.cs | 8 +++--- .../FastSync/BlockingVerifyTrie.cs | 26 +++++++------------ .../FastSync/IBlockingVerifyTrie.cs | 4 +-- .../FastSync/ITreeSync.cs | 5 ++-- .../FastSync/TreeSync.cs | 2 +- .../VerifyStateOnStateSyncFinished.cs | 2 +- 13 files changed, 38 insertions(+), 34 deletions(-) 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/IApiWithNetwork.cs b/src/Nethermind/Nethermind.Api/IApiWithNetwork.cs index a9ca7119a5e..6da7de010d8 100644 --- a/src/Nethermind/Nethermind.Api/IApiWithNetwork.cs +++ b/src/Nethermind/Nethermind.Api/IApiWithNetwork.cs @@ -57,7 +57,6 @@ public interface IApiWithNetwork : IApiWithBlockchain ISubscriptionFactory? SubscriptionFactory { get; set; } IContainer? ApiWithNetworkServiceContainer { get; set; } - IBlockingVerifyTrie BlockingVerifyTrie { get; } public ContainerBuilder ConfigureContainerBuilderFromApiWithNetwork(ContainerBuilder builder) { diff --git a/src/Nethermind/Nethermind.Api/NethermindApi.cs b/src/Nethermind/Nethermind.Api/NethermindApi.cs index 00184b6255d..8aba56c5504 100644 --- a/src/Nethermind/Nethermind.Api/NethermindApi.cs +++ b/src/Nethermind/Nethermind.Api/NethermindApi.cs @@ -198,7 +198,7 @@ public ISealEngine SealEngine public IPeerDifficultyRefreshPool? PeerDifficultyRefreshPool => ApiWithNetworkServiceContainer?.Resolve(); public ISynchronizer? Synchronizer => ApiWithNetworkServiceContainer?.Resolve(); public ISyncServer? SyncServer => ApiWithNetworkServiceContainer?.Resolve(); - public IBlockingVerifyTrie BlockingVerifyTrie => 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 98653df1267..d8575e45aeb 100644 --- a/src/Nethermind/Nethermind.Init/Steps/RegisterRpcModules.cs +++ b/src/Nethermind/Nethermind.Init/Steps/RegisterRpcModules.cs @@ -133,7 +133,7 @@ public virtual async Task Execute(CancellationToken cancellationToken) networkConfig, _api.PeerPool, _api.StaticNodesManager, - _api.BlockingVerifyTrie, + _api.BlockingVerifyTrie!, _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 bb4a2eafc38..41c68f518c3 100644 --- a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/AdminModuleTests.cs +++ b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/AdminModuleTests.cs @@ -118,7 +118,7 @@ public async Task Test_admin_dataDir() public async Task Test_admin_verifyTrie() { (await RpcTest.TestSerializedRequest(_adminRpcModule, "admin_verifyTrie")).Should().Contain("Unable to start verify trie"); - _blockingVerifyTrie.TryStartVerifyTrie(Arg.Any()).Returns(true); + _blockingVerifyTrie.TryStartVerifyTrie(Arg.Any()).Returns(true); (await RpcTest.TestSerializedRequest(_adminRpcModule, "admin_verifyTrie")).Should().Contain("Starting"); } diff --git a/src/Nethermind/Nethermind.JsonRpc/Modules/Admin/AdminRpcModule.cs b/src/Nethermind/Nethermind.JsonRpc/Modules/Admin/AdminRpcModule.cs index e1ab03d6918..e2819a1592d 100644 --- a/src/Nethermind/Nethermind.JsonRpc/Modules/Admin/AdminRpcModule.cs +++ b/src/Nethermind/Nethermind.JsonRpc/Modules/Admin/AdminRpcModule.cs @@ -151,7 +151,7 @@ public ResultWrapper admin_verifyTrie() return ResultWrapper.Fail("Head is null. Unable to know state root to verify."); } - if (!_blockingVerifyTrie.TryStartVerifyTrie(_blockTree.Head!.StateRoot!)) + if (!_blockingVerifyTrie.TryStartVerifyTrie(_blockTree.Head!.Header)) { return ResultWrapper.Fail("Unable to start verify trie. Verify trie already running."); } diff --git a/src/Nethermind/Nethermind.Synchronization.Test/SynchronizerModuleTests.cs b/src/Nethermind/Nethermind.Synchronization.Test/SynchronizerModuleTests.cs index a63e8aa97fb..f8a1a782377 100644 --- a/src/Nethermind/Nethermind.Synchronization.Test/SynchronizerModuleTests.cs +++ b/src/Nethermind/Nethermind.Synchronization.Test/SynchronizerModuleTests.cs @@ -50,8 +50,9 @@ public async Task TestOnTreeSyncFinish_CallVisit() ITreeSync treeSync = ctx.Resolve(); IStateReader stateReader = ctx.Resolve(); - treeSync.SyncCompleted += Raise.EventWith(null, new ITreeSync.SyncCompletedEventArgs(TestItem.KeccakA)); - treeSync.SyncCompleted += Raise.EventWith(null, new ITreeSync.SyncCompletedEventArgs(TestItem.KeccakA)); + 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); @@ -69,6 +70,7 @@ public async Task TestOnTreeSyncFinish_BlockProcessingQueue_UntilFinished() IBlockProcessingQueue blockQueue = ctx.Resolve(); ManualResetEvent treeVisitorBlocker = new ManualResetEvent(false); + BlockHeader header = Build.A.BlockHeader.WithStateRoot(TestItem.KeccakA).TestObject; stateReader .When(sr => sr.RunTreeVisitor(Arg.Any(), Arg.Is(TestItem.KeccakA), Arg.Any())) @@ -79,7 +81,7 @@ public async Task TestOnTreeSyncFinish_BlockProcessingQueue_UntilFinished() Task triggerTask = Task.Run(() => { - treeSync.SyncCompleted += Raise.EventWith(null, new ITreeSync.SyncCompletedEventArgs(TestItem.KeccakA)); + treeSync.SyncCompleted += Raise.EventWith(null, new ITreeSync.SyncCompletedEventArgs(header)); }); await Task.Delay(100); diff --git a/src/Nethermind/Nethermind.Synchronization/FastSync/BlockingVerifyTrie.cs b/src/Nethermind/Nethermind.Synchronization/FastSync/BlockingVerifyTrie.cs index bc703c7334d..eb14dca75dd 100644 --- a/src/Nethermind/Nethermind.Synchronization/FastSync/BlockingVerifyTrie.cs +++ b/src/Nethermind/Nethermind.Synchronization/FastSync/BlockingVerifyTrie.cs @@ -7,16 +7,18 @@ 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( - IBlockProcessingQueue processingQueue, + ITrieStore trieStore, IStateReader stateReader, [KeyFilter(DbNames.Code)] IDb codeDb, IProcessExitSource exitSource, @@ -26,22 +28,24 @@ public class BlockingVerifyTrie( private bool _alreadyRunning = false; - public bool TryStartVerifyTrie(Hash256 rootNode) + public bool TryStartVerifyTrie(BlockHeader stateAtBlock) { if (Interlocked.CompareExchange(ref _alreadyRunning, true, false)) { return false; } - ManualResetEvent processingBlocker = new ManualResetEvent(false); - - processingQueue.BlockRemoved += ProcessingQueueOnBlockRemoved; - 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) { @@ -57,19 +61,9 @@ public bool TryStartVerifyTrie(Hash256 rootNode) { _logger.Error($"Error in verify trie", e); } - finally - { - processingBlocker.Set(); - processingQueue.BlockRemoved -= ProcessingQueueOnBlockRemoved; - } }, TaskCreationOptions.LongRunning); return true; - - void ProcessingQueueOnBlockRemoved(object? o, BlockRemovedEventArgs blockRemovedEventArgs) - { - processingBlocker.WaitOne(); - } } } diff --git a/src/Nethermind/Nethermind.Synchronization/FastSync/IBlockingVerifyTrie.cs b/src/Nethermind/Nethermind.Synchronization/FastSync/IBlockingVerifyTrie.cs index def9b1f7fb7..a47d33dd466 100644 --- a/src/Nethermind/Nethermind.Synchronization/FastSync/IBlockingVerifyTrie.cs +++ b/src/Nethermind/Nethermind.Synchronization/FastSync/IBlockingVerifyTrie.cs @@ -1,11 +1,11 @@ // SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only -using Nethermind.Core.Crypto; +using Nethermind.Core; namespace Nethermind.Synchronization.FastSync; public interface IBlockingVerifyTrie { - bool TryStartVerifyTrie(Hash256 rootNode); + 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..ab96fbceb4f 100644 --- a/src/Nethermind/Nethermind.Synchronization/FastSync/TreeSync.cs +++ b/src/Nethermind/Nethermind.Synchronization/FastSync/TreeSync.cs @@ -765,7 +765,7 @@ private void VerifyPostSyncCleanUp() CleanupMemory(); - SyncCompleted?.Invoke(this, new ITreeSync.SyncCompletedEventArgs(_rootNode)); + SyncCompleted?.Invoke(this, new ITreeSync.SyncCompletedEventArgs(_stateSyncPivot.GetPivotHeader())); } private void CleanupMemory() diff --git a/src/Nethermind/Nethermind.Synchronization/FastSync/VerifyStateOnStateSyncFinished.cs b/src/Nethermind/Nethermind.Synchronization/FastSync/VerifyStateOnStateSyncFinished.cs index 7cc5cbbd573..67ccc96a969 100644 --- a/src/Nethermind/Nethermind.Synchronization/FastSync/VerifyStateOnStateSyncFinished.cs +++ b/src/Nethermind/Nethermind.Synchronization/FastSync/VerifyStateOnStateSyncFinished.cs @@ -16,6 +16,6 @@ private void TreeSyncOnOnVerifyPostSyncCleanup(object? sender, ITreeSync.SyncCom { treeSync.SyncCompleted -= TreeSyncOnOnVerifyPostSyncCleanup; - blockingVerifyTrie.TryStartVerifyTrie(evt.Root); + blockingVerifyTrie.TryStartVerifyTrie(evt.Pivot); } } From e7b10fc6b287a34559bc21a1e5d1aaa7b32bd7f6 Mon Sep 17 00:00:00 2001 From: Amirul Ashraf Date: Mon, 23 Dec 2024 12:48:26 +0800 Subject: [PATCH 06/11] Cleanup --- src/Nethermind/Nethermind.Api/IApiWithNetwork.cs | 1 - .../Nethermind.Runner.Test/Ethereum/ContextWithMocks.cs | 1 - .../Nethermind.Synchronization/FastSync/TreeSync.cs | 5 ++++- src/Nethermind/Nethermind.Synchronization/Synchronizer.cs | 1 - 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Nethermind/Nethermind.Api/IApiWithNetwork.cs b/src/Nethermind/Nethermind.Api/IApiWithNetwork.cs index 6da7de010d8..5abb6d545e6 100644 --- a/src/Nethermind/Nethermind.Api/IApiWithNetwork.cs +++ b/src/Nethermind/Nethermind.Api/IApiWithNetwork.cs @@ -18,7 +18,6 @@ using Nethermind.Synchronization; using Nethermind.Synchronization.Peers; using Nethermind.Sockets; -using Nethermind.Synchronization.FastSync; using Nethermind.Synchronization.ParallelSync; namespace Nethermind.Api diff --git a/src/Nethermind/Nethermind.Runner.Test/Ethereum/ContextWithMocks.cs b/src/Nethermind/Nethermind.Runner.Test/Ethereum/ContextWithMocks.cs index 8c00c187dd5..0b746f75da4 100644 --- a/src/Nethermind/Nethermind.Runner.Test/Ethereum/ContextWithMocks.cs +++ b/src/Nethermind/Nethermind.Runner.Test/Ethereum/ContextWithMocks.cs @@ -123,7 +123,6 @@ public static NethermindApi ContextWithMocks() .AddSingleton(Substitute.For()) .AddSingleton(Substitute.For()) .AddSingleton(Substitute.For()) - .AddSingleton(Substitute.For()) .AddSingleton(Substitute.For()) .AddSingleton(Substitute.For()) .Build(), diff --git a/src/Nethermind/Nethermind.Synchronization/FastSync/TreeSync.cs b/src/Nethermind/Nethermind.Synchronization/FastSync/TreeSync.cs index ab96fbceb4f..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(_stateSyncPivot.GetPivotHeader())); + if (_stateSyncPivot.GetPivotHeader() is { } pivotHeader) + { + SyncCompleted?.Invoke(this, new ITreeSync.SyncCompletedEventArgs(pivotHeader)); + } } private void CleanupMemory() diff --git a/src/Nethermind/Nethermind.Synchronization/Synchronizer.cs b/src/Nethermind/Nethermind.Synchronization/Synchronizer.cs index 6cd541e487b..6da08fbf902 100644 --- a/src/Nethermind/Nethermind.Synchronization/Synchronizer.cs +++ b/src/Nethermind/Nethermind.Synchronization/Synchronizer.cs @@ -299,7 +299,6 @@ protected override void Load(ContainerBuilder builder) .AddSingleton() .AddSingleton() .AddSingleton() - .AddSingleton() // For blocks. There are two block scope, Fast and Full .AddScoped>() From 2486ee86c218be16215ec67fdc3c7a0d5705a9de Mon Sep 17 00:00:00 2001 From: Amirul Ashraf Date: Mon, 23 Dec 2024 13:14:45 +0800 Subject: [PATCH 07/11] Lock triestore --- src/Nethermind/Nethermind.Trie/Pruning/TrieStore.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) 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)); From e6293e2731afaa227f9f0367569aa2e79c500e64 Mon Sep 17 00:00:00 2001 From: Amirul Ashraf Date: Tue, 24 Dec 2024 13:48:58 +0800 Subject: [PATCH 08/11] Fix test --- .../Ethereum/ContextWithMocks.cs | 1 + .../SynchronizerModuleTests.cs | 48 ++----------------- 2 files changed, 5 insertions(+), 44 deletions(-) diff --git a/src/Nethermind/Nethermind.Runner.Test/Ethereum/ContextWithMocks.cs b/src/Nethermind/Nethermind.Runner.Test/Ethereum/ContextWithMocks.cs index 0b746f75da4..00fcaf0ff35 100644 --- a/src/Nethermind/Nethermind.Runner.Test/Ethereum/ContextWithMocks.cs +++ b/src/Nethermind/Nethermind.Runner.Test/Ethereum/ContextWithMocks.cs @@ -95,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 f8a1a782377..a444fbef96e 100644 --- a/src/Nethermind/Nethermind.Synchronization.Test/SynchronizerModuleTests.cs +++ b/src/Nethermind/Nethermind.Synchronization.Test/SynchronizerModuleTests.cs @@ -38,6 +38,7 @@ public IContainer CreateTestContainer() .AddSingleton(stateReader) .AddSingleton(treeSync) .AddSingleton(blockQueue) + .AddSingleton(Substitute.For()) .AddSingleton(Substitute.For()) .AddSingleton(LimboLogs.Instance) .Build(); @@ -48,7 +49,7 @@ public async Task TestOnTreeSyncFinish_CallVisit() { IContainer ctx = CreateTestContainer(); ITreeSync treeSync = ctx.Resolve(); - IStateReader stateReader = ctx.Resolve(); + IBlockingVerifyTrie verifyTrie = ctx.Resolve(); BlockHeader header = Build.A.BlockHeader.WithStateRoot(TestItem.KeccakA).TestObject; treeSync.SyncCompleted += Raise.EventWith(null, new ITreeSync.SyncCompletedEventArgs(header)); @@ -56,49 +57,8 @@ public async Task TestOnTreeSyncFinish_CallVisit() await Task.Delay(100); - stateReader + verifyTrie .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); - BlockHeader header = Build.A.BlockHeader.WithStateRoot(TestItem.KeccakA).TestObject; - - 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(header)); - }); - - await Task.Delay(100); - - Task blockQueueTask = Task.Run(() => - { - blockQueue.BlockRemoved += - Raise.EventWith(null, new BlockRemovedEventArgs(null!, ProcessingResult.Success)); - }); - - await Task.Delay(100); - - blockQueueTask.IsCompleted.Should().BeFalse(); - treeVisitorBlocker.Set(); - - await triggerTask; - await blockQueueTask; - blockQueue.BlockRemoved += Raise.EventWith(null, new BlockRemovedEventArgs(null!, ProcessingResult.Success)); + .TryStartVerifyTrie(Arg.Any()); } } From 2fd50310d37add2e3b729983627dce486e961e26 Mon Sep 17 00:00:00 2001 From: Amirul Ashraf Date: Tue, 31 Dec 2024 10:11:28 +0800 Subject: [PATCH 09/11] Add has state --- .../Steps/RegisterRpcModules.cs | 1 + .../Modules/AdminModuleTests.cs | 16 ++++++++++-- .../Modules/Admin/AdminRpcModule.cs | 25 ++++++++++++++++--- .../Modules/Admin/IAdminRpcModule.cs | 8 +++--- 4 files changed, 40 insertions(+), 10 deletions(-) diff --git a/src/Nethermind/Nethermind.Init/Steps/RegisterRpcModules.cs b/src/Nethermind/Nethermind.Init/Steps/RegisterRpcModules.cs index 810f73ffd2d..8f15d15d8e2 100644 --- a/src/Nethermind/Nethermind.Init/Steps/RegisterRpcModules.cs +++ b/src/Nethermind/Nethermind.Init/Steps/RegisterRpcModules.cs @@ -134,6 +134,7 @@ public virtual async Task Execute(CancellationToken cancellationToken) _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 41c68f518c3..da429aec03b 100644 --- a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/AdminModuleTests.cs +++ b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/AdminModuleTests.cs @@ -18,6 +18,7 @@ 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; @@ -34,6 +35,7 @@ public class AdminModuleTests 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"; @@ -42,6 +44,7 @@ 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(); @@ -61,6 +64,7 @@ public void Setup() peerPool, staticNodesManager, _blockingVerifyTrie, + _stateReader, enode, _exampleDataDir, new ManualPruningTrigger(), @@ -117,9 +121,17 @@ public async Task Test_admin_dataDir() [Test] public async Task Test_admin_verifyTrie() { - (await RpcTest.TestSerializedRequest(_adminRpcModule, "admin_verifyTrie")).Should().Contain("Unable to start verify trie"); + (await RpcTest.TestSerializedRequest(_adminRpcModule, "admin_verifyTrie", "latest")).Should().Contain("Unable to start verify trie"); _blockingVerifyTrie.TryStartVerifyTrie(Arg.Any()).Returns(true); - (await RpcTest.TestSerializedRequest(_adminRpcModule, "admin_verifyTrie")).Should().Contain("Starting"); + (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] diff --git a/src/Nethermind/Nethermind.JsonRpc/Modules/Admin/AdminRpcModule.cs b/src/Nethermind/Nethermind.JsonRpc/Modules/Admin/AdminRpcModule.cs index e2819a1592d..4a6d2e3317d 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,6 +13,7 @@ using Nethermind.Network; using Nethermind.Network.Config; using Nethermind.Specs.ChainSpecStyle; +using Nethermind.State; using Nethermind.Stats.Model; using Nethermind.Synchronization.FastSync; @@ -28,6 +30,7 @@ public class AdminRpcModule : IAdminRpcModule private readonly string _dataDir; private readonly ManualPruningTrigger _pruningTrigger; private readonly IBlockingVerifyTrie _blockingVerifyTrie; + private readonly IStateReader _stateReader; private NodeInfo _nodeInfo = null!; public AdminRpcModule( @@ -36,6 +39,7 @@ public AdminRpcModule( IPeerPool peerPool, IStaticNodesManager staticNodesManager, IBlockingVerifyTrie blockingVerifyTrie, + IStateReader stateReader, IEnode enode, string dataDir, ManualPruningTrigger pruningTrigger, @@ -48,6 +52,7 @@ public AdminRpcModule( _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)); @@ -139,19 +144,31 @@ public ResultWrapper admin_setSolc() return ResultWrapper.Success(true); } + public ResultWrapper admin_isStateRootAvailable(BlockParameter block) + { + SearchResult headerSearchResult = _blockTree.SearchForHeader(block); + if (headerSearchResult.Object is null) + { + return ResultWrapper.Fail("Unable to find block. Unable to know state root to verify."); + } + + return ResultWrapper.Success(_stateReader.HasStateForBlock(headerSearchResult.Object)); + } + public ResultWrapper admin_prune() { return ResultWrapper.Success(_pruningTrigger.Trigger()); } - public ResultWrapper admin_verifyTrie() + public ResultWrapper admin_verifyTrie(BlockParameter block) { - if (_blockTree.Head is null) + SearchResult headerSearchResult = _blockTree.SearchForHeader(block); + if (headerSearchResult.Object is null) { - return ResultWrapper.Fail("Head is null. Unable to know state root to verify."); + return ResultWrapper.Fail("Unable to find block. Unable to know state root to verify."); } - if (!_blockingVerifyTrie.TryStartVerifyTrie(_blockTree.Head!.Header)) + if (!_blockingVerifyTrie.TryStartVerifyTrie(headerSearchResult.Object)) { return ResultWrapper.Fail("Unable to start verify trie. Verify trie already running."); } diff --git a/src/Nethermind/Nethermind.JsonRpc/Modules/Admin/IAdminRpcModule.cs b/src/Nethermind/Nethermind.JsonRpc/Modules/Admin/IAdminRpcModule.cs index a4ab1e9ca30..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,20 +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_prune(); + ResultWrapper admin_isStateRootAvailable(BlockParameter block); [JsonRpcMethod(Description = "Runs VerifyTrie.", EdgeCaseHint = "", ExampleResponse = "\"Starting\"", IsImplemented = true)] - ResultWrapper admin_verifyTrie(); + ResultWrapper admin_verifyTrie(BlockParameter block); } From cbac315ec5b59fe72617369c9d2d0794829b6e35 Mon Sep 17 00:00:00 2001 From: Amirul Ashraf Date: Tue, 31 Dec 2024 17:06:19 +0800 Subject: [PATCH 10/11] Could just use header directly --- .../Modules/Admin/AdminRpcModule.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Nethermind/Nethermind.JsonRpc/Modules/Admin/AdminRpcModule.cs b/src/Nethermind/Nethermind.JsonRpc/Modules/Admin/AdminRpcModule.cs index 4a6d2e3317d..365ab4cd9ce 100644 --- a/src/Nethermind/Nethermind.JsonRpc/Modules/Admin/AdminRpcModule.cs +++ b/src/Nethermind/Nethermind.JsonRpc/Modules/Admin/AdminRpcModule.cs @@ -146,13 +146,13 @@ public ResultWrapper admin_setSolc() public ResultWrapper admin_isStateRootAvailable(BlockParameter block) { - SearchResult headerSearchResult = _blockTree.SearchForHeader(block); - if (headerSearchResult.Object is null) + 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(headerSearchResult.Object)); + return ResultWrapper.Success(_stateReader.HasStateForBlock(header)); } public ResultWrapper admin_prune() @@ -162,13 +162,13 @@ public ResultWrapper admin_prune() public ResultWrapper admin_verifyTrie(BlockParameter block) { - SearchResult headerSearchResult = _blockTree.SearchForHeader(block); - if (headerSearchResult.Object is null) + BlockHeader? header = _blockTree.FindHeader(block); + if (header is null) { return ResultWrapper.Fail("Unable to find block. Unable to know state root to verify."); } - if (!_blockingVerifyTrie.TryStartVerifyTrie(headerSearchResult.Object)) + if (!_blockingVerifyTrie.TryStartVerifyTrie(header)) { return ResultWrapper.Fail("Unable to start verify trie. Verify trie already running."); } From 262fdd8e43c6b432123efae2790243556cf01528 Mon Sep 17 00:00:00 2001 From: Amirul Ashraf Date: Tue, 31 Dec 2024 22:55:15 +0800 Subject: [PATCH 11/11] Check for state --- .../Nethermind.JsonRpc.Test/Modules/AdminModuleTests.cs | 1 + .../Nethermind.JsonRpc/Modules/Admin/AdminRpcModule.cs | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/AdminModuleTests.cs b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/AdminModuleTests.cs index da429aec03b..fdada32f4d1 100644 --- a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/AdminModuleTests.cs +++ b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/AdminModuleTests.cs @@ -122,6 +122,7 @@ public async Task Test_admin_dataDir() 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"); } diff --git a/src/Nethermind/Nethermind.JsonRpc/Modules/Admin/AdminRpcModule.cs b/src/Nethermind/Nethermind.JsonRpc/Modules/Admin/AdminRpcModule.cs index 365ab4cd9ce..6ccd648c721 100644 --- a/src/Nethermind/Nethermind.JsonRpc/Modules/Admin/AdminRpcModule.cs +++ b/src/Nethermind/Nethermind.JsonRpc/Modules/Admin/AdminRpcModule.cs @@ -168,6 +168,11 @@ public ResultWrapper admin_verifyTrie(BlockParameter block) 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.");