diff --git a/src/Nethermind/Directory.Packages.props b/src/Nethermind/Directory.Packages.props index a82c8f71f14..8d24f2a123c 100644 --- a/src/Nethermind/Directory.Packages.props +++ b/src/Nethermind/Directory.Packages.props @@ -6,6 +6,8 @@ + + @@ -36,6 +38,7 @@ + diff --git a/src/Nethermind/Nethermind.Api/IApiWithBlockchain.cs b/src/Nethermind/Nethermind.Api/IApiWithBlockchain.cs index a3a510e7c89..be6c36dcd63 100644 --- a/src/Nethermind/Nethermind.Api/IApiWithBlockchain.cs +++ b/src/Nethermind/Nethermind.Api/IApiWithBlockchain.cs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LGPL-3.0-only #nullable enable +using Autofac; using Nethermind.Blockchain; using Nethermind.Blockchain.Filters; using Nethermind.Blockchain.FullPruning; @@ -99,5 +100,12 @@ public interface IApiWithBlockchain : IApiWithStores, IBlockchainBridgeFactory INodeStorageFactory NodeStorageFactory { get; set; } BackgroundTaskScheduler BackgroundTaskScheduler { get; set; } CensorshipDetector CensorshipDetector { get; set; } + + public ContainerBuilder ConfigureContainerBuilderFromApiWithBlockchain(ContainerBuilder builder) + { + return ConfigureContainerBuilderFromApiWithStores(builder) + .AddPropertiesFrom(this) + .AddSingleton(NodeStorageFactory.WrapKeyValueStore(DbProvider!.StateDb)); + } } } diff --git a/src/Nethermind/Nethermind.Api/IApiWithNetwork.cs b/src/Nethermind/Nethermind.Api/IApiWithNetwork.cs index 0f5d2262535..0b0e05e2a6d 100644 --- a/src/Nethermind/Nethermind.Api/IApiWithNetwork.cs +++ b/src/Nethermind/Nethermind.Api/IApiWithNetwork.cs @@ -2,7 +2,9 @@ // SPDX-License-Identifier: LGPL-3.0-only using System.Collections.Generic; +using Autofac; using Nethermind.Consensus; +using Nethermind.Core; using Nethermind.Core.PubSub; using Nethermind.Grpc; using Nethermind.JsonRpc; @@ -16,6 +18,7 @@ using Nethermind.Synchronization; using Nethermind.Synchronization.Peers; using Nethermind.Sockets; +using Nethermind.Synchronization.ParallelSync; namespace Nethermind.Api { @@ -41,12 +44,22 @@ public interface IApiWithNetwork : IApiWithBlockchain IJsonRpcLocalStats? JsonRpcLocalStats { get; set; } ISessionMonitor? SessionMonitor { get; set; } IStaticNodesManager? StaticNodesManager { get; set; } - ISynchronizer? Synchronizer { get; set; } + ISynchronizer? Synchronizer { get; } + ISyncModeSelector SyncModeSelector { get; } + ISyncProgressResolver? SyncProgressResolver { get; } IPivot? Pivot { get; set; } ISyncPeerPool? SyncPeerPool { get; set; } IPeerDifficultyRefreshPool? PeerDifficultyRefreshPool { get; set; } ISyncServer? SyncServer { get; set; } IWebSocketsManager WebSocketsManager { get; set; } ISubscriptionFactory? SubscriptionFactory { get; set; } + + IContainer? ApiWithNetworkServiceContainer { get; set; } + + public ContainerBuilder ConfigureContainerBuilderFromApiWithNetwork(ContainerBuilder builder) + { + return ConfigureContainerBuilderFromApiWithBlockchain(builder) + .AddPropertiesFrom(this); + } } } diff --git a/src/Nethermind/Nethermind.Api/IApiWithStores.cs b/src/Nethermind/Nethermind.Api/IApiWithStores.cs index f6e02313adc..22b2b0eb9e9 100644 --- a/src/Nethermind/Nethermind.Api/IApiWithStores.cs +++ b/src/Nethermind/Nethermind.Api/IApiWithStores.cs @@ -1,11 +1,13 @@ // SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only +using Autofac; using Nethermind.Blockchain; using Nethermind.Blockchain.Blocks; using Nethermind.Blockchain.Find; using Nethermind.Blockchain.Receipts; using Nethermind.Consensus; +using Nethermind.Core; using Nethermind.Crypto; using Nethermind.Db.Blooms; using Nethermind.State.Repositories; @@ -29,5 +31,11 @@ public interface IApiWithStores : IBasicApi IReceiptMonitor? ReceiptMonitor { get; set; } IWallet? Wallet { get; set; } IBlockStore? BadBlocksStore { get; set; } + + public ContainerBuilder ConfigureContainerBuilderFromApiWithStores(ContainerBuilder builder) + { + return ConfigureContainerBuilderFromBasicApi(builder) + .AddPropertiesFrom(this); + } } } diff --git a/src/Nethermind/Nethermind.Api/IBasicApi.cs b/src/Nethermind/Nethermind.Api/IBasicApi.cs index 3b78f16a865..1ba0adb91f9 100644 --- a/src/Nethermind/Nethermind.Api/IBasicApi.cs +++ b/src/Nethermind/Nethermind.Api/IBasicApi.cs @@ -1,11 +1,14 @@ // SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only +using System; using System.Collections.Generic; using System.IO.Abstractions; using System.Linq; +using Autofac; using Nethermind.Abi; using Nethermind.Api.Extensions; +using Nethermind.Blockchain.Synchronization; using Nethermind.Config; using Nethermind.Core; using Nethermind.Core.Specs; @@ -17,7 +20,6 @@ using Nethermind.Serialization.Json; using Nethermind.Specs.ChainSpecStyle; using Nethermind.Synchronization; -using Nethermind.Synchronization.ParallelSync; namespace Nethermind.Api { @@ -38,10 +40,9 @@ public interface IBasicApi ILogManager LogManager { get; set; } ProtectedPrivateKey? OriginalSignerKey { get; set; } IReadOnlyList Plugins { get; } + [SkipServiceCollection] string SealEngineType { get; set; } ISpecProvider? SpecProvider { get; set; } - ISyncModeSelector SyncModeSelector { get; set; } - ISyncProgressResolver? SyncProgressResolver { get; set; } IBetterPeerStrategy? BetterPeerStrategy { get; set; } ITimestamper Timestamper { get; } ITimerFactory TimerFactory { get; } @@ -57,5 +58,16 @@ public IEnumerable GetConsensusWrapperPlugins() => public IEnumerable GetSynchronizationPlugins() => Plugins.OfType(); + + public ContainerBuilder ConfigureContainerBuilderFromBasicApi(ContainerBuilder builder) + { + builder + .AddPropertiesFrom(this) + .AddSingleton(ConfigProvider.GetConfig()); + + DbProvider!.ConfigureServiceCollection(builder); + + return builder; + } } } diff --git a/src/Nethermind/Nethermind.Api/NethermindApi.cs b/src/Nethermind/Nethermind.Api/NethermindApi.cs index ceee96957d1..624d8d99344 100644 --- a/src/Nethermind/Nethermind.Api/NethermindApi.cs +++ b/src/Nethermind/Nethermind.Api/NethermindApi.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.IO.Abstractions; +using Autofac; using Nethermind.Abi; using Nethermind.Api.Extensions; using Nethermind.Blockchain; @@ -185,14 +186,14 @@ public ISealEngine SealEngine public ISessionMonitor? SessionMonitor { get; set; } public ISpecProvider? SpecProvider { get; set; } public IPoSSwitcher PoSSwitcher { get; set; } = NoPoS.Instance; - public ISyncModeSelector SyncModeSelector { get; set; } = null!; + public ISyncModeSelector SyncModeSelector => ApiWithNetworkServiceContainer?.Resolve()!; - public ISyncProgressResolver? SyncProgressResolver { get; set; } + public ISyncProgressResolver? SyncProgressResolver => ApiWithNetworkServiceContainer?.Resolve(); public IBetterPeerStrategy? BetterPeerStrategy { get; set; } public IPivot? Pivot { get; set; } public ISyncPeerPool? SyncPeerPool { get; set; } public IPeerDifficultyRefreshPool? PeerDifficultyRefreshPool { get; set; } - public ISynchronizer? Synchronizer { get; set; } + public ISynchronizer? Synchronizer => ApiWithNetworkServiceContainer?.Resolve(); public ISyncServer? SyncServer { get; set; } public IWorldState? WorldState { get; set; } public IReadOnlyStateProvider? ChainHeadStateProvider { get; set; } @@ -241,5 +242,7 @@ public ISealEngine SealEngine public CompositePruningTrigger PruningTrigger { get; } = new(); public IProcessExitSource? ProcessExit { get; set; } public CompositeTxGossipPolicy TxGossipPolicy { get; } = new(); + + public IContainer? ApiWithNetworkServiceContainer { get; set; } } } diff --git a/src/Nethermind/Nethermind.Blockchain/Synchronization/ISyncConfig.cs b/src/Nethermind/Nethermind.Blockchain/Synchronization/ISyncConfig.cs index 35c6c3fc1ac..cfee2a225fd 100644 --- a/src/Nethermind/Nethermind.Blockchain/Synchronization/ISyncConfig.cs +++ b/src/Nethermind/Nethermind.Blockchain/Synchronization/ISyncConfig.cs @@ -143,4 +143,7 @@ public interface ISyncConfig : IConfig [ConfigItem(Description = "_Technical._ MultiSyncModeSelector sync mode timer loop interval. Used for testing.", DefaultValue = "1000", HiddenFromDocs = true)] int MultiSyncModeSelectorLoopTimerMs { get; set; } + + [ConfigItem(Description = "_Technical._ MultiSyncModeSelector will wait for header to completely sync first.", DefaultValue = "false", HiddenFromDocs = true)] + bool NeedToWaitForHeader { get; set; } } diff --git a/src/Nethermind/Nethermind.Blockchain/Synchronization/SyncConfig.cs b/src/Nethermind/Nethermind.Blockchain/Synchronization/SyncConfig.cs index d2645336586..c467650ca7a 100644 --- a/src/Nethermind/Nethermind.Blockchain/Synchronization/SyncConfig.cs +++ b/src/Nethermind/Nethermind.Blockchain/Synchronization/SyncConfig.cs @@ -65,6 +65,7 @@ public string? PivotHash public int MallocTrimIntervalSec { get; set; } = 300; public bool? SnapServingEnabled { get; set; } = null; public int MultiSyncModeSelectorLoopTimerMs { get; set; } = 1000; + public bool NeedToWaitForHeader { get; set; } public bool TrieHealing { get; set; } = true; public override string ToString() diff --git a/src/Nethermind/Nethermind.Core.Test/ContainerBuilderExtensionsTests.cs b/src/Nethermind/Nethermind.Core.Test/ContainerBuilderExtensionsTests.cs new file mode 100644 index 00000000000..28e890c8499 --- /dev/null +++ b/src/Nethermind/Nethermind.Core.Test/ContainerBuilderExtensionsTests.cs @@ -0,0 +1,113 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using System; +using Autofac; +using FluentAssertions; +using NUnit.Framework; + +namespace Nethermind.Core.Test; + +public class ContainerBuilderExtensionsTests +{ + [Test] + public void AddPropertiesFrom_CanAddProperties() + { + ITestInterface interfaceImplementation = new InterfaceImplementation(); + IContainer sp = new ContainerBuilder() + .AddPropertiesFrom(interfaceImplementation) + .Build(); + + sp.ResolveOptional().Should().NotBeNull(); + sp.ResolveOptional().Should().BeNull(); + sp.ResolveOptional().Should().BeNull(); + sp.ResolveOptional().Should().BeNull(); + } + + [Test] + public void TestRegisterNamedComponent() + { + IContainer sp = new ContainerBuilder() + .AddScoped() + .AddScoped() + .RegisterNamedComponentInItsOwnLifetime("custom", cfg => + { + // Override it in custom + cfg.AddScoped(); + }) + .Build(); + + using (ILifetimeScope scope = sp.BeginLifetimeScope()) + { + scope.Resolve().Property.Should().BeOfType(); + } + + MainComponentDependency customMainComponentDependency = sp.ResolveNamed("custom").Property; + sp.ResolveNamed("custom").Property.Should().BeOfType(); + + sp.Dispose(); + + customMainComponentDependency.WasDisposed.Should().BeTrue(); + } + + private class MainComponent(MainComponentDependency mainComponentDependency, ILifetimeScope scope) : IDisposable + { + public MainComponentDependency Property => mainComponentDependency; + + public void Dispose() + { + scope.Dispose(); + } + } + + private class MainComponentDependency : IDisposable + { + public bool WasDisposed { get; set; } + + public void Dispose() + { + WasDisposed = true; + } + } + + private class MainComponentDependencySubClass : MainComponentDependency + { + } + + private class InterfaceImplementation : ITestInterface + { + public DeclaredService TheService { get; set; } = new DeclaredService(); + public DeclaredButNullService? NullService { get; set; } = null; + public Ignored IgnoredService { get; set; } = new Ignored(); + public DeclaredInBase BaseService { get; set; } = new DeclaredInBase(); + } + + private interface ITestInterface : ITestInterfaceBase + { + DeclaredService TheService { get; set; } + DeclaredButNullService? NullService { get; set; } + + [SkipServiceCollection] + Ignored IgnoredService { get; set; } + } + + private interface ITestInterfaceBase + { + DeclaredInBase BaseService { get; set; } + } + + private class DeclaredInBase { } + private class DeclaredService { } + private class DeclaredButNullService { } + private class Ignored { } + + private class DisposableService : IDisposable + { + public bool WasDisposed { get; set; } = false; + + public void Dispose() + { + WasDisposed = true; + } + } +} diff --git a/src/Nethermind/Nethermind.Core/ContainerBuilderExtensions.cs b/src/Nethermind/Nethermind.Core/ContainerBuilderExtensions.cs new file mode 100644 index 00000000000..1c30a830b55 --- /dev/null +++ b/src/Nethermind/Nethermind.Core/ContainerBuilderExtensions.cs @@ -0,0 +1,125 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using Autofac; +using Autofac.Features.AttributeFilters; + +namespace Nethermind.Core; + +public static class ContainerBuilderExtensions +{ + /// + /// Add all properties as singleton. It get them ahead of time instead of lazily to prevent the final service provider + /// from disposing it. To prevent a property from being included, use . + /// + /// + /// + /// + /// + public static ContainerBuilder AddPropertiesFrom(this ContainerBuilder configuration, T source) where T : class + { + Type t = typeof(T); + + IEnumerable properties = t + .GetProperties(BindingFlags.GetProperty | BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly) + .Where(p => p.GetCustomAttribute() == null); + + foreach (PropertyInfo propertyInfo in properties) + { + object? val = propertyInfo.GetValue(source); + if (val != null) + { + configuration.RegisterInstance(val).As(propertyInfo.PropertyType); + } + } + + return configuration; + } + + public static ContainerBuilder AddSingleton(this ContainerBuilder builder) where T : notnull + { + builder.RegisterType() + .As() + .WithAttributeFiltering() + .SingleInstance(); + + return builder; + } + + public static ContainerBuilder AddSingleton(this ContainerBuilder builder, T instance) where T : class + { + builder.RegisterInstance(instance) + .As() + .SingleInstance(); + + return builder; + } + + public static ContainerBuilder AddSingleton(this ContainerBuilder builder) where TImpl : notnull where T : notnull + { + builder.RegisterType() + .As() + .AsSelf() + .WithAttributeFiltering() + .SingleInstance(); + + return builder; + } + + public static ContainerBuilder AddKeyedSingleton(this ContainerBuilder builder, string key, T instance) where T : class + { + builder.RegisterInstance(instance) + .Named(key) + .SingleInstance(); + + return builder; + } + + public static ContainerBuilder AddScoped(this ContainerBuilder builder) where T : notnull + { + builder.RegisterType() + .As() + .AsSelf() + .WithAttributeFiltering() + .InstancePerLifetimeScope(); + + return builder; + } + + public static ContainerBuilder AddScoped(this ContainerBuilder builder) where TImpl : notnull where T : notnull + { + builder.RegisterType() + .As() + .WithAttributeFiltering() + .InstancePerLifetimeScope(); + + return builder; + } + + /// + /// A convenient way of creating a service whose member can be configured indipendent of other instance of the same + /// type (assuming the type is of lifetime scope). This is useful for same type with multiple configuration + /// or a graph of multiple same type. The T is expected to be of a main container of sort that contains the + /// main service of interest. + /// Note: The T should dispose an injected ILifetimeScope on dispose as ILifetimeScope is not automatically disposed + /// when parent scope is disposed. + /// + public static ContainerBuilder RegisterNamedComponentInItsOwnLifetime(this ContainerBuilder builder, string name, Action configurator) where T : notnull + { + builder.Register(ctx => ctx.BeginLifetimeScope(configurator).Resolve()) + .Named(name); + + return builder; + } +} + +/// +/// Mark a property so that it is not picked up by `AddPropertiesFrom`. +/// +public class SkipServiceCollectionAttribute : Attribute +{ +} diff --git a/src/Nethermind/Nethermind.Core/Nethermind.Core.csproj b/src/Nethermind/Nethermind.Core/Nethermind.Core.csproj index de2832e6ea5..930e96abe48 100644 --- a/src/Nethermind/Nethermind.Core/Nethermind.Core.csproj +++ b/src/Nethermind/Nethermind.Core/Nethermind.Core.csproj @@ -5,7 +5,10 @@ + + + diff --git a/src/Nethermind/Nethermind.Db/IDbProvider.cs b/src/Nethermind/Nethermind.Db/IDbProvider.cs index 7786271bc74..6a0380b0446 100644 --- a/src/Nethermind/Nethermind.Db/IDbProvider.cs +++ b/src/Nethermind/Nethermind.Db/IDbProvider.cs @@ -3,6 +3,9 @@ using System; using System.Collections.Generic; +using Autofac; +using Microsoft.Extensions.DependencyInjection; +using Nethermind.Core; namespace Nethermind.Db { @@ -30,5 +33,34 @@ public interface IDbProvider : IDisposable void RegisterDb(string dbName, T db) where T : class, IDb; void RegisterColumnDb(string dbName, IColumnsDb db); IEnumerable> GetAllDbMeta(); + + void ConfigureServiceCollection(ContainerBuilder sc) + { + sc.AddSingleton(this); + + // TODO: Have hooks that automatically get these + string[] dbNames = [ + DbNames.State, + DbNames.Code, + DbNames.Metadata, + DbNames.Blocks, + DbNames.Headers, + DbNames.BlockInfos, + DbNames.BadBlocks, + DbNames.Bloom, + DbNames.Metadata, + ]; + foreach (string dbName in dbNames) + { + var db = GetDb(dbName); + sc.AddKeyedSingleton(dbName, db); + sc.AddKeyedSingleton(dbName, db); + sc.AddKeyedSingleton(dbName, db as ITunableDb ?? new NoopTunableDb()); + } + + IColumnsDb receiptColumnDb = GetColumnDb(DbNames.Receipts); + sc.AddSingleton>(receiptColumnDb); + sc.AddKeyedSingleton(DbNames.Receipts, receiptColumnDb as ITunableDb ?? new NoopTunableDb()); + } } } diff --git a/src/Nethermind/Nethermind.Db/ITunableDb.cs b/src/Nethermind/Nethermind.Db/ITunableDb.cs index 7584364badd..00b0edf0f0c 100644 --- a/src/Nethermind/Nethermind.Db/ITunableDb.cs +++ b/src/Nethermind/Nethermind.Db/ITunableDb.cs @@ -3,7 +3,7 @@ namespace Nethermind.Db; -public interface ITunableDb : IDb +public interface ITunableDb { public void Tune(TuneType type); @@ -18,3 +18,10 @@ enum TuneType HashDb } } + +public class NoopTunableDb : ITunableDb +{ + public void Tune(ITunableDb.TuneType type) + { + } +} diff --git a/src/Nethermind/Nethermind.Init/Steps/InitializeNetwork.cs b/src/Nethermind/Nethermind.Init/Steps/InitializeNetwork.cs index 7f4636d56be..db2854c0003 100644 --- a/src/Nethermind/Nethermind.Init/Steps/InitializeNetwork.cs +++ b/src/Nethermind/Nethermind.Init/Steps/InitializeNetwork.cs @@ -3,9 +3,13 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Reflection; using System.Threading; using System.Threading.Tasks; +using Autofac; +using Autofac.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection; using Nethermind.Api; using Nethermind.Api.Extensions; using Nethermind.Blockchain.Synchronization; @@ -126,39 +130,22 @@ private async Task Initialize(CancellationToken cancellationToken) if (_api.Synchronizer is null) { - BlockDownloaderFactory blockDownloaderFactory = new BlockDownloaderFactory( - _api.SpecProvider!, - _api.BlockValidator!, - _api.SealValidator!, - _api.BetterPeerStrategy!, - _api.LogManager); + if (_api.ChainSpec.SealEngineType == SealEngineType.Clique) + _syncConfig.NeedToWaitForHeader = true; // Should this be in chainspec itself? - _api.Synchronizer ??= new Synchronizer( - _api.DbProvider, - _api.NodeStorageFactory.WrapKeyValueStore(_api.DbProvider.StateDb), - _api.SpecProvider!, - _api.BlockTree, - _api.ReceiptStorage!, - _api.SyncPeerPool, - _api.NodeStatsManager!, - _syncConfig, - blockDownloaderFactory, - _api.Pivot, - _api.ProcessExit!, - _api.BetterPeerStrategy, - _api.ChainSpec, - _api.StateReader!, - _api.LogManager); - } + ContainerBuilder builder = new ContainerBuilder(); + _api.ConfigureContainerBuilderFromApiWithNetwork(builder) + .AddSingleton(No.BeaconSync); + builder.RegisterModule(new SynchronizerModule(_syncConfig)); + IContainer container = builder.Build(); - _api.SyncModeSelector = _api.Synchronizer.SyncModeSelector; - _api.SyncProgressResolver = _api.Synchronizer.SyncProgressResolver; + _api.ApiWithNetworkServiceContainer = container; + _api.DisposeStack.Append(container); + } _api.EthSyncingInfo = new EthSyncingInfo(_api.BlockTree, _api.ReceiptStorage!, _syncConfig, - _api.SyncModeSelector, _api.SyncProgressResolver, _api.LogManager); + _api.SyncModeSelector!, _api.SyncProgressResolver!, _api.LogManager); _api.TxGossipPolicy.Policies.Add(new SyncedTxGossipPolicy(_api.SyncModeSelector)); - _api.DisposeStack.Push(_api.SyncModeSelector); - _api.DisposeStack.Push(_api.Synchronizer); ISyncServer syncServer = _api.SyncServer = new SyncServer( _api.TrieStore!.TrieNodeRlpStore, diff --git a/src/Nethermind/Nethermind.Merge.Plugin/MergePlugin.cs b/src/Nethermind/Nethermind.Merge.Plugin/MergePlugin.cs index cb00c3fafc2..2bf987ade8e 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin/MergePlugin.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin/MergePlugin.cs @@ -6,6 +6,10 @@ using System.Net.Http; using System.Threading; using System.Threading.Tasks; +using Autofac; +using Autofac.Core; +using Autofac.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection; using Nethermind.Api; using Nethermind.Api.Extensions; using Nethermind.Blockchain; @@ -29,6 +33,8 @@ using Nethermind.Merge.Plugin.Handlers; using Nethermind.Merge.Plugin.InvalidChainTracker; using Nethermind.Merge.Plugin.Synchronization; +using Nethermind.Synchronization; +using Nethermind.Synchronization.Blocks; using Nethermind.Synchronization.ParallelSync; using Nethermind.TxPool; @@ -434,43 +440,24 @@ public Task InitSynchronization() _api.Pivot = _beaconPivot; - MergeBlockDownloaderFactory blockDownloaderFactory = new MergeBlockDownloaderFactory( - _poSSwitcher, - _beaconPivot, - _api.SpecProvider, - _api.BlockValidator!, - _api.SealValidator!, - _syncConfig, - _api.BetterPeerStrategy!, - new FullStateFinder(_api.BlockTree, _api.StateReader), - _api.LogManager); + ContainerBuilder builder = new ContainerBuilder(); - MergeSynchronizer synchronizer = new MergeSynchronizer( - _api.DbProvider, - _api.NodeStorageFactory.WrapKeyValueStore(_api.DbProvider.StateDb), - _api.SpecProvider!, - _api.BlockTree!, - _api.ReceiptStorage!, - _api.SyncPeerPool, - _api.NodeStatsManager!, - _syncConfig, - blockDownloaderFactory, - _beaconPivot, - _poSSwitcher, - _mergeConfig, - _invalidChainTracker, - _api.ProcessExit!, - _api.BetterPeerStrategy, - _api.ChainSpec, - _beaconSync, - _api.StateReader, - _api.LogManager - ); - _api.Synchronizer = synchronizer; + _api.ConfigureContainerBuilderFromApiWithNetwork(builder) + .AddSingleton(_beaconSync) + .AddSingleton(_beaconPivot) + .AddSingleton(_mergeConfig) + .AddSingleton(_invalidChainTracker); + + builder.RegisterModule(new SynchronizerModule(_syncConfig)); + builder.RegisterModule(new MergeSynchronizerModule()); + + IContainer container = builder.Build(); + _api.ApiWithNetworkServiceContainer = container; + _api.DisposeStack.Append(container); PivotUpdator pivotUpdator = new( _api.BlockTree, - synchronizer.SyncModeSelector, + _api.SyncModeSelector, _api.SyncPeerPool, _syncConfig, _blockCacheService, diff --git a/src/Nethermind/Nethermind.Merge.Plugin/Synchronization/MergeBlockDownloaderFactory.cs b/src/Nethermind/Nethermind.Merge.Plugin/Synchronization/MergeBlockDownloaderFactory.cs deleted file mode 100644 index 8c3b99555bf..00000000000 --- a/src/Nethermind/Nethermind.Merge.Plugin/Synchronization/MergeBlockDownloaderFactory.cs +++ /dev/null @@ -1,81 +0,0 @@ -// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited -// SPDX-License-Identifier: LGPL-3.0-only - -using System; -using Nethermind.Blockchain; -using Nethermind.Blockchain.Receipts; -using Nethermind.Blockchain.Synchronization; -using Nethermind.Consensus; -using Nethermind.Consensus.Validators; -using Nethermind.Core.Specs; -using Nethermind.Logging; -using Nethermind.Synchronization; -using Nethermind.Synchronization.Blocks; -using Nethermind.Synchronization.ParallelSync; -using Nethermind.Synchronization.Peers; -using Nethermind.Synchronization.Reporting; - - -namespace Nethermind.Merge.Plugin.Synchronization -{ - public class MergeBlockDownloaderFactory : IBlockDownloaderFactory - { - private readonly IPoSSwitcher _poSSwitcher; - private readonly IBeaconPivot _beaconPivot; - private readonly ISpecProvider _specProvider; - private readonly IBlockValidator _blockValidator; - private readonly ISealValidator _sealValidator; - private readonly IBetterPeerStrategy _betterPeerStrategy; - private readonly ILogManager _logManager; - private readonly IFullStateFinder _fullStateFinder; - private readonly ISyncConfig _syncConfig; - - public MergeBlockDownloaderFactory( - IPoSSwitcher poSSwitcher, - IBeaconPivot beaconPivot, - ISpecProvider specProvider, - IBlockValidator blockValidator, - ISealValidator sealValidator, - ISyncConfig syncConfig, - IBetterPeerStrategy betterPeerStrategy, - IFullStateFinder fullStateFinder, - ILogManager logManager) - { - _poSSwitcher = poSSwitcher ?? throw new ArgumentNullException(nameof(poSSwitcher)); - _beaconPivot = beaconPivot ?? throw new ArgumentNullException(nameof(beaconPivot)); - _specProvider = specProvider ?? throw new ArgumentNullException(nameof(specProvider)); - _blockValidator = blockValidator ?? throw new ArgumentNullException(nameof(blockValidator)); - _sealValidator = sealValidator ?? throw new ArgumentNullException(nameof(sealValidator)); - _betterPeerStrategy = betterPeerStrategy ?? throw new ArgumentNullException(nameof(betterPeerStrategy)); - _logManager = logManager ?? throw new ArgumentNullException(nameof(logManager)); - _fullStateFinder = fullStateFinder ?? throw new ArgumentNullException(nameof(fullStateFinder)); ; - _syncConfig = syncConfig ?? throw new ArgumentNullException(nameof(syncConfig)); ; - } - - public BlockDownloader Create(ISyncFeed syncFeed, IBlockTree blockTree, IReceiptStorage receiptStorage, - ISyncPeerPool syncPeerPool, ISyncReport syncReport) - { - ChainLevelHelper chainLevelHelper = new ChainLevelHelper(blockTree, _beaconPivot, _syncConfig, _logManager); - return new MergeBlockDownloader( - _poSSwitcher, - _beaconPivot, - syncFeed, - syncPeerPool, - blockTree, - _blockValidator, - _sealValidator, - syncReport, - receiptStorage, - _specProvider, - _betterPeerStrategy, - chainLevelHelper, - _fullStateFinder, - _logManager); - } - - public IPeerAllocationStrategyFactory CreateAllocationStrategyFactory() - { - return new MergeBlocksSyncPeerAllocationStrategyFactory(_poSSwitcher, _beaconPivot, _logManager); - } - } -} diff --git a/src/Nethermind/Nethermind.Merge.Plugin/Synchronization/MergeSynchronizer.cs b/src/Nethermind/Nethermind.Merge.Plugin/Synchronization/MergeSynchronizer.cs index 38e65be39e7..ac3ad98313f 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin/Synchronization/MergeSynchronizer.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin/Synchronization/MergeSynchronizer.cs @@ -1,113 +1,58 @@ // SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only -using Nethermind.Blockchain; -using Nethermind.Blockchain.Receipts; +using System; +using System.Threading; +using System.Threading.Tasks; +using Autofac; +using Autofac.Features.AttributeFilters; using Nethermind.Blockchain.Synchronization; -using Nethermind.Config; -using Nethermind.Consensus; -using Nethermind.Core.Specs; -using Nethermind.Db; +using Nethermind.Core; using Nethermind.Logging; -using Nethermind.Merge.Plugin.InvalidChainTracker; -using Nethermind.Specs.ChainSpecStyle; -using Nethermind.State; -using Nethermind.Stats; using Nethermind.Synchronization; using Nethermind.Synchronization.Blocks; using Nethermind.Synchronization.FastBlocks; using Nethermind.Synchronization.ParallelSync; -using Nethermind.Synchronization.Peers; -using Nethermind.Trie; -using Nethermind.Trie.Pruning; namespace Nethermind.Merge.Plugin.Synchronization; -public class MergeSynchronizer : Synchronizer +public class MergeSynchronizer( + [KeyFilter(nameof(BeaconHeadersSyncFeed))] SyncFeedComponent beaconHeaderComponent, + ISyncConfig syncConfig, + Synchronizer baseSynchronizer, + ILogManager logManager) + : ISynchronizer { - private readonly IPoSSwitcher _poSSwitcher; - private readonly IMergeConfig _mergeConfig; - private readonly IInvalidChainTracker _invalidChainTracker; - private BeaconHeadersSyncFeed _beaconHeadersFeed = null!; - private readonly IBeaconSyncStrategy _beaconSync; + private readonly CancellationTokenSource? _syncCancellation = new(); + private readonly ILogger _logger = logManager.GetClassLogger(); - public override ISyncModeSelector SyncModeSelector => _syncModeSelector ??= new MultiSyncModeSelector( - SyncProgressResolver, - _syncPeerPool, - _syncConfig, - _beaconSync, - _betterPeerStrategy!, - _logManager); - - public MergeSynchronizer( - IDbProvider dbProvider, - INodeStorage nodeStorage, - ISpecProvider specProvider, - IBlockTree blockTree, - IReceiptStorage receiptStorage, - ISyncPeerPool peerPool, - INodeStatsManager nodeStatsManager, - ISyncConfig syncConfig, - IBlockDownloaderFactory blockDownloaderFactory, - IPivot pivot, - IPoSSwitcher poSSwitcher, - IMergeConfig mergeConfig, - IInvalidChainTracker invalidChainTracker, - IProcessExitSource exitSource, - IBetterPeerStrategy betterPeerStrategy, - ChainSpec chainSpec, - IBeaconSyncStrategy beaconSync, - IStateReader stateReader, - ILogManager logManager) - : base( - dbProvider, - nodeStorage, - specProvider, - blockTree, - receiptStorage, - peerPool, - nodeStatsManager, - syncConfig, - blockDownloaderFactory, - pivot, - exitSource, - betterPeerStrategy, - chainSpec, - stateReader, - logManager) + public event EventHandler? SyncEvent { - _invalidChainTracker = invalidChainTracker; - _poSSwitcher = poSSwitcher; - _mergeConfig = mergeConfig; - _beaconSync = beaconSync; + add => baseSynchronizer.SyncEvent += value; + remove => baseSynchronizer.SyncEvent -= value; } - public override void Start() + public void Start() { - if (!_syncConfig.SynchronizationEnabled) + if (!syncConfig.SynchronizationEnabled) { return; } - base.Start(); + baseSynchronizer.Start(); StartBeaconHeadersComponents(); WireMultiSyncModeSelector(); } - private void StartBeaconHeadersComponents() + public Task StopAsync() { - FastBlocksPeerAllocationStrategyFactory fastFactory = new(); - _beaconHeadersFeed = - new(_poSSwitcher, _blockTree, _syncPeerPool, _syncConfig, _syncReport, _pivot, _mergeConfig, _invalidChainTracker, _logManager); - BeaconHeadersSyncDownloader beaconHeadersDownloader = new(_logManager); - - SyncDispatcher dispatcher = CreateDispatcher( - _beaconHeadersFeed!, - beaconHeadersDownloader, - fastFactory - ); + _syncCancellation?.Cancel(); + return baseSynchronizer.StopAsync(); + } - dispatcher.Start(_syncCancellation!.Token).ContinueWith(t => + private void StartBeaconHeadersComponents() + { + beaconHeaderComponent.Dispatcher.Start(_syncCancellation!.Token).ContinueWith(t => { if (t.IsFaulted) { @@ -122,6 +67,36 @@ private void StartBeaconHeadersComponents() private void WireMultiSyncModeSelector() { - WireFeedWithModeSelector(_beaconHeadersFeed); + baseSynchronizer.WireFeedWithModeSelector(beaconHeaderComponent.Feed); + } + + public void Dispose() + { + baseSynchronizer.Dispose(); + } +} + +public class MergeSynchronizerModule : Module +{ + protected override void Load(ContainerBuilder builder) + { + builder + .RegisterType() + .As() + .As>() + .InstancePerLifetimeScope(); + + builder + .AddSingleton() + .AddSingleton() + .AddScoped, MergeBlocksSyncPeerAllocationStrategyFactory>() + + .RegisterNamedComponentInItsOwnLifetime>(nameof(BeaconHeadersSyncFeed), ConfigureBeaconHeader); + } + + private void ConfigureBeaconHeader(ContainerBuilder scopeConfig) + { + scopeConfig.AddScoped, BeaconHeadersSyncFeed>() + .AddScoped, BeaconHeadersSyncDownloader>(); } } diff --git a/src/Nethermind/Nethermind.Optimism/OptimismPlugin.cs b/src/Nethermind/Nethermind.Optimism/OptimismPlugin.cs index 82d7d0665c4..90e05a4c4b6 100644 --- a/src/Nethermind/Nethermind.Optimism/OptimismPlugin.cs +++ b/src/Nethermind/Nethermind.Optimism/OptimismPlugin.cs @@ -2,7 +2,11 @@ // SPDX-License-Identifier: LGPL-3.0-only using System; +using System.Linq; using System.Threading.Tasks; +using Autofac; +using Autofac.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection; using Nethermind.Api; using Nethermind.Api.Extensions; using Nethermind.Consensus; @@ -23,12 +27,13 @@ using Nethermind.Consensus.Validators; using Nethermind.Core; using Nethermind.Merge.Plugin.Synchronization; -using Nethermind.Synchronization.ParallelSync; using Nethermind.HealthChecks; using Nethermind.Serialization.Json; using Nethermind.Specs.ChainSpecStyle; using Nethermind.Serialization.Rlp; using Nethermind.Optimism.Rpc; +using Nethermind.Synchronization; +using Nethermind.Synchronization.ParallelSync; namespace Nethermind.Optimism; @@ -147,42 +152,25 @@ public Task InitSynchronization() _api.BetterPeerStrategy = new MergeBetterPeerStrategy(null!, _api.PoSSwitcher, _beaconPivot, _api.LogManager); _api.Pivot = _beaconPivot; - MergeBlockDownloaderFactory blockDownloaderFactory = new MergeBlockDownloaderFactory( - _api.PoSSwitcher, - _beaconPivot, - _api.SpecProvider, - _api.BlockValidator!, - _api.SealValidator!, - _syncConfig, - _api.BetterPeerStrategy!, - new FullStateFinder(_api.BlockTree, _api.StateReader!), - _api.LogManager); + ContainerBuilder builder = new ContainerBuilder(); + ((INethermindApi)_api).ConfigureContainerBuilderFromApiWithNetwork(builder) + .AddSingleton(_beaconSync) + .AddSingleton(_beaconPivot) + .AddSingleton(_api.PoSSwitcher) + .AddSingleton(_mergeConfig) + .AddSingleton(_invalidChainTracker); - _api.Synchronizer = new MergeSynchronizer( - _api.DbProvider, - _api.NodeStorageFactory.WrapKeyValueStore(_api.DbProvider.StateDb), - _api.SpecProvider!, - _api.BlockTree!, - _api.ReceiptStorage!, - _api.SyncPeerPool, - _api.NodeStatsManager!, - _syncConfig, - blockDownloaderFactory, - _beaconPivot, - _api.PoSSwitcher, - _mergeConfig, - _invalidChainTracker, - _api.ProcessExit!, - _api.BetterPeerStrategy, - _api.ChainSpec, - _beaconSync, - _api.StateReader!, - _api.LogManager - ); + builder.RegisterModule(new SynchronizerModule(_syncConfig)); + builder.RegisterModule(new MergeSynchronizerModule()); + + IContainer container = builder.Build(); + + _api.ApiWithNetworkServiceContainer = container; + _api.DisposeStack.Append(container); _ = new PivotUpdator( _api.BlockTree, - _api.Synchronizer.SyncModeSelector, + _api.SyncModeSelector, _api.SyncPeerPool, _syncConfig, _blockCacheService, diff --git a/src/Nethermind/Nethermind.Runner.Test/Ethereum/ContextWithMocks.cs b/src/Nethermind/Nethermind.Runner.Test/Ethereum/ContextWithMocks.cs index 73c0c925c45..7478cfed5d5 100644 --- a/src/Nethermind/Nethermind.Runner.Test/Ethereum/ContextWithMocks.cs +++ b/src/Nethermind/Nethermind.Runner.Test/Ethereum/ContextWithMocks.cs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LGPL-3.0-only using System.IO.Abstractions; +using Autofac; using Nethermind.Api; using Nethermind.Blockchain; using Nethermind.Blockchain.Filters; @@ -46,6 +47,7 @@ using Nethermind.Trie; using NSubstitute; using Nethermind.Blockchain.Blocks; +using Nethermind.Core; namespace Nethermind.Runner.Test.Ethereum { @@ -75,7 +77,6 @@ public static NethermindApi ContextWithMocks() StaticNodesManager = Substitute.For(), BloomStorage = Substitute.For(), Sealer = Substitute.For(), - Synchronizer = Substitute.For(), BlockchainProcessor = Substitute.For(), BlockProducer = Substitute.For(), DiscoveryApp = Substitute.For(), @@ -102,7 +103,6 @@ public static NethermindApi ContextWithMocks() EngineSignerStore = Substitute.For(), NodeStatsManager = Substitute.For(), RpcModuleProvider = Substitute.For(), - SyncModeSelector = Substitute.For(), SyncPeerPool = Substitute.For(), PeerDifficultyRefreshPool = Substitute.For(), WebSocketsManager = Substitute.For(), @@ -116,10 +116,15 @@ public static NethermindApi ContextWithMocks() TxValidator = new TxValidator(MainnetSpecProvider.Instance.ChainId), UnclesValidator = Substitute.For(), BlockProductionPolicy = Substitute.For(), - SyncProgressResolver = Substitute.For(), BetterPeerStrategy = Substitute.For(), ReceiptMonitor = Substitute.For(), - BadBlocksStore = Substitute.For() + BadBlocksStore = Substitute.For(), + + ApiWithNetworkServiceContainer = new ContainerBuilder() + .AddSingleton(Substitute.For()) + .AddSingleton(Substitute.For()) + .AddSingleton(Substitute.For()) + .Build(), }; api.WorldStateManager = new ReadOnlyWorldStateManager(api.DbProvider, Substitute.For(), LimboLogs.Instance); diff --git a/src/Nethermind/Nethermind.Synchronization.Test/DbTuner/SyncDbTunerTests.cs b/src/Nethermind/Nethermind.Synchronization.Test/DbTuner/SyncDbTunerTests.cs index 8c7954d8b92..ffc2251face 100644 --- a/src/Nethermind/Nethermind.Synchronization.Test/DbTuner/SyncDbTunerTests.cs +++ b/src/Nethermind/Nethermind.Synchronization.Test/DbTuner/SyncDbTunerTests.cs @@ -53,15 +53,6 @@ public void Setup() _receiptDb); } - [TearDown] - public void TearDown() - { - _blockDb?.Dispose(); - _codeDb?.Dispose(); - _receiptDb?.Dispose(); - _stateDb?.Dispose(); - } - [Test] public void WhenSnapIsOn_TriggerStateDbTune() { diff --git a/src/Nethermind/Nethermind.Synchronization.Test/OldStyleFullSynchronizerTests.cs b/src/Nethermind/Nethermind.Synchronization.Test/OldStyleFullSynchronizerTests.cs index d5e3adcbeae..89bd50a3ca4 100644 --- a/src/Nethermind/Nethermind.Synchronization.Test/OldStyleFullSynchronizerTests.cs +++ b/src/Nethermind/Nethermind.Synchronization.Test/OldStyleFullSynchronizerTests.cs @@ -4,7 +4,10 @@ using System; using System.Threading; using System.Threading.Tasks; +using Autofac; +using Autofac.Extensions.DependencyInjection; using FluentAssertions; +using Microsoft.Extensions.DependencyInjection; using Nethermind.Blockchain; using Nethermind.Blockchain.Find; using Nethermind.Blockchain.Receipts; @@ -15,6 +18,7 @@ using Nethermind.Core; using Nethermind.Core.Collections; using Nethermind.Core.Crypto; +using Nethermind.Core.Specs; using Nethermind.Core.Test.Builders; using Nethermind.Core.Timers; using Nethermind.Db; @@ -24,6 +28,7 @@ using Nethermind.State; using Nethermind.Stats; using Nethermind.Synchronization.Blocks; +using Nethermind.Synchronization.ParallelSync; using Nethermind.Synchronization.Peers; using Nethermind.Synchronization.Reporting; using Nethermind.Synchronization.SnapSync; @@ -61,31 +66,34 @@ public async Task Setup() TrieStore trieStore = new(nodeStorage, LimboLogs.Instance); TotalDifficultyBetterPeerStrategy bestPeerStrategy = new(LimboLogs.Instance); Pivot pivot = new(syncConfig); - BlockDownloaderFactory blockDownloaderFactory = new( - MainnetSpecProvider.Instance, - Always.Valid, - Always.Valid, - new TotalDifficultyBetterPeerStrategy(LimboLogs.Instance), - LimboLogs.Instance); IStateReader stateReader = new StateReader(trieStore, _codeDb, LimboLogs.Instance); - _synchronizer = new Synchronizer( - dbProvider, - nodeStorage, - MainnetSpecProvider.Instance, - _blockTree, - _receiptStorage, - _pool, - stats, - syncConfig, - blockDownloaderFactory, - pivot, - Substitute.For(), - bestPeerStrategy, - new ChainSpec(), - stateReader, - LimboLogs.Instance); + ContainerBuilder builder = new ContainerBuilder() + .AddSingleton(nodeStorage) + .AddSingleton(MainnetSpecProvider.Instance) + .AddSingleton(_blockTree) + .AddSingleton(_receiptStorage) + .AddSingleton(_pool) + .AddSingleton(stats) + .AddSingleton(syncConfig) + .AddSingleton(Always.Valid) + .AddSingleton(Always.Valid) + .AddSingleton(pivot) + .AddSingleton(Substitute.For()) + .AddSingleton(bestPeerStrategy) + .AddSingleton(new ChainSpec()) + .AddSingleton(stateReader) + .AddSingleton(No.BeaconSync) + .AddSingleton(LimboLogs.Instance); + dbProvider.ConfigureServiceCollection(builder); + + builder.RegisterModule(new SynchronizerModule(syncConfig)); + + IContainer container = builder.Build(); + + _synchronizer = container.Resolve(); + _syncServer = new SyncServer( trieStore.TrieNodeRlpStore, _codeDb, @@ -94,7 +102,7 @@ public async Task Setup() Always.Valid, Always.Valid, _pool, - _synchronizer.SyncModeSelector, + container.Resolve(), quickConfig, Policy.FullGossip, MainnetSpecProvider.Instance, diff --git a/src/Nethermind/Nethermind.Synchronization.Test/ParallelSync/MultiSyncModeSelectorTests.Scenario.cs b/src/Nethermind/Nethermind.Synchronization.Test/ParallelSync/MultiSyncModeSelectorTests.Scenario.cs index f44d95d9c8c..87ab10fe7bd 100644 --- a/src/Nethermind/Nethermind.Synchronization.Test/ParallelSync/MultiSyncModeSelectorTests.Scenario.cs +++ b/src/Nethermind/Nethermind.Synchronization.Test/ParallelSync/MultiSyncModeSelectorTests.Scenario.cs @@ -145,7 +145,6 @@ public class ScenarioBuilder private readonly List _overwrites = new(); private readonly List _peers = new(); - private bool _needToWaitForHeaders; public ISyncPeerPool SyncPeerPool { get; set; } = null!; @@ -812,7 +811,7 @@ void Test() } TotalDifficultyBetterPeerStrategy bestPeerStrategy = new(LimboLogs.Instance); - MultiSyncModeSelector selector = new(SyncProgressResolver, SyncPeerPool, SyncConfig, BeaconSyncStrategy, bestPeerStrategy, LimboLogs.Instance, _needToWaitForHeaders); + MultiSyncModeSelector selector = new(SyncProgressResolver, SyncPeerPool, SyncConfig, BeaconSyncStrategy, bestPeerStrategy, LimboLogs.Instance); selector.Stop(); selector.Update(); selector.Current.Should().Be(syncMode); @@ -840,7 +839,7 @@ void Test() public ScenarioBuilder WhenConsensusRequiresToWaitForHeaders(bool needToWaitForHeaders) { - _needToWaitForHeaders = needToWaitForHeaders; + SyncConfig.NeedToWaitForHeader = needToWaitForHeaders; return this; } diff --git a/src/Nethermind/Nethermind.Synchronization.Test/SyncThreadTests.cs b/src/Nethermind/Nethermind.Synchronization.Test/SyncThreadTests.cs index fb3f5927289..be5768ee9bc 100644 --- a/src/Nethermind/Nethermind.Synchronization.Test/SyncThreadTests.cs +++ b/src/Nethermind/Nethermind.Synchronization.Test/SyncThreadTests.cs @@ -5,6 +5,9 @@ using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; +using Autofac; +using Autofac.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection; using Nethermind.Blockchain; using Nethermind.Blockchain.BeaconBlockRoot; using Nethermind.Blockchain.Blocks; @@ -42,6 +45,7 @@ using BlockTree = Nethermind.Blockchain.BlockTree; using Nethermind.Synchronization.SnapSync; using Nethermind.Config; +using Nethermind.Core.Specs; using Nethermind.Specs.ChainSpecStyle; using Nethermind.Trie; @@ -356,28 +360,32 @@ private SyncTestContext CreateSyncManager(int index) TotalDifficultyBetterPeerStrategy bestPeerStrategy = new(LimboLogs.Instance); Pivot pivot = new(syncConfig); - BlockDownloaderFactory blockDownloaderFactory = new( - MainnetSpecProvider.Instance, - blockValidator, - sealValidator, - new TotalDifficultyBetterPeerStrategy(LimboLogs.Instance), - logManager); - Synchronizer synchronizer = new( - dbProvider, - new NodeStorage(dbProvider.StateDb), - MainnetSpecProvider.Instance, - tree, - NullReceiptStorage.Instance, - syncPeerPool, - nodeStatsManager, - syncConfig, - blockDownloaderFactory, - pivot, - Substitute.For(), - bestPeerStrategy, - new ChainSpec(), - stateReader, - logManager); + + ContainerBuilder builder = new ContainerBuilder(); + builder + .AddSingleton(dbProvider) + .AddSingleton(new NodeStorage(dbProvider.StateDb)) + .AddSingleton(MainnetSpecProvider.Instance) + .AddSingleton(tree) + .AddSingleton(NullReceiptStorage.Instance) + .AddSingleton(syncPeerPool) + .AddSingleton(nodeStatsManager) + .AddSingleton(syncConfig) + .AddSingleton(blockValidator) + .AddSingleton(sealValidator) + .AddSingleton(pivot) + .AddSingleton(Substitute.For()) + .AddSingleton(bestPeerStrategy) + .AddSingleton(new ChainSpec()) + .AddSingleton(stateReader) + .AddSingleton(receiptStorage) + .AddSingleton(No.BeaconSync) + .AddSingleton(logManager); + dbProvider.ConfigureServiceCollection(builder); + builder.RegisterModule(new SynchronizerModule(syncConfig)); + IContainer container = builder.Build(); + + Synchronizer synchronizer = container.Resolve(); ISyncModeSelector selector = synchronizer.SyncModeSelector; SyncServer syncServer = new( diff --git a/src/Nethermind/Nethermind.Synchronization.Test/SynchronizerTests.cs b/src/Nethermind/Nethermind.Synchronization.Test/SynchronizerTests.cs index 872499cf73f..47c721d274c 100644 --- a/src/Nethermind/Nethermind.Synchronization.Test/SynchronizerTests.cs +++ b/src/Nethermind/Nethermind.Synchronization.Test/SynchronizerTests.cs @@ -8,6 +8,9 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using Autofac; +using Autofac.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection; using Nethermind.Blockchain; using Nethermind.Blockchain.Receipts; using Nethermind.Blockchain.Synchronization; @@ -17,6 +20,7 @@ using Nethermind.Core; using Nethermind.Core.Collections; using Nethermind.Core.Crypto; +using Nethermind.Core.Specs; using Nethermind.Core.Test.Builders; using Nethermind.Core.Timers; using Nethermind.Db; @@ -333,74 +337,48 @@ ISyncConfig GetSyncConfig() => : totalDifficultyBetterPeerStrategy; StateReader reader = new StateReader(trieStore, codeDb, LimboLogs.Instance); - FullStateFinder fullStateFinder = new FullStateFinder(BlockTree, reader); INodeStorage nodeStorage = new NodeStorage(dbProvider.StateDb); SyncPeerPool = new SyncPeerPool(BlockTree, stats, bestPeerStrategy, _logManager, 25); Pivot pivot = new(syncConfig); IInvalidChainTracker invalidChainTracker = new NoopInvalidChainTracker(); + + ContainerBuilder builder = new ContainerBuilder(); + dbProvider.ConfigureServiceCollection(builder); + + builder + .AddSingleton(dbProvider) + .AddSingleton(nodeStorage) + .AddSingleton(MainnetSpecProvider.Instance) + .AddSingleton(BlockTree) + .AddSingleton(NullReceiptStorage.Instance) + .AddSingleton(SyncPeerPool) + .AddSingleton(stats) + .AddSingleton(syncConfig) + .AddSingleton(pivot) + .AddSingleton(poSSwitcher) + .AddSingleton(mergeConfig) + .AddSingleton(invalidChainTracker) + .AddSingleton(Substitute.For()) + .AddSingleton(bestPeerStrategy) + .AddSingleton(new ChainSpec()) + .AddSingleton(No.BeaconSync) + .AddSingleton(reader) + .AddSingleton(Always.Valid) + .AddSingleton(Always.Valid) + .AddSingleton(beaconPivot) + .AddSingleton(_logManager); + + builder.RegisterModule(new SynchronizerModule(syncConfig)); + if (IsMerge(synchronizerType)) { - IBlockDownloaderFactory blockDownloaderFactory = new MergeBlockDownloaderFactory( - poSSwitcher, - beaconPivot, - MainnetSpecProvider.Instance, - Always.Valid, - Always.Valid, - syncConfig, - bestPeerStrategy, - fullStateFinder, - _logManager - ); - Synchronizer = new MergeSynchronizer( - dbProvider, - nodeStorage, - MainnetSpecProvider.Instance, - BlockTree, - NullReceiptStorage.Instance, - SyncPeerPool, - stats, - syncConfig, - blockDownloaderFactory, - pivot, - poSSwitcher, - mergeConfig, - invalidChainTracker, - Substitute.For(), - bestPeerStrategy, - new ChainSpec(), - No.BeaconSync, - reader, - _logManager); - } - else - { - IBlockDownloaderFactory blockDownloaderFactory = new BlockDownloaderFactory( - MainnetSpecProvider.Instance, - Always.Valid, - Always.Valid, - new TotalDifficultyBetterPeerStrategy(_logManager), - _logManager); - - Synchronizer = new Synchronizer( - dbProvider, - nodeStorage, - MainnetSpecProvider.Instance, - BlockTree, - NullReceiptStorage.Instance, - SyncPeerPool, - stats, - syncConfig, - blockDownloaderFactory, - pivot, - Substitute.For(), - bestPeerStrategy, - new ChainSpec(), - reader, - _logManager); + builder.RegisterModule(new MergeSynchronizerModule()); } + IContainer container = builder.Build(); + Synchronizer = container.Resolve(); SyncServer = new SyncServer( trieStore.TrieNodeRlpStore, codeDb, @@ -409,7 +387,7 @@ ISyncConfig GetSyncConfig() => Always.Valid, Always.Valid, SyncPeerPool, - Synchronizer.SyncModeSelector, + container.Resolve(), syncConfig, Policy.FullGossip, MainnetSpecProvider.Instance, diff --git a/src/Nethermind/Nethermind.Synchronization/Blocks/IBlockDownloaderFactory.cs b/src/Nethermind/Nethermind.Synchronization/Blocks/IBlockDownloaderFactory.cs deleted file mode 100644 index 64afb7b1061..00000000000 --- a/src/Nethermind/Nethermind.Synchronization/Blocks/IBlockDownloaderFactory.cs +++ /dev/null @@ -1,65 +0,0 @@ -// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited -// SPDX-License-Identifier: LGPL-3.0-only - -using System; -using Nethermind.Blockchain; -using Nethermind.Blockchain.Receipts; -using Nethermind.Consensus; -using Nethermind.Consensus.Validators; -using Nethermind.Core.Specs; -using Nethermind.Logging; -using Nethermind.Synchronization.ParallelSync; -using Nethermind.Synchronization.Peers; -using Nethermind.Synchronization.Reporting; - -namespace Nethermind.Synchronization.Blocks -{ - public class BlockDownloaderFactory : IBlockDownloaderFactory - { - private readonly ISpecProvider _specProvider; - private readonly IBlockValidator _blockValidator; - private readonly ISealValidator _sealValidator; - private readonly IBetterPeerStrategy _betterPeerStrategy; - private readonly ILogManager _logManager; - - public BlockDownloaderFactory( - ISpecProvider specProvider, - IBlockValidator blockValidator, - ISealValidator sealValidator, - IBetterPeerStrategy betterPeerStrategy, - ILogManager logManager) - { - _specProvider = specProvider ?? throw new ArgumentNullException(nameof(specProvider)); - _blockValidator = blockValidator ?? throw new ArgumentNullException(nameof(blockValidator)); - _sealValidator = sealValidator ?? throw new ArgumentNullException(nameof(sealValidator)); - _betterPeerStrategy = betterPeerStrategy ?? throw new ArgumentNullException(nameof(betterPeerStrategy)); - _logManager = logManager ?? throw new ArgumentNullException(nameof(logManager)); - } - - public BlockDownloader Create(ISyncFeed syncFeed, IBlockTree blockTree, IReceiptStorage receiptStorage, ISyncPeerPool peerPool, ISyncReport syncReport) - { - return new( - syncFeed, - peerPool, - blockTree, - _blockValidator, - _sealValidator, - syncReport, - receiptStorage, - _specProvider, - _betterPeerStrategy, - _logManager); - } - - public IPeerAllocationStrategyFactory CreateAllocationStrategyFactory() - { - return new BlocksSyncPeerAllocationStrategyFactory(); - } - } - - public interface IBlockDownloaderFactory - { - BlockDownloader Create(ISyncFeed syncFeed, IBlockTree blockTree, IReceiptStorage receiptStorage, ISyncPeerPool syncPeerPool, ISyncReport syncReport); - IPeerAllocationStrategyFactory CreateAllocationStrategyFactory(); - } -} diff --git a/src/Nethermind/Nethermind.Synchronization/DbTuner/SyncDbOptimizer.cs b/src/Nethermind/Nethermind.Synchronization/DbTuner/SyncDbOptimizer.cs index e9f5c7c10d5..13a8ecbb4a6 100644 --- a/src/Nethermind/Nethermind.Synchronization/DbTuner/SyncDbOptimizer.cs +++ b/src/Nethermind/Nethermind.Synchronization/DbTuner/SyncDbOptimizer.cs @@ -1,6 +1,8 @@ // SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only +using Autofac.Features.AttributeFilters; +using Microsoft.Extensions.DependencyInjection; using Nethermind.Blockchain.Synchronization; using Nethermind.Db; using Nethermind.Synchronization.FastBlocks; @@ -24,26 +26,32 @@ public SyncDbTuner( ISyncFeed? snapSyncFeed, ISyncFeed? bodiesSyncFeed, ISyncFeed? receiptSyncFeed, - ITunableDb? stateDb, - ITunableDb? codeDb, - ITunableDb? blockDb, - ITunableDb? receiptDb + [KeyFilter(DbNames.State)] ITunableDb? stateDb, + [KeyFilter(DbNames.Code)] ITunableDb? codeDb, + [KeyFilter(DbNames.Blocks)] ITunableDb? blockDb, + [KeyFilter(DbNames.Receipts)] ITunableDb? receiptDb ) { + if (syncConfig.TuneDbMode == ITunableDb.TuneType.Default && syncConfig.BlocksDbTuneDbMode == ITunableDb.TuneType.Default) + { + // Do nothing. + return; + } + // Only these three make sense as they are write heavy // Headers is used everywhere, so slowing read might slow the whole sync. // Statesync is read heavy, Forward sync is just plain too slow to saturate IO. - if (snapSyncFeed is not null) + if (snapSyncFeed is not NoopSyncFeed) { snapSyncFeed.StateChanged += SnapStateChanged; } - if (bodiesSyncFeed is not null) + if (bodiesSyncFeed is not NoopSyncFeed) { bodiesSyncFeed.StateChanged += BodiesStateChanged; } - if (receiptSyncFeed is not null) + if (receiptSyncFeed is not NoopSyncFeed) { receiptSyncFeed.StateChanged += ReceiptsStateChanged; } diff --git a/src/Nethermind/Nethermind.Synchronization/FastBlocks/BodiesSyncFeed.cs b/src/Nethermind/Nethermind.Synchronization/FastBlocks/BodiesSyncFeed.cs index 9b972b68d67..1152f416054 100644 --- a/src/Nethermind/Nethermind.Synchronization/FastBlocks/BodiesSyncFeed.cs +++ b/src/Nethermind/Nethermind.Synchronization/FastBlocks/BodiesSyncFeed.cs @@ -4,6 +4,8 @@ using System; using System.Threading; using System.Threading.Tasks; +using Autofac.Features.AttributeFilters; +using Microsoft.Extensions.DependencyInjection; using Nethermind.Blockchain; using Nethermind.Blockchain.Synchronization; using Nethermind.Consensus.Validators; @@ -50,8 +52,8 @@ public BodiesSyncFeed( ISyncPeerPool syncPeerPool, ISyncConfig syncConfig, ISyncReport syncReport, - IDbMeta blocksDb, - IDb metadataDb, + [KeyFilter(DbNames.Blocks)] IDbMeta blocksDb, + [KeyFilter(DbNames.Metadata)] IDb metadataDb, ILogManager logManager, long flushDbInterval = DefaultFlushDbInterval) : base(metadataDb, specProvider, logManager.GetClassLogger()) diff --git a/src/Nethermind/Nethermind.Synchronization/FastBlocks/ReceiptsSyncFeed.cs b/src/Nethermind/Nethermind.Synchronization/FastBlocks/ReceiptsSyncFeed.cs index e621dc56795..cbfce46215c 100644 --- a/src/Nethermind/Nethermind.Synchronization/FastBlocks/ReceiptsSyncFeed.cs +++ b/src/Nethermind/Nethermind.Synchronization/FastBlocks/ReceiptsSyncFeed.cs @@ -6,6 +6,8 @@ using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; +using Autofac.Features.AttributeFilters; +using Microsoft.Extensions.DependencyInjection; using Nethermind.Blockchain; using Nethermind.Blockchain.Receipts; using Nethermind.Blockchain.Synchronization; @@ -57,7 +59,7 @@ public ReceiptsSyncFeed( ISyncPeerPool syncPeerPool, ISyncConfig syncConfig, ISyncReport syncReport, - IDb metadataDb, + [KeyFilter(DbNames.Metadata)] IDb metadataDb, ILogManager logManager) : base(metadataDb, specProvider, logManager?.GetClassLogger() ?? default) { diff --git a/src/Nethermind/Nethermind.Synchronization/FastSync/TreeSync.cs b/src/Nethermind/Nethermind.Synchronization/FastSync/TreeSync.cs index 4cc449cb47b..e10a80a62a1 100644 --- a/src/Nethermind/Nethermind.Synchronization/FastSync/TreeSync.cs +++ b/src/Nethermind/Nethermind.Synchronization/FastSync/TreeSync.cs @@ -8,6 +8,8 @@ using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; +using Autofac.Features.AttributeFilters; +using Microsoft.Extensions.DependencyInjection; using Nethermind.Blockchain; using Nethermind.Core; using Nethermind.Core.Caching; @@ -74,6 +76,12 @@ public class TreeSync private long _blockNumber; private readonly SyncMode _syncMode; + public TreeSync([KeyFilter(DbNames.Code)] IDb codeDb, INodeStorage nodeStorage, IBlockTree blockTree, ILogManager logManager) + : this(SyncMode.StateNodes, codeDb, nodeStorage, blockTree, logManager) + { + + } + public TreeSync(SyncMode syncMode, IDb codeDb, INodeStorage nodeStorage, IBlockTree blockTree, ILogManager logManager) { _syncMode = syncMode; diff --git a/src/Nethermind/Nethermind.Synchronization/ISynchronizer.cs b/src/Nethermind/Nethermind.Synchronization/ISynchronizer.cs index 512b0a767a5..011659c5238 100644 --- a/src/Nethermind/Nethermind.Synchronization/ISynchronizer.cs +++ b/src/Nethermind/Nethermind.Synchronization/ISynchronizer.cs @@ -15,8 +15,5 @@ public interface ISynchronizer : IDisposable void Start(); Task StopAsync(); - - ISyncProgressResolver SyncProgressResolver { get; } - ISyncModeSelector SyncModeSelector { get; } } } diff --git a/src/Nethermind/Nethermind.Synchronization/MallocTrimmer.cs b/src/Nethermind/Nethermind.Synchronization/MallocTrimmer.cs index 63c6e85e36c..0010bc111db 100644 --- a/src/Nethermind/Nethermind.Synchronization/MallocTrimmer.cs +++ b/src/Nethermind/Nethermind.Synchronization/MallocTrimmer.cs @@ -3,6 +3,7 @@ using System; using System.Diagnostics; +using Nethermind.Blockchain.Synchronization; using Nethermind.Core.Extensions; using Nethermind.Core.Memory; using Nethermind.Logging; @@ -16,6 +17,14 @@ public class MallocTrimmer private readonly MallocHelper _mallocHelper; private readonly ILogger _logger; + public MallocTrimmer( + ISyncModeSelector syncModeSelector, + ISyncConfig syncConfig, + ILogManager logManager + ) : this(syncModeSelector, TimeSpan.FromSeconds(syncConfig.MallocTrimIntervalSec), logManager) + { + } + public MallocTrimmer( ISyncModeSelector syncModeSelector, TimeSpan interval, diff --git a/src/Nethermind/Nethermind.Synchronization/ParallelSync/ISyncFeed.cs b/src/Nethermind/Nethermind.Synchronization/ParallelSync/ISyncFeed.cs index 64ac3f4687e..1f87736fb08 100644 --- a/src/Nethermind/Nethermind.Synchronization/ParallelSync/ISyncFeed.cs +++ b/src/Nethermind/Nethermind.Synchronization/ParallelSync/ISyncFeed.cs @@ -30,6 +30,6 @@ public interface ISyncFeed /// Return true if not finished. May not run even if return true if MultiSyncModeSelector said no, probably /// because it's waiting for other sync or something. - bool IsFinished { get; } + bool IsFinished => false; } } diff --git a/src/Nethermind/Nethermind.Synchronization/ParallelSync/MultiSyncModeSelector.cs b/src/Nethermind/Nethermind.Synchronization/ParallelSync/MultiSyncModeSelector.cs index e9eff01f553..7cfc08deca8 100644 --- a/src/Nethermind/Nethermind.Synchronization/ParallelSync/MultiSyncModeSelector.cs +++ b/src/Nethermind/Nethermind.Synchronization/ParallelSync/MultiSyncModeSelector.cs @@ -8,8 +8,10 @@ using System.Threading; using System.Threading.Tasks; using Nethermind.Blockchain.Synchronization; +using Nethermind.Core; using Nethermind.Int256; using Nethermind.Logging; +using Nethermind.Specs.ChainSpecStyle; using Nethermind.State.Snap; using Nethermind.Synchronization.Peers; @@ -80,8 +82,7 @@ public MultiSyncModeSelector( ISyncConfig syncConfig, IBeaconSyncStrategy beaconSyncStrategy, IBetterPeerStrategy betterPeerStrategy, - ILogManager logManager, - bool needToWaitForHeaders = false) + ILogManager logManager) { _logger = logManager?.GetClassLogger() ?? throw new ArgumentNullException(nameof(logManager)); _syncConfig = syncConfig ?? throw new ArgumentNullException(nameof(syncConfig)); @@ -89,7 +90,7 @@ public MultiSyncModeSelector( _syncPeerPool = syncPeerPool ?? throw new ArgumentNullException(nameof(syncPeerPool)); _betterPeerStrategy = betterPeerStrategy ?? throw new ArgumentNullException(nameof(betterPeerStrategy)); _syncProgressResolver = syncProgressResolver ?? throw new ArgumentNullException(nameof(syncProgressResolver)); - _needToWaitForHeaders = needToWaitForHeaders; + _needToWaitForHeaders = syncConfig.NeedToWaitForHeader; if (syncConfig.FastSyncCatchUpHeightDelta <= FastSyncLag) { diff --git a/src/Nethermind/Nethermind.Synchronization/ParallelSync/NoopSyncFeed.cs b/src/Nethermind/Nethermind.Synchronization/ParallelSync/NoopSyncFeed.cs new file mode 100644 index 00000000000..f04f755c736 --- /dev/null +++ b/src/Nethermind/Nethermind.Synchronization/ParallelSync/NoopSyncFeed.cs @@ -0,0 +1,45 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using System; +using System.Threading; +using System.Threading.Tasks; +using Nethermind.Synchronization.Peers; + +namespace Nethermind.Synchronization.ParallelSync; + +public class NoopSyncFeed : ISyncFeed +{ + public SyncFeedState CurrentState { get; } + +#pragma warning disable CS0067 + public event EventHandler? StateChanged; +#pragma warning disable + + public Task PrepareRequest(CancellationToken token = default) + { + return Task.FromResult(default); + } + + public SyncResponseHandlingResult HandleResponse(T response, PeerInfo? peer = null) + { + return SyncResponseHandlingResult.NotAssigned; + } + + public bool IsMultiFeed { get; } + public AllocationContexts Contexts { get; } + public void Activate() + { + } + + public void Finish() + { + } + + public Task FeedTask => Task.CompletedTask; + public void SyncModeSelectorOnChanged(SyncMode current) + { + } + + public bool IsFinished { get; } = true; +} diff --git a/src/Nethermind/Nethermind.Synchronization/ParallelSync/SyncDispatcher.cs b/src/Nethermind/Nethermind.Synchronization/ParallelSync/SyncDispatcher.cs index 50c38f3384b..2bbdb3e50d4 100644 --- a/src/Nethermind/Nethermind.Synchronization/ParallelSync/SyncDispatcher.cs +++ b/src/Nethermind/Nethermind.Synchronization/ParallelSync/SyncDispatcher.cs @@ -4,6 +4,8 @@ using System; using System.Threading; using System.Threading.Tasks; +using Nethermind.Blockchain.Synchronization; +using Nethermind.Core; using Nethermind.Core.Exceptions; using Nethermind.Core.Extensions; using Nethermind.Logging; @@ -25,6 +27,18 @@ public class SyncDispatcher private readonly SemaphoreSlim _concurrentProcessingSemaphore; + public SyncDispatcher( + ISyncConfig syncConfig, + ISyncFeed? syncFeed, + ISyncDownloader? downloader, + ISyncPeerPool? syncPeerPool, + IPeerAllocationStrategyFactory? peerAllocationStrategy, + ILogManager? logManager) + : this(syncConfig.MaxProcessingThreads, syncFeed, downloader, syncPeerPool, peerAllocationStrategy, logManager) + { + + } + public SyncDispatcher( int maxNumberOfProcessingThread, ISyncFeed? syncFeed, diff --git a/src/Nethermind/Nethermind.Synchronization/ParallelSync/SyncProgressResolver.cs b/src/Nethermind/Nethermind.Synchronization/ParallelSync/SyncProgressResolver.cs index 73a325d3149..705611e0f79 100644 --- a/src/Nethermind/Nethermind.Synchronization/ParallelSync/SyncProgressResolver.cs +++ b/src/Nethermind/Nethermind.Synchronization/ParallelSync/SyncProgressResolver.cs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LGPL-3.0-only using System; +using Autofac.Features.AttributeFilters; using Nethermind.Blockchain; using Nethermind.Blockchain.Synchronization; using Nethermind.Core; @@ -23,19 +24,19 @@ public class SyncProgressResolver : ISyncProgressResolver // ReSharper disable once NotAccessedField.Local private readonly ILogger _logger; - private readonly ISyncFeed? _headersSyncFeed; - private readonly ISyncFeed? _bodiesSyncFeed; - private readonly ISyncFeed? _receiptsSyncFeed; - private readonly ISyncFeed? _snapSyncFeed; + private readonly ISyncFeed _headersSyncFeed; + private readonly ISyncFeed _bodiesSyncFeed; + private readonly ISyncFeed _receiptsSyncFeed; + private readonly ISyncFeed _snapSyncFeed; public SyncProgressResolver( IBlockTree blockTree, IFullStateFinder fullStateFinder, ISyncConfig syncConfig, - ISyncFeed? headersSyncFeed, - ISyncFeed? bodiesSyncFeed, - ISyncFeed? receiptsSyncFeed, - ISyncFeed? snapSyncFeed, + [KeyFilter(nameof(HeadersSyncFeed))] ISyncFeed headersSyncFeed, + ISyncFeed bodiesSyncFeed, + ISyncFeed receiptsSyncFeed, + ISyncFeed snapSyncFeed, ILogManager logManager) { _logger = logManager?.GetClassLogger() ?? throw new ArgumentNullException(nameof(logManager)); @@ -83,11 +84,11 @@ public long FindBestFullState() return _blockTree.FindHeader(blockHash)?.TotalDifficulty == 0 ? null : _blockTree.FindHeader(blockHash)?.TotalDifficulty; } - public bool IsFastBlocksHeadersFinished() => !IsFastBlocks() || !_syncConfig.DownloadHeadersInFastSync || _headersSyncFeed?.IsFinished == true; + public bool IsFastBlocksHeadersFinished() => !IsFastBlocks() || !_syncConfig.DownloadHeadersInFastSync || _headersSyncFeed.IsFinished; - public bool IsFastBlocksBodiesFinished() => !IsFastBlocks() || !_syncConfig.DownloadBodiesInFastSync || _bodiesSyncFeed?.IsFinished == true; + public bool IsFastBlocksBodiesFinished() => !IsFastBlocks() || !_syncConfig.DownloadBodiesInFastSync || _bodiesSyncFeed.IsFinished; - public bool IsFastBlocksReceiptsFinished() => !IsFastBlocks() || !_syncConfig.DownloadReceiptsInFastSync || _receiptsSyncFeed?.IsFinished == true; + public bool IsFastBlocksReceiptsFinished() => !IsFastBlocks() || !_syncConfig.DownloadReceiptsInFastSync || _receiptsSyncFeed.IsFinished; public bool IsSnapGetRangesFinished() => _snapSyncFeed?.IsFinished ?? true; diff --git a/src/Nethermind/Nethermind.Synchronization/SnapSync/ProgressTracker.cs b/src/Nethermind/Nethermind.Synchronization/SnapSync/ProgressTracker.cs index eda6709e66e..b6dba820c0c 100644 --- a/src/Nethermind/Nethermind.Synchronization/SnapSync/ProgressTracker.cs +++ b/src/Nethermind/Nethermind.Synchronization/SnapSync/ProgressTracker.cs @@ -8,7 +8,10 @@ using System.Linq; using System.Text; using System.Threading; +using Autofac.Features.AttributeFilters; +using Microsoft.Extensions.DependencyInjection; using Nethermind.Blockchain; +using Nethermind.Blockchain.Synchronization; using Nethermind.Core; using Nethermind.Core.Collections; using Nethermind.Core.Crypto; @@ -58,6 +61,11 @@ public class ProgressTracker : IDisposable private readonly Pivot _pivot; + public ProgressTracker(IBlockTree blockTree, [KeyFilter(DbNames.State)] IDb db, ILogManager logManager, ISyncConfig syncConfig) + : this(blockTree, db, logManager, syncConfig.SnapSyncAccountRangePartitionCount) + { + } + public ProgressTracker(IBlockTree blockTree, IDb db, ILogManager logManager, int accountRangePartitionCount = 8) { _logger = logManager?.GetClassLogger() ?? throw new ArgumentNullException(nameof(logManager)); diff --git a/src/Nethermind/Nethermind.Synchronization/SnapSync/SnapProvider.cs b/src/Nethermind/Nethermind.Synchronization/SnapSync/SnapProvider.cs index afb19297673..51548bfa9f6 100644 --- a/src/Nethermind/Nethermind.Synchronization/SnapSync/SnapProvider.cs +++ b/src/Nethermind/Nethermind.Synchronization/SnapSync/SnapProvider.cs @@ -6,6 +6,8 @@ using System.Linq; using System.Runtime.InteropServices; using System.Threading; +using Autofac.Features.AttributeFilters; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.ObjectPool; using Nethermind.Core; using Nethermind.Core.Caching; @@ -33,7 +35,7 @@ public class SnapProvider : ISnapProvider // This is actually close to 97% effective. private readonly ClockKeyCache _codeExistKeyCache = new(1024 * 16); - public SnapProvider(ProgressTracker progressTracker, IDb codeDb, INodeStorage nodeStorage, ILogManager logManager) + public SnapProvider(ProgressTracker progressTracker, [KeyFilter(DbNames.Code)] IDb codeDb, INodeStorage nodeStorage, ILogManager logManager) { _codeDb = codeDb ?? throw new ArgumentNullException(nameof(codeDb)); _progressTracker = progressTracker ?? throw new ArgumentNullException(nameof(progressTracker)); diff --git a/src/Nethermind/Nethermind.Synchronization/SyncFeedComponent.cs b/src/Nethermind/Nethermind.Synchronization/SyncFeedComponent.cs new file mode 100644 index 00000000000..93b4fe0df45 --- /dev/null +++ b/src/Nethermind/Nethermind.Synchronization/SyncFeedComponent.cs @@ -0,0 +1,30 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using System; +using System.Threading.Tasks; +using Autofac; +using Nethermind.Synchronization.Blocks; +using Nethermind.Synchronization.ParallelSync; + +namespace Nethermind.Synchronization; + +/// +/// Container to make it simpler to get a bunch of components within a same named scoped. +/// +public class SyncFeedComponent(Lazy> feed, Lazy> dispatcher, Lazy> blockDownloader, ILifetimeScope lifetimeScope) : IDisposable, IAsyncDisposable +{ + public ISyncFeed Feed => feed.Value; + public SyncDispatcher Dispatcher => dispatcher.Value; + public BlockDownloader BlockDownloader => (BlockDownloader)blockDownloader.Value; + + public void Dispose() + { + lifetimeScope.Dispose(); + } + + public async ValueTask DisposeAsync() + { + await lifetimeScope.DisposeAsync(); + } +} diff --git a/src/Nethermind/Nethermind.Synchronization/Synchronizer.cs b/src/Nethermind/Nethermind.Synchronization/Synchronizer.cs index ff69883e6f6..826406ca9de 100644 --- a/src/Nethermind/Nethermind.Synchronization/Synchronizer.cs +++ b/src/Nethermind/Nethermind.Synchronization/Synchronizer.cs @@ -4,165 +4,74 @@ using System; using System.Threading; using System.Threading.Tasks; -using Nethermind.Blockchain; -using Nethermind.Blockchain.Receipts; +using Autofac; +using Autofac.Features.AttributeFilters; using Nethermind.Blockchain.Synchronization; using Nethermind.Config; using Nethermind.Core; using Nethermind.Core.Extensions; -using Nethermind.Core.Specs; -using Nethermind.Db; using Nethermind.Logging; -using Nethermind.Specs.ChainSpecStyle; -using Nethermind.State; using Nethermind.Stats; using Nethermind.Stats.Model; +using Nethermind.Synchronization; using Nethermind.Synchronization.Blocks; using Nethermind.Synchronization.DbTuner; -using Nethermind.Synchronization.FastBlocks - ; +using Nethermind.Synchronization.FastBlocks; using Nethermind.Synchronization.FastSync; using Nethermind.Synchronization.ParallelSync; -using Nethermind.Synchronization.Peers; using Nethermind.Synchronization.Reporting; using Nethermind.Synchronization.SnapSync; using Nethermind.Synchronization.StateSync; -using Nethermind.Trie; namespace Nethermind.Synchronization { - public class Synchronizer : ISynchronizer + public class Synchronizer( + ISyncModeSelector syncModeSelector, + ISyncReport syncReport, + ISyncConfig syncConfig, + ILogManager logManager, + INodeStatsManager nodeStatsManager, + [KeyFilter(nameof(FullSyncFeed))] SyncFeedComponent fullSyncComponent, + [KeyFilter(nameof(FastSyncFeed))] SyncFeedComponent fastSyncComponent, + SyncFeedComponent stateSyncComponent, + SyncFeedComponent snapSyncComponent, + [KeyFilter(nameof(HeadersSyncFeed))] SyncFeedComponent fastHeaderComponent, + SyncFeedComponent oldBodiesComponent, + SyncFeedComponent oldReceiptsComponent, +#pragma warning disable CS9113 // Parameter is unread. But it need to be instantiated to function + SyncDbTuner syncDbTuner, + MallocTrimmer mallocTrimmer, +#pragma warning restore CS9113 // Parameter is unread. + IProcessExitSource exitSource) + : ISynchronizer { private const int FeedsTerminationTimeout = 5_000; - private static MallocTrimmer? s_trimmer; - private static SyncDbTuner? s_dbTuner; + private readonly ILogger _logger = logManager.GetClassLogger(); - private readonly ISpecProvider _specProvider; - private readonly IReceiptStorage _receiptStorage; - private readonly IBlockDownloaderFactory _blockDownloaderFactory; - private readonly INodeStatsManager _nodeStatsManager; - - protected readonly ILogger _logger; - protected readonly IBlockTree _blockTree; - protected readonly ISyncConfig _syncConfig; - protected readonly ISyncPeerPool _syncPeerPool; - protected readonly ILogManager _logManager; - protected readonly ISyncReport _syncReport; - protected readonly IPivot _pivot; - - protected CancellationTokenSource? _syncCancellation = new(); + private CancellationTokenSource? _syncCancellation = new(); /* sync events are used mainly for managing sync peers reputation */ public event EventHandler? SyncEvent; - private readonly IDbProvider _dbProvider; - private FastSyncFeed? _fastSyncFeed; - private StateSyncFeed? _stateSyncFeed; - private FullSyncFeed? _fullSyncFeed; - private readonly IProcessExitSource _exitSource; - protected IBetterPeerStrategy _betterPeerStrategy; - private readonly ChainSpec _chainSpec; - - public ISnapProvider SnapProvider { get; } - - private HeadersSyncFeed? _headersSyncFeed; - private HeadersSyncFeed? HeadersSyncFeed => _headersSyncFeed ??= CreateHeadersSyncFeed(); - - private ReceiptsSyncFeed? _receiptsSyncFeed; - private ReceiptsSyncFeed? ReceiptsSyncFeed => _receiptsSyncFeed ??= CreateReceiptsSyncFeed(); - - private BodiesSyncFeed? _bodiesSyncFeed; - private BodiesSyncFeed? BodiesSyncFeed => _bodiesSyncFeed ??= CreateBodiesSyncFeed(); - - private SnapSyncFeed? _snapSyncFeed; - private SnapSyncFeed? SnapSyncFeed => _snapSyncFeed ??= CreateSnapSyncFeed(); - - private ISyncProgressResolver? _syncProgressResolver; - public ISyncProgressResolver SyncProgressResolver => _syncProgressResolver ??= new SyncProgressResolver( - _blockTree, - new FullStateFinder(_blockTree, _stateReader), - _syncConfig, - HeadersSyncFeed, - BodiesSyncFeed, - ReceiptsSyncFeed, - SnapSyncFeed, - _logManager); - - protected ISyncModeSelector? _syncModeSelector; - private readonly IStateReader _stateReader; - private readonly INodeStorage _nodeStorage; - private readonly ProgressTracker _progressTracker; - - public virtual ISyncModeSelector SyncModeSelector => _syncModeSelector ??= new MultiSyncModeSelector( - SyncProgressResolver, - _syncPeerPool!, - _syncConfig, - No.BeaconSync, - _betterPeerStrategy!, - _logManager, - _chainSpec?.SealEngineType == SealEngineType.Clique); - - public Synchronizer( - IDbProvider dbProvider, - INodeStorage nodeStorage, - ISpecProvider specProvider, - IBlockTree blockTree, - IReceiptStorage receiptStorage, - ISyncPeerPool peerPool, - INodeStatsManager nodeStatsManager, - ISyncConfig syncConfig, - IBlockDownloaderFactory blockDownloaderFactory, - IPivot pivot, - IProcessExitSource processExitSource, - IBetterPeerStrategy betterPeerStrategy, - ChainSpec chainSpec, - IStateReader stateReader, - ILogManager logManager) - { - _dbProvider = dbProvider ?? throw new ArgumentNullException(nameof(dbProvider)); - _nodeStorage = nodeStorage ?? throw new ArgumentNullException(nameof(nodeStorage)); - _logger = logManager?.GetClassLogger() ?? throw new ArgumentNullException(nameof(logManager)); - _specProvider = specProvider ?? throw new ArgumentNullException(nameof(specProvider)); - _blockTree = blockTree ?? throw new ArgumentNullException(nameof(blockTree)); - _receiptStorage = receiptStorage ?? throw new ArgumentNullException(nameof(receiptStorage)); - _syncConfig = syncConfig ?? throw new ArgumentNullException(nameof(syncConfig)); - _blockDownloaderFactory = blockDownloaderFactory ?? throw new ArgumentNullException(nameof(blockDownloaderFactory)); - _pivot = pivot ?? throw new ArgumentNullException(nameof(pivot)); - _syncPeerPool = peerPool ?? throw new ArgumentNullException(nameof(peerPool)); - _nodeStatsManager = nodeStatsManager ?? throw new ArgumentNullException(nameof(nodeStatsManager)); - _exitSource = processExitSource ?? throw new ArgumentNullException(nameof(processExitSource)); - _logManager = logManager ?? throw new ArgumentNullException(nameof(logManager)); - _betterPeerStrategy = betterPeerStrategy ?? throw new ArgumentNullException(nameof(betterPeerStrategy)); - _chainSpec = chainSpec ?? throw new ArgumentNullException(nameof(chainSpec)); - _stateReader = stateReader ?? throw new ArgumentNullException(nameof(_stateReader)); - - _syncReport = new SyncReport(_syncPeerPool!, nodeStatsManager!, _syncConfig, _pivot, logManager); - - _progressTracker = new( - blockTree, - dbProvider.StateDb, - logManager, - _syncConfig.SnapSyncAccountRangePartitionCount); - SnapProvider = new SnapProvider(_progressTracker, dbProvider.CodeDb, nodeStorage, logManager); - } + public ISyncModeSelector SyncModeSelector => syncModeSelector; public virtual void Start() { - if (!_syncConfig.SynchronizationEnabled) + if (!syncConfig.SynchronizationEnabled) { return; } StartFullSyncComponents(); - if (_syncConfig.FastSync) + if (syncConfig.FastSync) { StartFastBlocksComponents(); StartFastSyncComponents(); - if (_syncConfig.SnapSync) + if (syncConfig.SnapSync) { StartSnapSyncComponents(); } @@ -170,72 +79,20 @@ public virtual void Start() StartStateSyncComponents(); } - if (_syncConfig.TuneDbMode != ITunableDb.TuneType.Default || _syncConfig.BlocksDbTuneDbMode != ITunableDb.TuneType.Default) + if (syncConfig.ExitOnSynced) { - SetupDbOptimizer(); - } - - if (_syncConfig.ExitOnSynced) - { - _exitSource.WatchForExit(SyncModeSelector, _logManager, TimeSpan.FromSeconds(_syncConfig.ExitOnSyncedWaitTimeSec)); + exitSource.WatchForExit(SyncModeSelector, logManager, TimeSpan.FromSeconds(syncConfig.ExitOnSyncedWaitTimeSec)); } WireMultiSyncModeSelector(); - s_trimmer ??= new MallocTrimmer(SyncModeSelector, TimeSpan.FromSeconds(_syncConfig.MallocTrimIntervalSec), _logManager); - SyncModeSelector.Changed += _syncReport.SyncModeSelectorOnChanged; - } - - private HeadersSyncFeed? CreateHeadersSyncFeed() - { - if (!_syncConfig.FastSync || !_syncConfig.DownloadHeadersInFastSync) return null; - return new HeadersSyncFeed(_blockTree, _syncPeerPool, _syncConfig, _syncReport, _logManager); - } - - private BodiesSyncFeed? CreateBodiesSyncFeed() - { - if (!_syncConfig.FastSync || !_syncConfig.DownloadHeadersInFastSync || !_syncConfig.DownloadBodiesInFastSync) return null; - return new BodiesSyncFeed(_specProvider, _blockTree, _syncPeerPool, _syncConfig, _syncReport, _dbProvider.BlocksDb, _dbProvider.MetadataDb, _logManager); - } - - private ReceiptsSyncFeed? CreateReceiptsSyncFeed() - { - if (!_syncConfig.FastSync || !_syncConfig.DownloadHeadersInFastSync || !_syncConfig.DownloadBodiesInFastSync || !_syncConfig.DownloadReceiptsInFastSync) return null; - return new ReceiptsSyncFeed(_specProvider, _blockTree, _receiptStorage, _syncPeerPool, _syncConfig, _syncReport, _dbProvider.MetadataDb, _logManager); - } - - private SnapSyncFeed? CreateSnapSyncFeed() - { - if (!_syncConfig.FastSync || !_syncConfig.SnapSync) return null; - return new SnapSyncFeed(SnapProvider, _logManager); - } - - private void SetupDbOptimizer() - { - s_dbTuner ??= new SyncDbTuner( - _syncConfig, - SnapSyncFeed, - BodiesSyncFeed, - ReceiptsSyncFeed, - _dbProvider.StateDb as ITunableDb, - _dbProvider.CodeDb as ITunableDb, - _dbProvider.BlocksDb as ITunableDb, - _dbProvider.ReceiptsDb as ITunableDb); + SyncModeSelector.Changed += syncReport.SyncModeSelectorOnChanged; } private void StartFullSyncComponents() { - _fullSyncFeed = new FullSyncFeed(); - BlockDownloader fullSyncBlockDownloader = _blockDownloaderFactory.Create(_fullSyncFeed, _blockTree, _receiptStorage, _syncPeerPool, _syncReport); - fullSyncBlockDownloader.SyncEvent += DownloaderOnSyncEvent; - - SyncDispatcher dispatcher = CreateDispatcher( - _fullSyncFeed, - fullSyncBlockDownloader, - _blockDownloaderFactory.CreateAllocationStrategyFactory() - ); - - dispatcher.Start(_syncCancellation!.Token).ContinueWith(t => + fullSyncComponent.BlockDownloader.SyncEvent += DownloaderOnSyncEvent; + fullSyncComponent.Dispatcher.Start(_syncCancellation!.Token).ContinueWith(t => { if (t.IsFaulted) { @@ -250,17 +107,8 @@ private void StartFullSyncComponents() private void StartFastSyncComponents() { - _fastSyncFeed = new FastSyncFeed(_syncConfig); - BlockDownloader downloader = _blockDownloaderFactory.Create(_fastSyncFeed, _blockTree, _receiptStorage, _syncPeerPool, _syncReport); - downloader.SyncEvent += DownloaderOnSyncEvent; - - SyncDispatcher dispatcher = CreateDispatcher( - _fastSyncFeed, - downloader, - _blockDownloaderFactory.CreateAllocationStrategyFactory() - ); - - dispatcher.Start(_syncCancellation!.Token).ContinueWith(t => + fastSyncComponent.BlockDownloader.SyncEvent += DownloaderOnSyncEvent; + fastSyncComponent.Dispatcher.Start(_syncCancellation!.Token).ContinueWith(t => { if (t.IsFaulted) { @@ -275,15 +123,7 @@ private void StartFastSyncComponents() private void StartStateSyncComponents() { - TreeSync treeSync = new(SyncMode.StateNodes, _dbProvider.CodeDb, _nodeStorage, _blockTree, _logManager); - _stateSyncFeed = new StateSyncFeed(treeSync, _logManager); - SyncDispatcher stateSyncDispatcher = CreateDispatcher( - _stateSyncFeed, - new StateSyncDownloader(_logManager), - new StateSyncAllocationStrategyFactory() - ); - - Task syncDispatcherTask = stateSyncDispatcher.Start(_syncCancellation.Token).ContinueWith(t => + Task syncDispatcherTask = stateSyncComponent.Dispatcher.Start(_syncCancellation.Token).ContinueWith(t => { if (t.IsFaulted) { @@ -296,15 +136,10 @@ private void StartStateSyncComponents() }); } + private void StartSnapSyncComponents() { - SyncDispatcher dispatcher = CreateDispatcher( - SnapSyncFeed, - new SnapSyncDownloader(_logManager), - new SnapSyncAllocationStrategyFactory() - ); - - Task _ = dispatcher.Start(_syncCancellation!.Token).ContinueWith(t => + Task _ = snapSyncComponent.Dispatcher.Start(_syncCancellation!.Token).ContinueWith(t => { if (t.IsFaulted) { @@ -319,14 +154,7 @@ private void StartSnapSyncComponents() private void StartFastBlocksComponents() { - FastBlocksPeerAllocationStrategyFactory fastFactory = new(); - SyncDispatcher headersDispatcher = CreateDispatcher( - HeadersSyncFeed, - new HeadersSyncDownloader(_logManager), - fastFactory - ); - - Task headersTask = headersDispatcher.Start(_syncCancellation!.Token).ContinueWith(t => + Task headersTask = fastHeaderComponent.Dispatcher.Start(_syncCancellation!.Token).ContinueWith(t => { if (t.IsFaulted) { @@ -338,18 +166,11 @@ private void StartFastBlocksComponents() } }); - if (_syncConfig.DownloadHeadersInFastSync) + if (syncConfig.DownloadHeadersInFastSync) { - if (_syncConfig.DownloadBodiesInFastSync) + if (syncConfig.DownloadBodiesInFastSync) { - - SyncDispatcher bodiesDispatcher = CreateDispatcher( - BodiesSyncFeed!, - new BodiesSyncDownloader(_logManager), - fastFactory - ); - - Task bodiesTask = bodiesDispatcher.Start(_syncCancellation.Token).ContinueWith(t => + Task bodiesTask = oldBodiesComponent.Dispatcher.Start(_syncCancellation.Token).ContinueWith(t => { if (t.IsFaulted) { @@ -362,15 +183,9 @@ private void StartFastBlocksComponents() }); } - if (_syncConfig.DownloadReceiptsInFastSync) + if (syncConfig.DownloadReceiptsInFastSync) { - SyncDispatcher receiptsDispatcher = CreateDispatcher( - ReceiptsSyncFeed!, - new ReceiptsSyncDispatcher(_logManager), - fastFactory - ); - - Task receiptsTask = receiptsDispatcher.Start(_syncCancellation.Token).ContinueWith(t => + Task receiptsTask = oldReceiptsComponent.Dispatcher.Start(_syncCancellation.Token).ContinueWith(t => { if (t.IsFaulted) { @@ -385,17 +200,6 @@ private void StartFastBlocksComponents() } } - protected SyncDispatcher CreateDispatcher(ISyncFeed feed, ISyncDownloader downloader, IPeerAllocationStrategyFactory peerAllocationStrategyFactory) - { - return new( - _syncConfig.MaxProcessingThreads, - feed!, - downloader, - _syncPeerPool, - peerAllocationStrategyFactory, - _logManager); - } - private static NodeStatsEventType Convert(SyncEvent syncEvent) { return syncEvent switch @@ -410,7 +214,7 @@ private static NodeStatsEventType Convert(SyncEvent syncEvent) private void DownloaderOnSyncEvent(object? sender, SyncEventArgs e) { - _nodeStatsManager.ReportSyncEvent(e.Peer.Node, Convert(e.SyncEvent)); + nodeStatsManager.ReportSyncEvent(e.Peer.Node, Convert(e.SyncEvent)); SyncEvent?.Invoke(this, e); } @@ -421,27 +225,27 @@ public Task StopAsync() return Task.WhenAny( Task.Delay(FeedsTerminationTimeout), Task.WhenAll( - _fastSyncFeed?.FeedTask ?? Task.CompletedTask, - _stateSyncFeed?.FeedTask ?? Task.CompletedTask, - SnapSyncFeed?.FeedTask ?? Task.CompletedTask, - _fullSyncFeed?.FeedTask ?? Task.CompletedTask, - HeadersSyncFeed?.FeedTask ?? Task.CompletedTask, - BodiesSyncFeed?.FeedTask ?? Task.CompletedTask, - ReceiptsSyncFeed?.FeedTask ?? Task.CompletedTask)); + fullSyncComponent.Feed.FeedTask, + fastSyncComponent.Feed.FeedTask, + stateSyncComponent.Feed.FeedTask, + snapSyncComponent.Feed.FeedTask, + fastHeaderComponent.Feed.FeedTask, + oldBodiesComponent.Feed.FeedTask, + oldReceiptsComponent.Feed.FeedTask)); } private void WireMultiSyncModeSelector() { - WireFeedWithModeSelector(_fastSyncFeed); - WireFeedWithModeSelector(_stateSyncFeed); - WireFeedWithModeSelector(SnapSyncFeed); - WireFeedWithModeSelector(_fullSyncFeed); - WireFeedWithModeSelector(HeadersSyncFeed); - WireFeedWithModeSelector(BodiesSyncFeed); - WireFeedWithModeSelector(ReceiptsSyncFeed); + WireFeedWithModeSelector(fullSyncComponent.Feed); + WireFeedWithModeSelector(fastSyncComponent.Feed); + WireFeedWithModeSelector(stateSyncComponent.Feed); + WireFeedWithModeSelector(snapSyncComponent.Feed); + WireFeedWithModeSelector(fastHeaderComponent.Feed); + WireFeedWithModeSelector(oldBodiesComponent.Feed); + WireFeedWithModeSelector(oldReceiptsComponent.Feed); } - protected void WireFeedWithModeSelector(ISyncFeed? feed) + public void WireFeedWithModeSelector(ISyncFeed? feed) { if (feed is null) return; SyncModeSelector.Changed += ((sender, args) => @@ -454,17 +258,141 @@ protected void WireFeedWithModeSelector(ISyncFeed? feed) public void Dispose() { CancellationTokenExtensions.CancelDisposeAndClear(ref _syncCancellation); - _syncReport.Dispose(); - _fastSyncFeed?.Dispose(); - _stateSyncFeed?.Dispose(); - _stateSyncFeed = null; - SnapSyncFeed?.Dispose(); - _snapSyncFeed = null; - _fullSyncFeed?.Dispose(); - HeadersSyncFeed?.Dispose(); - BodiesSyncFeed?.Dispose(); - ReceiptsSyncFeed?.Dispose(); - _progressTracker.Dispose(); } } } + +public class SynchronizerModule(ISyncConfig syncConfig) : Module +{ + protected override void Load(ContainerBuilder builder) + { + base.Load(builder); + + builder + .AddSingleton() + + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + + // For blocks. There are two block scope, Fast and Full + .AddScoped>() + .AddScoped, BlockDownloader>() + .AddScoped, BlocksSyncPeerAllocationStrategyFactory>() + .AddScoped>() + + // For headers. There are two header scope, Fast and Beacon + .AddScoped>() + .AddScoped, HeadersSyncDownloader>() + .AddScoped, FastBlocksPeerAllocationStrategyFactory>() + .AddScoped>() + + // SyncProgress resolver need one header sync batch feed, which is the fast header one. + .Register(ctx => ctx + .ResolveNamed>(nameof(HeadersSyncFeed)) + .Feed) + .Named>(nameof(HeadersSyncFeed)); + + ConfigureSnapComponent(builder); + ConfigureReceiptSyncComponent(builder); + ConfigureBodiesSyncComponent(builder); + ConfigureStateSyncComponent(builder); + + builder + .RegisterNamedComponentInItsOwnLifetime>(nameof(HeadersSyncFeed), ConfigureFastHeader) + .RegisterNamedComponentInItsOwnLifetime>(nameof(FastSyncFeed), ConfigureFastSync) + .RegisterNamedComponentInItsOwnLifetime>(nameof(FullSyncFeed), ConfigureFullSync); + } + + private void ConfigureFullSync(ContainerBuilder scopeConfig) + { + scopeConfig.AddScoped, FullSyncFeed>(); + } + + private void ConfigureFastSync(ContainerBuilder scopeConfig) + { + if (syncConfig.FastSync) + { + scopeConfig.AddScoped, FastSyncFeed>(); + } + else + { + scopeConfig.AddScoped, NoopSyncFeed>(); + } + } + + private void ConfigureFastHeader(ContainerBuilder scopeConfig) + { + if (!syncConfig.FastSync || !syncConfig.DownloadHeadersInFastSync) + { + scopeConfig.AddScoped, NoopSyncFeed>(); + } + else + { + scopeConfig.AddScoped, HeadersSyncFeed>(); + } + } + + private void ConfigureSnapComponent(ContainerBuilder serviceCollection) + { + serviceCollection + .AddSingleton() + .AddSingleton(); + + ConfigureSingletonSyncFeed(serviceCollection); + + if (!syncConfig.FastSync || !syncConfig.SnapSync) + { + serviceCollection.AddSingleton, NoopSyncFeed>(); + } + } + + private void ConfigureReceiptSyncComponent(ContainerBuilder serviceCollection) + { + ConfigureSingletonSyncFeed(serviceCollection); + + if (!syncConfig.FastSync || !syncConfig.DownloadHeadersInFastSync || + !syncConfig.DownloadBodiesInFastSync || + !syncConfig.DownloadReceiptsInFastSync) + { + serviceCollection.AddSingleton, NoopSyncFeed>(); + } + } + + private void ConfigureBodiesSyncComponent(ContainerBuilder serviceCollection) + { + ConfigureSingletonSyncFeed(serviceCollection); + + if (!syncConfig.FastSync || !syncConfig.DownloadHeadersInFastSync || + !syncConfig.DownloadBodiesInFastSync) + { + serviceCollection.AddSingleton, NoopSyncFeed>(); + } + + } + + private void ConfigureStateSyncComponent(ContainerBuilder serviceCollection) + { + serviceCollection + .AddSingleton(); + + ConfigureSingletonSyncFeed(serviceCollection); + + // Disable it by setting noop + if (!syncConfig.FastSync) serviceCollection.AddSingleton, NoopSyncFeed>(); + } + + private static void ConfigureSingletonSyncFeed(ContainerBuilder serviceCollection) where TFeed : class, ISyncFeed where TDownloader : class, ISyncDownloader where TAllocationStrategy : class, IPeerAllocationStrategyFactory + { + serviceCollection + .AddSingleton, TFeed>() + .AddSingleton>() + .AddSingleton, TDownloader>() + .AddSingleton, TAllocationStrategy>() + .AddSingleton>(); + } + +}