diff --git a/src/Nethermind/Nethermind.Analytics/AnalyticsPlugin.cs b/src/Nethermind/Nethermind.Analytics/AnalyticsPlugin.cs index 503ce7ffc4c..27c415208fe 100644 --- a/src/Nethermind/Nethermind.Analytics/AnalyticsPlugin.cs +++ b/src/Nethermind/Nethermind.Analytics/AnalyticsPlugin.cs @@ -12,14 +12,11 @@ namespace Nethermind.Analytics { - public class AnalyticsPlugin : INethermindPlugin + public class AnalyticsPlugin(IAnalyticsConfig analyticsConfig, IInitConfig initConfig) : INethermindPlugin { - private IAnalyticsConfig _analyticsConfig; private IList _publishers; private INethermindApi _api; - private bool _isOn; - public ValueTask DisposeAsync() { return ValueTask.CompletedTask; } public string Name => "Analytics"; @@ -28,19 +25,20 @@ public class AnalyticsPlugin : INethermindPlugin public string Author => "Nethermind"; + + public bool Enabled => initConfig.WebSocketsEnabled && + (analyticsConfig.PluginsEnabled || + analyticsConfig.StreamBlocks || + analyticsConfig.StreamTransactions); + public Task Init(INethermindApi api) { _api = api; var (getFromAPi, _) = _api.ForInit; - _analyticsConfig = getFromAPi.Config(); IInitConfig initConfig = getFromAPi.Config(); - _isOn = initConfig.WebSocketsEnabled && - (_analyticsConfig.PluginsEnabled || - _analyticsConfig.StreamBlocks || - _analyticsConfig.StreamTransactions); - if (!_isOn) + if (!Enabled) { if (!initConfig.WebSocketsEnabled) { @@ -57,7 +55,7 @@ public Task Init(INethermindApi api) private void TxPoolOnNewDiscovered(object sender, TxEventArgs e) { - if (_analyticsConfig.StreamTransactions) + if (analyticsConfig.StreamTransactions) { foreach (IPublisher publisher in _publishers) { @@ -70,12 +68,12 @@ private void TxPoolOnNewDiscovered(object sender, TxEventArgs e) public Task InitNetworkProtocol() { var (getFromAPi, _) = _api.ForNetwork; - if (_isOn) + if (Enabled) { getFromAPi.TxPool!.NewDiscovered += TxPoolOnNewDiscovered; } - if (_isOn) + if (Enabled) { AnalyticsWebSocketsModule webSocketsModule = new(getFromAPi.EthereumJsonSerializer, getFromAPi.LogManager); getFromAPi.WebSocketsManager!.AddModule(webSocketsModule, true); diff --git a/src/Nethermind/Nethermind.Api.Test/TestPlugin.cs b/src/Nethermind/Nethermind.Api.Test/TestPlugin.cs index 39aa5a8be2e..60b5375a548 100644 --- a/src/Nethermind/Nethermind.Api.Test/TestPlugin.cs +++ b/src/Nethermind/Nethermind.Api.Test/TestPlugin.cs @@ -30,5 +30,7 @@ public Task InitRpcModules() { throw new System.NotImplementedException(); } + + public bool Enabled => true; } } diff --git a/src/Nethermind/Nethermind.Api.Test/TestPlugin2.cs b/src/Nethermind/Nethermind.Api.Test/TestPlugin2.cs index 51377593c31..e84df3677c5 100644 --- a/src/Nethermind/Nethermind.Api.Test/TestPlugin2.cs +++ b/src/Nethermind/Nethermind.Api.Test/TestPlugin2.cs @@ -30,5 +30,7 @@ public Task InitRpcModules() { throw new System.NotImplementedException(); } + + public bool Enabled => true; } } diff --git a/src/Nethermind/Nethermind.Api/Extensions/IConsensusPlugin.cs b/src/Nethermind/Nethermind.Api/Extensions/IConsensusPlugin.cs index 9a0be89152e..88b0aad8d6b 100644 --- a/src/Nethermind/Nethermind.Api/Extensions/IConsensusPlugin.cs +++ b/src/Nethermind/Nethermind.Api/Extensions/IConsensusPlugin.cs @@ -1,13 +1,7 @@ // SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only -using System.Threading.Tasks; -using Nethermind.Config; using Nethermind.Consensus; -using Nethermind.Consensus.Producers; -using Nethermind.Logging; -using Nethermind.Serialization.Json; -using Nethermind.Specs.ChainSpecStyle; namespace Nethermind.Api.Extensions { @@ -15,9 +9,6 @@ public interface IConsensusPlugin : INethermindPlugin, IBlockProducerFactory { string SealEngineType { get; } - INethermindApi CreateApi(IConfigProvider configProvider, IJsonSerializer jsonSerializer, - ILogManager logManager, ChainSpec chainSpec) => new NethermindApi(configProvider, jsonSerializer, logManager, chainSpec); - IBlockProducerRunner CreateBlockProducerRunner(); } } diff --git a/src/Nethermind/Nethermind.Api/Extensions/IConsensusWrapperPlugin.cs b/src/Nethermind/Nethermind.Api/Extensions/IConsensusWrapperPlugin.cs index becb062362d..1654ca3ea46 100644 --- a/src/Nethermind/Nethermind.Api/Extensions/IConsensusWrapperPlugin.cs +++ b/src/Nethermind/Nethermind.Api/Extensions/IConsensusWrapperPlugin.cs @@ -17,6 +17,6 @@ public interface IConsensusWrapperPlugin : INethermindPlugin /// int Priority => 0; - bool Enabled { get; } + bool ConsensusWrapperEnabled { get; } } } diff --git a/src/Nethermind/Nethermind.Api/Extensions/IInitializationPlugin.cs b/src/Nethermind/Nethermind.Api/Extensions/IInitializationPlugin.cs deleted file mode 100644 index 308038d06e8..00000000000 --- a/src/Nethermind/Nethermind.Api/Extensions/IInitializationPlugin.cs +++ /dev/null @@ -1,19 +0,0 @@ -// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited -// SPDX-License-Identifier: LGPL-3.0-only - -namespace Nethermind.Api.Extensions; - -/// -/// Assemblies containing instances of this interface will be the ones -/// used to load custom initialization steps. -/// -public interface IInitializationPlugin : INethermindPlugin -{ - /// - /// This method will be called on the plugin instance - /// decide whether or not we need to run initialization steps - /// defined in its assembly. It receives the api to be able to - /// look at the config. - /// - bool ShouldRunSteps(INethermindApi api); -} diff --git a/src/Nethermind/Nethermind.Api/Extensions/INethermindPlugin.cs b/src/Nethermind/Nethermind.Api/Extensions/INethermindPlugin.cs index 2c9f2042f42..d4c67139e6e 100644 --- a/src/Nethermind/Nethermind.Api/Extensions/INethermindPlugin.cs +++ b/src/Nethermind/Nethermind.Api/Extensions/INethermindPlugin.cs @@ -3,6 +3,8 @@ using System; using System.Threading.Tasks; +using Autofac; +using Autofac.Core; namespace Nethermind.Api.Extensions; @@ -23,4 +25,7 @@ void InitTxTypesAndRlpDecoders(INethermindApi api) { } Task InitRpcModules() => Task.CompletedTask; bool MustInitialize => false; + + bool Enabled { get; } + IModule? ContainerModule => null; } diff --git a/src/Nethermind/Nethermind.Api/Extensions/ISynchronizationPlugin.cs b/src/Nethermind/Nethermind.Api/Extensions/ISynchronizationPlugin.cs index 9defba7560c..d47de6925df 100644 --- a/src/Nethermind/Nethermind.Api/Extensions/ISynchronizationPlugin.cs +++ b/src/Nethermind/Nethermind.Api/Extensions/ISynchronizationPlugin.cs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LGPL-3.0-only using System.Threading.Tasks; +using Autofac; namespace Nethermind.Api.Extensions { diff --git a/src/Nethermind/Nethermind.Api/IApiWithBlockchain.cs b/src/Nethermind/Nethermind.Api/IApiWithBlockchain.cs index da24eaa918b..be91259ba3b 100644 --- a/src/Nethermind/Nethermind.Api/IApiWithBlockchain.cs +++ b/src/Nethermind/Nethermind.Api/IApiWithBlockchain.cs @@ -17,6 +17,7 @@ using Nethermind.Consensus.Scheduler; using Nethermind.Consensus.Validators; using Nethermind.Core; +using Nethermind.Core.Container; using Nethermind.Evm.TransactionProcessing; using Nethermind.Facade; using Nethermind.Facade.Eth; @@ -52,7 +53,7 @@ public interface IApiWithBlockchain : IApiWithStores, IBlockchainBridgeFactory /// /// PoS switcher for The Merge /// - IPoSSwitcher PoSSwitcher { get; set; } + IPoSSwitcher PoSSwitcher { get; } ISealer? Sealer { get; set; } ISealValidator? SealValidator { get; set; } ISealEngine SealEngine { get; set; } @@ -93,20 +94,13 @@ public interface IApiWithBlockchain : IApiWithStores, IBlockchainBridgeFactory IGasPriceOracle? GasPriceOracle { get; set; } - IEthSyncingInfo? EthSyncingInfo { get; set; } + IEthSyncingInfo? EthSyncingInfo { get; } CompositePruningTrigger PruningTrigger { get; } IBlockProductionPolicy? BlockProductionPolicy { get; set; } INodeStorageFactory NodeStorageFactory { get; set; } - BackgroundTaskScheduler BackgroundTaskScheduler { get; set; } + IBackgroundTaskScheduler 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 0b0e05e2a6d..aecf65f55ed 100644 --- a/src/Nethermind/Nethermind.Api/IApiWithNetwork.cs +++ b/src/Nethermind/Nethermind.Api/IApiWithNetwork.cs @@ -5,6 +5,7 @@ using Autofac; using Nethermind.Consensus; using Nethermind.Core; +using Nethermind.Core.Container; using Nethermind.Core.PubSub; using Nethermind.Grpc; using Nethermind.JsonRpc; @@ -26,40 +27,27 @@ public interface IApiWithNetwork : IApiWithBlockchain { (IApiWithNetwork GetFromApi, IApiWithNetwork SetInApi) ForNetwork => (this, this); - IDisconnectsAnalyzer? DisconnectsAnalyzer { get; set; } - IDiscoveryApp? DiscoveryApp { get; set; } + IDiscoveryApp? DiscoveryApp { get; } IGrpcServer? GrpcServer { get; set; } IIPResolver? IpResolver { get; set; } IMessageSerializationService MessageSerializationService { get; } IGossipPolicy GossipPolicy { get; set; } IMonitoringService MonitoringService { get; set; } - INodeStatsManager? NodeStatsManager { get; set; } - IPeerManager? PeerManager { get; set; } - IPeerPool? PeerPool { get; set; } - IProtocolsManager? ProtocolsManager { get; set; } - IProtocolValidator? ProtocolValidator { get; set; } + INodeStatsManager? NodeStatsManager { get; } + IPeerManager? PeerManager { get; } + IPeerPool? PeerPool { get; } IList Publishers { get; } - IRlpxHost? RlpxPeer { get; set; } + IRlpxHost? RlpxPeer { get; } IRpcModuleProvider? RpcModuleProvider { get; set; } IJsonRpcLocalStats? JsonRpcLocalStats { get; set; } - ISessionMonitor? SessionMonitor { get; set; } - IStaticNodesManager? StaticNodesManager { get; set; } + ISessionMonitor? SessionMonitor { get; } + IStaticNodesManager? StaticNodesManager { get; } 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; } + ISyncPeerPool? SyncPeerPool { get; } + IPeerDifficultyRefreshPool? PeerDifficultyRefreshPool { get; } + ISyncServer? SyncServer { get; } 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 eed8ed62430..207a5870e28 100644 --- a/src/Nethermind/Nethermind.Api/IApiWithStores.cs +++ b/src/Nethermind/Nethermind.Api/IApiWithStores.cs @@ -8,6 +8,7 @@ using Nethermind.Blockchain.Receipts; using Nethermind.Consensus; using Nethermind.Core; +using Nethermind.Core.Container; using Nethermind.Crypto; using Nethermind.Db.Blooms; using Nethermind.Facade.Find; @@ -26,17 +27,13 @@ public interface IApiWithStores : IBasicApi ILogFinder? LogFinder { get; set; } ISigner? EngineSigner { get; set; } ISignerStore? EngineSignerStore { get; set; } + + [ComponentKey(ComponentKey.NodeKey)] ProtectedPrivateKey? NodeKey { get; set; } IReceiptStorage? ReceiptStorage { get; set; } IReceiptFinder? ReceiptFinder { get; set; } 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 1ba0adb91f9..57749bea726 100644 --- a/src/Nethermind/Nethermind.Api/IBasicApi.cs +++ b/src/Nethermind/Nethermind.Api/IBasicApi.cs @@ -11,12 +11,14 @@ using Nethermind.Blockchain.Synchronization; using Nethermind.Config; using Nethermind.Core; +using Nethermind.Core.Container; using Nethermind.Core.Specs; using Nethermind.Core.Timers; using Nethermind.Crypto; using Nethermind.Db; using Nethermind.KeyStore; using Nethermind.Logging; +using Nethermind.Network.Config; using Nethermind.Serialization.Json; using Nethermind.Specs.ChainSpecStyle; using Nethermind.Synchronization; @@ -28,25 +30,27 @@ public interface IBasicApi DisposableStack DisposeStack { get; } IAbiEncoder AbiEncoder { get; } - ChainSpec ChainSpec { get; set; } - IConfigProvider ConfigProvider { get; set; } + ChainSpec ChainSpec { get; } + IConfigProvider ConfigProvider { get; } ICryptoRandom CryptoRandom { get; } IDbProvider? DbProvider { get; set; } IDbFactory? DbFactory { get; set; } IEthereumEcdsa? EthereumEcdsa { get; set; } - IJsonSerializer EthereumJsonSerializer { get; set; } + IJsonSerializer EthereumJsonSerializer { get; } IFileSystem FileSystem { get; set; } IKeyStore? KeyStore { get; set; } - ILogManager LogManager { get; set; } + ILogManager LogManager { get; } + [SkipServiceCollection] ProtectedPrivateKey? OriginalSignerKey { get; set; } IReadOnlyList Plugins { get; } [SkipServiceCollection] - string SealEngineType { get; set; } - ISpecProvider? SpecProvider { get; set; } - IBetterPeerStrategy? BetterPeerStrategy { get; set; } + string SealEngineType { get; } + ISpecProvider? SpecProvider { get; } + IBetterPeerStrategy? BetterPeerStrategy { get; } ITimestamper Timestamper { get; } ITimerFactory TimerFactory { get; } - IProcessExitSource? ProcessExit { get; set; } + IProcessExitSource? ProcessExit { get; } + ILifetimeScope BaseContainer { get; } public IConsensusPlugin? GetConsensusPlugin() => Plugins @@ -54,20 +58,9 @@ public interface IBasicApi .SingleOrDefault(cp => cp.SealEngineType == SealEngineType); public IEnumerable GetConsensusWrapperPlugins() => - Plugins.OfType().Where(p => p.Enabled); + Plugins.OfType().Where(p => p.ConsensusWrapperEnabled); 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 566a094eaa0..c831deb6109 100644 --- a/src/Nethermind/Nethermind.Api/NethermindApi.cs +++ b/src/Nethermind/Nethermind.Api/NethermindApi.cs @@ -58,22 +58,20 @@ using Nethermind.Sockets; using Nethermind.Trie; using Nethermind.Consensus.Processing.CensorshipDetector; +using Nethermind.Core.Container; using Nethermind.Facade.Find; namespace Nethermind.Api { public class NethermindApi : INethermindApi { - public NethermindApi(IConfigProvider configProvider, IJsonSerializer jsonSerializer, ILogManager logManager, ChainSpec chainSpec) + public NethermindApi(ILifetimeScope lifetimeScope) { - ConfigProvider = configProvider; - EthereumJsonSerializer = jsonSerializer; - LogManager = logManager; - ChainSpec = chainSpec; - CryptoRandom = new CryptoRandom(); - DisposeStack.Push(CryptoRandom); + BaseContainer = lifetimeScope; } + public ILifetimeScope BaseContainer { get; set; } + public IBlockchainBridge CreateBlockchainBridge() { ReadOnlyBlockTree readOnlyTree = BlockTree!.AsReadOnly(); @@ -124,12 +122,12 @@ public IBlockchainBridge CreateBlockchainBridge() public IBlockValidator? BlockValidator { get; set; } public IBloomStorage? BloomStorage { get; set; } public IChainLevelInfoRepository? ChainLevelInfoRepository { get; set; } - public IConfigProvider ConfigProvider { get; set; } - public ICryptoRandom CryptoRandom { get; } + public IConfigProvider ConfigProvider => BaseContainer.Resolve(); + public ICryptoRandom CryptoRandom => BaseContainer.Resolve(); public IDbProvider? DbProvider { get; set; } public IDbFactory? DbFactory { get; set; } - public IDisconnectsAnalyzer? DisconnectsAnalyzer { get; set; } - public IDiscoveryApp? DiscoveryApp { get; set; } + + public IDiscoveryApp? DiscoveryApp => BaseContainer.ResolveOptional(); public ISigner? EngineSigner { get; set; } public ISignerStore? EngineSignerStore { get; set; } public IEnode? Enode { get; set; } @@ -145,30 +143,28 @@ public IBlockchainBridge CreateBlockchainBridge() new BuildBlocksWhenRequested(); public IIPResolver? IpResolver { get; set; } - public IJsonSerializer EthereumJsonSerializer { get; set; } + public IJsonSerializer EthereumJsonSerializer => BaseContainer.Resolve(); public IKeyStore? KeyStore { get; set; } public IPasswordProvider? PasswordProvider { get; set; } public ILogFinder? LogFinder { get; set; } - public ILogManager LogManager { get; set; } + public ILogManager LogManager => BaseContainer.Resolve(); public IKeyValueStoreWithBatching? MainStateDbWithCache { get; set; } public IMessageSerializationService MessageSerializationService { get; } = new MessageSerializationService(); public IGossipPolicy GossipPolicy { get; set; } = Policy.FullGossip; public IMonitoringService MonitoringService { get; set; } = NullMonitoringService.Instance; - public INodeStatsManager? NodeStatsManager { get; set; } - public IPeerManager? PeerManager { get; set; } - public IPeerPool? PeerPool { get; set; } - public IProtocolsManager? ProtocolsManager { get; set; } - public IProtocolValidator? ProtocolValidator { get; set; } + public INodeStatsManager? NodeStatsManager => BaseContainer.ResolveOptional(); + public IPeerManager? PeerManager => BaseContainer.ResolveOptional(); + public IPeerPool? PeerPool => BaseContainer.ResolveOptional(); public IReceiptStorage? ReceiptStorage { get; set; } public IReceiptFinder? ReceiptFinder { get; set; } public IReceiptMonitor? ReceiptMonitor { get; set; } public IRewardCalculatorSource? RewardCalculatorSource { get; set; } = NoBlockRewards.Instance; - public IRlpxHost? RlpxPeer { get; set; } + public IRlpxHost? RlpxPeer => BaseContainer.ResolveOptional(); public IRpcModuleProvider? RpcModuleProvider { get; set; } = NullModuleProvider.Instance; public IRpcAuthentication? RpcAuthentication { get; set; } public IJsonRpcLocalStats? JsonRpcLocalStats { get; set; } public ISealer? Sealer { get; set; } = NullSealEngine.Instance; - public string SealEngineType { get; set; } = Nethermind.Core.SealEngineType.None; + public string SealEngineType => ChainSpec.SealEngineType; public ISealValidator? SealValidator { get; set; } = NullSealEngine.Instance; private ISealEngine? _sealEngine; public ISealEngine SealEngine @@ -184,23 +180,22 @@ public ISealEngine SealEngine } } - public ISessionMonitor? SessionMonitor { get; set; } - public ISpecProvider? SpecProvider { get; set; } - public IPoSSwitcher PoSSwitcher { get; set; } = NoPoS.Instance; - public ISyncModeSelector SyncModeSelector => ApiWithNetworkServiceContainer?.Resolve()!; - - 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 => ApiWithNetworkServiceContainer?.Resolve(); - public ISyncServer? SyncServer { get; set; } + public ISessionMonitor? SessionMonitor => BaseContainer.ResolveOptional(); + public ISpecProvider? SpecProvider => BaseContainer.Resolve(); + public IPoSSwitcher PoSSwitcher => BaseContainer.Resolve(); + public ISyncModeSelector SyncModeSelector => BaseContainer.ResolveOptional()!; + public IBetterPeerStrategy? BetterPeerStrategy => BaseContainer.ResolveOptional(); + public ISyncPeerPool? SyncPeerPool => BaseContainer.ResolveOptional(); + public IPeerDifficultyRefreshPool? PeerDifficultyRefreshPool => BaseContainer.ResolveOptional(); + public ISynchronizer? Synchronizer => BaseContainer.ResolveOptional(); + public ISyncServer? SyncServer => BaseContainer.ResolveOptional(); + + [SkipServiceCollection] public IWorldState? WorldState { get; set; } public IReadOnlyStateProvider? ChainHeadStateProvider { get; set; } public IWorldStateManager? WorldStateManager { get; set; } public IStateReader? StateReader { get; set; } - public IStaticNodesManager? StaticNodesManager { get; set; } + public IStaticNodesManager? StaticNodesManager => BaseContainer.ResolveOptional(); public ITimestamper Timestamper { get; } = Core.Timestamper.Default; public ITimerFactory TimerFactory { get; } = Core.Timers.TimerFactory.Default; public ITransactionProcessor? TransactionProcessor { get; set; } @@ -219,10 +214,10 @@ public ISealEngine SealEngine public IBlockImprovementContextFactory? BlockImprovementContextFactory { get; set; } public IGasPriceOracle? GasPriceOracle { get; set; } - public IEthSyncingInfo? EthSyncingInfo { get; set; } + public IEthSyncingInfo? EthSyncingInfo => BaseContainer.ResolveOptional(); public IBlockProductionPolicy? BlockProductionPolicy { get; set; } public INodeStorageFactory NodeStorageFactory { get; set; } = null!; - public BackgroundTaskScheduler BackgroundTaskScheduler { get; set; } = null!; + public IBackgroundTaskScheduler BackgroundTaskScheduler { get; set; } = null!; public CensorshipDetector CensorshipDetector { get; set; } = null!; public IWallet? Wallet { get; set; } public IBlockStore? BadBlocksStore { get; set; } @@ -237,14 +232,12 @@ public ISealEngine SealEngine /// public ProtectedPrivateKey? OriginalSignerKey { get; set; } - public ChainSpec ChainSpec { get; set; } + public ChainSpec ChainSpec => BaseContainer.Resolve(); public DisposableStack DisposeStack { get; } = new(); - public IReadOnlyList Plugins { get; } = new List(); + public IReadOnlyList Plugins => BaseContainer.Resolve>(); public IList Publishers { get; } = new List(); // this should be called publishers public CompositePruningTrigger PruningTrigger { get; } = new(); - public IProcessExitSource? ProcessExit { get; set; } + public IProcessExitSource? ProcessExit => BaseContainer.Resolve(); public CompositeTxGossipPolicy TxGossipPolicy { get; } = new(); - - public IContainer? ApiWithNetworkServiceContainer { get; set; } } } diff --git a/src/Nethermind/Nethermind.AuRa.Test/AuRaPluginTests.cs b/src/Nethermind/Nethermind.AuRa.Test/AuRaPluginTests.cs index 03c84f9b2b8..58be05444e2 100644 --- a/src/Nethermind/Nethermind.AuRa.Test/AuRaPluginTests.cs +++ b/src/Nethermind/Nethermind.AuRa.Test/AuRaPluginTests.cs @@ -3,10 +3,14 @@ using System; using FluentAssertions; +using Microsoft.FSharp.Core; using Nethermind.Api; using Nethermind.Config; using Nethermind.Consensus.AuRa; using Nethermind.Consensus.AuRa.InitializationSteps; +using Nethermind.Core; +using Nethermind.Core.Container; +using Nethermind.Core.Test.Builders; using Nethermind.Logging; using Nethermind.Serialization.Json; using Nethermind.Specs.ChainSpecStyle; @@ -19,10 +23,19 @@ public class AuRaPluginTests [Test] public void Init_when_not_AuRa_doesnt_trow() { - AuRaPlugin auRaPlugin = new(); - Action init = () => auRaPlugin.Init(new AuRaNethermindApi(new ConfigProvider(), new EthereumJsonSerializer(), new TestLogManager(), new ChainSpec())); + ChainSpec chainSpec = new ChainSpec() + { + SealEngineType = SealEngineType.AuRa + }; + AuRaPlugin auRaPlugin = new(chainSpec); + + NethermindApi api = Runner.Test.Ethereum.Build.ContextWithMocks(containerConfigurer: (builder) => + { + builder.AddModule(auRaPlugin.ContainerModule!); + }); + + Action init = () => auRaPlugin.Init(api); init.Should().NotThrow(); } - } } diff --git a/src/Nethermind/Nethermind.AuRa.Test/Nethermind.AuRa.Test.csproj b/src/Nethermind/Nethermind.AuRa.Test/Nethermind.AuRa.Test.csproj index aa8bb0c1427..0b0c1dd3230 100644 --- a/src/Nethermind/Nethermind.AuRa.Test/Nethermind.AuRa.Test.csproj +++ b/src/Nethermind/Nethermind.AuRa.Test/Nethermind.AuRa.Test.csproj @@ -25,6 +25,7 @@ + diff --git a/src/Nethermind/Nethermind.Consensus.AuRa/AuRaPlugin.cs b/src/Nethermind/Nethermind.Consensus.AuRa/AuRaPlugin.cs index f3c766da5f0..54060d8344b 100644 --- a/src/Nethermind/Nethermind.Consensus.AuRa/AuRaPlugin.cs +++ b/src/Nethermind/Nethermind.Consensus.AuRa/AuRaPlugin.cs @@ -3,15 +3,16 @@ using System.Runtime.CompilerServices; using System.Threading.Tasks; +using Autofac; +using Autofac.Core; using Nethermind.Api; using Nethermind.Api.Extensions; -using Nethermind.Config; using Nethermind.Consensus.AuRa.InitializationSteps; -using Nethermind.Consensus.Producers; using Nethermind.Consensus.Transactions; -using Nethermind.Logging; -using Nethermind.Serialization.Json; +using Nethermind.Core.Container; +using Nethermind.Init.Steps; using Nethermind.Specs.ChainSpecStyle; +using Nethermind.Synchronization; [assembly: InternalsVisibleTo("Nethermind.Merge.AuRa")] @@ -20,7 +21,7 @@ namespace Nethermind.Consensus.AuRa /// /// Consensus plugin for AuRa setup. /// - public class AuRaPlugin : IConsensusPlugin, ISynchronizationPlugin, IInitializationPlugin + public class AuRaPlugin(ChainSpec chainSpec) : IConsensusPlugin, ISynchronizationPlugin { private AuRaNethermindApi? _nethermindApi; public string Name => SealEngineType; @@ -30,9 +31,11 @@ public class AuRaPlugin : IConsensusPlugin, ISynchronizationPlugin, IInitializat public string Author => "Nethermind"; public string SealEngineType => Core.SealEngineType.AuRa; + public bool Enabled => chainSpec.SealEngineType == SealEngineType; private StartBlockProducerAuRa? _blockProducerStarter; + public IModule? ContainerModule => new AuraModule(); public ValueTask DisposeAsync() { @@ -51,11 +54,6 @@ public Task Init(INethermindApi nethermindApi) public Task InitSynchronization() { - if (_nethermindApi is not null) - { - _nethermindApi.BetterPeerStrategy = new AuRaBetterPeerStrategy(_nethermindApi.BetterPeerStrategy!, _nethermindApi.LogManager); - } - return Task.CompletedTask; } @@ -76,10 +74,19 @@ public IBlockProducerRunner CreateBlockProducerRunner() _nethermindApi.BlockTree, _nethermindApi.BlockProducer!); } + } - public INethermindApi CreateApi(IConfigProvider configProvider, IJsonSerializer jsonSerializer, - ILogManager logManager, ChainSpec chainSpec) => new AuRaNethermindApi(configProvider, jsonSerializer, logManager, chainSpec); + public class AuraModule : Module + { + protected override void Load(ContainerBuilder builder) + { + base.Load(builder); - public bool ShouldRunSteps(INethermindApi api) => true; + builder.RegisterDecorator(); + + builder + .AddSingleton() + .AddIStepsFromAssembly(GetType().Assembly); + } } } diff --git a/src/Nethermind/Nethermind.Consensus.AuRa/InitializationSteps/AuRaNethermindApi.cs b/src/Nethermind/Nethermind.Consensus.AuRa/InitializationSteps/AuRaNethermindApi.cs index c3822f5edd0..fab6f6b2c54 100644 --- a/src/Nethermind/Nethermind.Consensus.AuRa/InitializationSteps/AuRaNethermindApi.cs +++ b/src/Nethermind/Nethermind.Consensus.AuRa/InitializationSteps/AuRaNethermindApi.cs @@ -1,6 +1,7 @@ // SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only +using Autofac; using Nethermind.Api; using Nethermind.Blockchain; using Nethermind.Config; @@ -20,8 +21,7 @@ namespace Nethermind.Consensus.AuRa.InitializationSteps { public class AuRaNethermindApi : NethermindApi { - public AuRaNethermindApi(IConfigProvider configProvider, IJsonSerializer jsonSerializer, ILogManager logManager, ChainSpec chainSpec) - : base(configProvider, jsonSerializer, logManager, chainSpec) + public AuRaNethermindApi(ILifetimeScope lifetimeScope) : base(lifetimeScope) { } diff --git a/src/Nethermind/Nethermind.Consensus.Clique/CliquePlugin.cs b/src/Nethermind/Nethermind.Consensus.Clique/CliquePlugin.cs index 9167e80f900..12c46a8ba91 100644 --- a/src/Nethermind/Nethermind.Consensus.Clique/CliquePlugin.cs +++ b/src/Nethermind/Nethermind.Consensus.Clique/CliquePlugin.cs @@ -21,11 +21,12 @@ using Nethermind.Db; using Nethermind.Evm.TransactionProcessing; using Nethermind.JsonRpc.Modules; +using Nethermind.Specs.ChainSpecStyle; using Nethermind.State; namespace Nethermind.Consensus.Clique { - public class CliquePlugin : IConsensusPlugin + public class CliquePlugin(ChainSpec chainSpec) : IConsensusPlugin { public string Name => "Clique"; @@ -33,6 +34,8 @@ public class CliquePlugin : IConsensusPlugin public string Author => "Nethermind"; + public bool Enabled => chainSpec.SealEngineType == SealEngineType; + public Task Init(INethermindApi nethermindApi) { _nethermindApi = nethermindApi; diff --git a/src/Nethermind/Nethermind.Consensus.Ethash/EthashPlugin.cs b/src/Nethermind/Nethermind.Consensus.Ethash/EthashPlugin.cs index dae39105746..ffbad929907 100644 --- a/src/Nethermind/Nethermind.Consensus.Ethash/EthashPlugin.cs +++ b/src/Nethermind/Nethermind.Consensus.Ethash/EthashPlugin.cs @@ -7,10 +7,11 @@ using Nethermind.Consensus.Producers; using Nethermind.Consensus.Rewards; using Nethermind.Consensus.Transactions; +using Nethermind.Specs.ChainSpecStyle; namespace Nethermind.Consensus.Ethash { - public class EthashPlugin : IConsensusPlugin + public class EthashPlugin(ChainSpec chainSpec) : IConsensusPlugin { private INethermindApi _nethermindApi; @@ -22,6 +23,8 @@ public class EthashPlugin : IConsensusPlugin public string Author => "Nethermind"; + public bool Enabled => chainSpec.SealEngineType == SealEngineType; + public Task Init(INethermindApi nethermindApi) { _nethermindApi = nethermindApi; diff --git a/src/Nethermind/Nethermind.Consensus.Ethash/NethDevPlugin.cs b/src/Nethermind/Nethermind.Consensus.Ethash/NethDevPlugin.cs index 215ae44e976..5ab25818e4b 100644 --- a/src/Nethermind/Nethermind.Consensus.Ethash/NethDevPlugin.cs +++ b/src/Nethermind/Nethermind.Consensus.Ethash/NethDevPlugin.cs @@ -18,11 +18,12 @@ using Nethermind.Db; using Nethermind.Evm.TransactionProcessing; using Nethermind.Logging; +using Nethermind.Specs.ChainSpecStyle; using Nethermind.State; namespace Nethermind.Consensus.Ethash { - public class NethDevPlugin : IConsensusPlugin + public class NethDevPlugin(ChainSpec chainSpec) : IConsensusPlugin { private INethermindApi? _nethermindApi; @@ -40,6 +41,8 @@ public Task Init(INethermindApi nethermindApi) return Task.CompletedTask; } + public bool Enabled => chainSpec.SealEngineType == SealEngineType; + public IBlockProducer InitBlockProducer(ITxSource? additionalTxSource = null) { if (_nethermindApi!.SealEngineType != Nethermind.Core.SealEngineType.NethDev) diff --git a/src/Nethermind/Nethermind.Core.Test/Blockchain/TestBlockchain.cs b/src/Nethermind/Nethermind.Core.Test/Blockchain/TestBlockchain.cs index 2af6892ee13..cda827eb468 100644 --- a/src/Nethermind/Nethermind.Core.Test/Blockchain/TestBlockchain.cs +++ b/src/Nethermind/Nethermind.Core.Test/Blockchain/TestBlockchain.cs @@ -5,6 +5,8 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using Autofac; +using Nethermind.Api; using Nethermind.Blockchain; using Nethermind.Blockchain.BeaconBlockRoot; using Nethermind.Blockchain.Blocks; @@ -21,6 +23,7 @@ using Nethermind.Consensus.Rewards; using Nethermind.Consensus.Transactions; using Nethermind.Consensus.Validators; +using Nethermind.Core.Container; using Nethermind.Core.Crypto; using Nethermind.Core.Extensions; using Nethermind.Core.Specs; @@ -33,6 +36,7 @@ using Nethermind.Facade.Find; using Nethermind.Int256; using Nethermind.Logging; +using Nethermind.Runner.Modules; using Nethermind.Serialization.Json; using Nethermind.Specs; using Nethermind.Specs.Test; @@ -127,11 +131,18 @@ protected TestBlockchain() private PreBlockCaches PreBlockCaches { get; } = new(); + protected IContainer Container { get; private set; } = null!; + protected virtual async Task Build(ISpecProvider? specProvider = null, UInt256? initialValues = null, bool addBlockOnStart = true) { Timestamper = new ManualTimestamper(new DateTime(2020, 2, 15, 12, 50, 30, DateTimeKind.Utc)); JsonSerializer = new EthereumJsonSerializer(); SpecProvider = CreateSpecProvider(specProvider ?? MainnetSpecProvider.Instance); + + ContainerBuilder builder = new ContainerBuilder(); + ConfigureContainer(builder); + Container = builder.Build(); + EthereumEcdsa = new EthereumEcdsa(SpecProvider.ChainId); DbProvider = await CreateDbProvider(); TrieStore = new TrieStore(StateDb, LogManager); @@ -250,6 +261,16 @@ protected virtual async Task Build(ISpecProvider? specProvider = return this; } + protected virtual void ConfigureContainer(ContainerBuilder builder) + { + builder + .AddModule(new BaseModule()) + .AddModule(new CoreModule()) + .AddInstance(SpecProvider) + .AddInstance(LogManager) + .AddInstance(new ConfigProvider()); + } + private static ISpecProvider CreateSpecProvider(ISpecProvider specProvider) { return specProvider is TestSpecProvider { AllowTestChainOverride: false } diff --git a/src/Nethermind/Nethermind.Core.Test/ContainerBuilderExtensionsTests.cs b/src/Nethermind/Nethermind.Core.Test/Container/ContainerBuilderExtensionsTests.cs similarity index 83% rename from src/Nethermind/Nethermind.Core.Test/ContainerBuilderExtensionsTests.cs rename to src/Nethermind/Nethermind.Core.Test/Container/ContainerBuilderExtensionsTests.cs index 28e890c8499..0c0e6aff644 100644 --- a/src/Nethermind/Nethermind.Core.Test/ContainerBuilderExtensionsTests.cs +++ b/src/Nethermind/Nethermind.Core.Test/Container/ContainerBuilderExtensionsTests.cs @@ -4,26 +4,13 @@ using System; using Autofac; using FluentAssertions; +using Nethermind.Core.Container; using NUnit.Framework; -namespace Nethermind.Core.Test; +namespace Nethermind.Core.Test.Container; 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() { @@ -79,6 +66,7 @@ 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 KeyedBaseService { get; set; } = new DeclaredInBase(); public DeclaredInBase BaseService { get; set; } = new DeclaredInBase(); } @@ -89,6 +77,9 @@ private interface ITestInterface : ITestInterfaceBase [SkipServiceCollection] Ignored IgnoredService { get; set; } + + [ComponentKey(ComponentKey.NodeKey)] + public DeclaredInBase KeyedBaseService { get; set; } } private interface ITestInterfaceBase diff --git a/src/Nethermind/Nethermind.Core.Test/Container/FallbackToFieldFromApiTests.cs b/src/Nethermind/Nethermind.Core.Test/Container/FallbackToFieldFromApiTests.cs new file mode 100644 index 00000000000..15e0c5b0df6 --- /dev/null +++ b/src/Nethermind/Nethermind.Core.Test/Container/FallbackToFieldFromApiTests.cs @@ -0,0 +1,81 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using System; +using Autofac; +using Autofac.Core; +using FluentAssertions; +using Nethermind.Core.Container; +using Nethermind.Core.Exceptions; +using NUnit.Framework; + +namespace Nethermind.Core.Test.Container; + +public class FallbackToFieldFromApiTests +{ + + [Test] + public void CanResolveFieldWithTypeWhenSetLater() + { + ContainerBuilder containerBuilder = new ContainerBuilder(); + containerBuilder.AddSingleton(); + containerBuilder.RegisterSource(new FallbackToFieldFromApi()); + + IContainer container = containerBuilder.Build(); + + Action act = (() => container.Resolve()); + act.Should().Throw(); + + container.Resolve().TargetService = new TargetService(); + container.Resolve().Should().NotBeNull(); + } + + [Test] + public void CanResolveFieldWithKey() + { + ContainerBuilder containerBuilder = new ContainerBuilder(); + containerBuilder.AddSingleton(); + containerBuilder.RegisterSource(new FallbackToFieldFromApi()); + + IContainer container = containerBuilder.Build(); + container.Resolve().NamedTargetService = new NamedTargetService(); + container.TryResolve(out NamedTargetService? _).Should().BeFalse(); + container.TryResolveKeyed(ComponentKey.NodeKey, out NamedTargetService? _).Should().BeFalse(); + } + + [Test] + public void ThrowExceptionIfTargetIsAlsoRegisterec() + { + ContainerBuilder containerBuilder = new ContainerBuilder(); + containerBuilder.AddSingleton(); + containerBuilder.AddSingleton(); + containerBuilder.RegisterSource(new FallbackToFieldFromApi()); + + IContainer container = containerBuilder.Build(); + + Action act = (() => container.Resolve()); + act.Should().Throw(); + } + + public interface IApi + { + [ComponentKey(ComponentKey.NodeKey)] + public NamedTargetService NamedTargetService { get; set; } + public TargetService TargetService { get; set; } + } + + public class Api : IApi + { + public NamedTargetService NamedTargetService { get; set; } = null!; + public TargetService TargetService { get; set; } = null!; + } + + public class TargetService + { + } + + public class NamedTargetService + { + } + +} diff --git a/src/Nethermind/Nethermind.Core.Test/Nethermind.Core.Test.csproj b/src/Nethermind/Nethermind.Core.Test/Nethermind.Core.Test.csproj index d277beb757b..acdc0dad54a 100644 --- a/src/Nethermind/Nethermind.Core.Test/Nethermind.Core.Test.csproj +++ b/src/Nethermind/Nethermind.Core.Test/Nethermind.Core.Test.csproj @@ -24,6 +24,7 @@ + diff --git a/src/Nethermind/Nethermind.Core/Container/ComponentKeys.cs b/src/Nethermind/Nethermind.Core/Container/ComponentKeys.cs new file mode 100644 index 00000000000..d638583c40b --- /dev/null +++ b/src/Nethermind/Nethermind.Core/Container/ComponentKeys.cs @@ -0,0 +1,16 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using System; + +namespace Nethermind.Core.Container; + +public enum ComponentKey +{ + NodeKey +} + +public class ComponentKeyAttribute(ComponentKey key) : Attribute +{ + public ComponentKey Key { get; } = key; +} diff --git a/src/Nethermind/Nethermind.Core/ContainerBuilderExtensions.cs b/src/Nethermind/Nethermind.Core/Container/ContainerBuilderExtensions.cs similarity index 70% rename from src/Nethermind/Nethermind.Core/ContainerBuilderExtensions.cs rename to src/Nethermind/Nethermind.Core/Container/ContainerBuilderExtensions.cs index 1c30a830b55..57d783f1f2e 100644 --- a/src/Nethermind/Nethermind.Core/ContainerBuilderExtensions.cs +++ b/src/Nethermind/Nethermind.Core/Container/ContainerBuilderExtensions.cs @@ -6,40 +6,13 @@ using System.Linq; using System.Reflection; using Autofac; +using Autofac.Core; using Autofac.Features.AttributeFilters; -namespace Nethermind.Core; +namespace Nethermind.Core.Container; 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() @@ -50,7 +23,7 @@ public static ContainerBuilder AddSingleton(this ContainerBuilder builder) wh return builder; } - public static ContainerBuilder AddSingleton(this ContainerBuilder builder, T instance) where T : class + public static ContainerBuilder AddInstance(this ContainerBuilder builder, T instance) where T : class { builder.RegisterInstance(instance) .As() @@ -115,6 +88,25 @@ public static ContainerBuilder RegisterNamedComponentInItsOwnLifetime(this Co return builder; } + + public static ContainerBuilder AddModule(this ContainerBuilder builder, IModule module) + { + builder.RegisterModule(module); + + return builder; + } + + /// + /// Shorthand for registering a constructor that resolve TImpl as TAs. + /// This is useful for clarity or for conditional registration where TImpl is declared somewhere else. + /// + public static ContainerBuilder Bind(this ContainerBuilder builder) where TImpl : notnull where TAs : notnull + { + builder.Register(ctx => ctx.Resolve()) + .As(); + + return builder; + } } /// diff --git a/src/Nethermind/Nethermind.Core/Container/FallbackToFieldFromApi.cs b/src/Nethermind/Nethermind.Core/Container/FallbackToFieldFromApi.cs new file mode 100644 index 00000000000..db45b2dea32 --- /dev/null +++ b/src/Nethermind/Nethermind.Core/Container/FallbackToFieldFromApi.cs @@ -0,0 +1,109 @@ +// 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.Builder; +using Autofac.Core; +using Nethermind.Core.Exceptions; + +namespace Nethermind.Core.Container; + +/// +/// If a service does not have any registration, try to get it from a member fo a type `T`. +/// This allow fetching of unregistered/unconfigured component from `NethermindApi`. +/// +public class FallbackToFieldFromApi : IRegistrationSource where TApi : notnull +{ + private readonly Dictionary _availableTypes; + + public FallbackToFieldFromApi() + { + Type tApi = typeof(TApi); + + IEnumerable properties = tApi + .GetInterfaces() + .SelectMany(i => i.GetProperties(BindingFlags.GetProperty | BindingFlags.Instance | BindingFlags.Public)) + .Where(p => p.GetCustomAttribute() == null); + + Dictionary availableTypes = new Dictionary(); + + foreach (PropertyInfo propertyInfo in properties) + { + availableTypes[propertyInfo.PropertyType] = propertyInfo; + } + + _availableTypes = availableTypes; + } + + public IEnumerable RegistrationsFor(Service service, Func> registrationAccessor) + { + if (registrationAccessor == null) + { + throw new ArgumentNullException(nameof(registrationAccessor)); + } + + IServiceWithType? ts = service as IServiceWithType; + if (ts == null || ts.ServiceType == typeof(string)) + { + return Enumerable.Empty(); + } + + PropertyInfo? property; + Type serviceType = ts.ServiceType; + if (registrationAccessor(service).Any()) + { + // Already have registration + if (_availableTypes.TryGetValue(serviceType, out property) && property.SetMethod != null) + { + // To prevent mistake, a service that already have registration via dependency injection must not also + // have a setter in api. This is to prevent the assumption that the setter will caause the service + // to be reflected in dependency injected components. It will not. Please remove the setter from the + // api. + throw new InvalidConfigurationException($"Service {serviceType} has both container registration and mutable field in {typeof(TApi).Name}", -1); + } + + return Enumerable.Empty(); + } + + if (!_availableTypes.TryGetValue(serviceType, out property)) + { + // Not available as a property + return Enumerable.Empty(); + } + + ComponentKeyAttribute? keyAttribute = property.GetCustomAttribute(); + if (keyAttribute is not null) + { + if (ts is not KeyedService keyedService) + { + // not a keyed service + return Enumerable.Empty(); + } + + if (!keyedService.ServiceKey.Equals(keyAttribute.Key)) + { + // Different key + return Enumerable.Empty(); + } + } + + IRegistrationBuilder builder = RegistrationBuilder.ForDelegate(serviceType, (ctx, reg) => + { + TApi baseT = ctx.Resolve(); + return property.GetValue(baseT)!; + }); + + if (keyAttribute is not null) + { + return new[] { builder.Keyed(keyAttribute.Key, serviceType).CreateRegistration() }; + } + + return new[] { builder.CreateRegistration() }; + } + + public bool IsAdapterForIndividualComponents => false; +} diff --git a/src/Nethermind/Nethermind.Db/IDbProvider.cs b/src/Nethermind/Nethermind.Db/IDbProvider.cs index 6a0380b0446..8a4ce4a82bb 100644 --- a/src/Nethermind/Nethermind.Db/IDbProvider.cs +++ b/src/Nethermind/Nethermind.Db/IDbProvider.cs @@ -6,6 +6,7 @@ using Autofac; using Microsoft.Extensions.DependencyInjection; using Nethermind.Core; +using Nethermind.Core.Container; namespace Nethermind.Db { @@ -34,33 +35,5 @@ public interface IDbProvider : IDisposable 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.EthStats.Test/EthStatsPluginTests.cs b/src/Nethermind/Nethermind.EthStats.Test/EthStatsPluginTests.cs index e0fffd67b31..3ec5c01fd2e 100644 --- a/src/Nethermind/Nethermind.EthStats.Test/EthStatsPluginTests.cs +++ b/src/Nethermind/Nethermind.EthStats.Test/EthStatsPluginTests.cs @@ -11,7 +11,6 @@ namespace Nethermind.EthStats.Test; public class EthStatsPluginTests { - public IEthStatsConfig StatsConfig { get; private set; } = null!; private NethermindApi _context = null!; #pragma warning disable NUnit1032 private INethermindPlugin _plugin = null!; @@ -21,7 +20,7 @@ public class EthStatsPluginTests public void Setup() { _context = Build.ContextWithMocks(); - _plugin = new EthStatsPlugin(); + _plugin = new EthStatsPlugin(new EthStatsConfig() { Enabled = true }); } [TearDown] @@ -31,7 +30,6 @@ public void Setup() [TestCase(false)] public void Init_eth_stats_plugin_does_not_throw_exception(bool enabled) { - StatsConfig = new EthStatsConfig() { Enabled = enabled }; Assert.DoesNotThrow(() => _plugin.InitTxTypesAndRlpDecoders(_context)); Assert.DoesNotThrowAsync(async () => await _plugin.Init(_context)); Assert.DoesNotThrowAsync(async () => await _plugin.InitNetworkProtocol()); diff --git a/src/Nethermind/Nethermind.EthStats/EthStatsPlugin.cs b/src/Nethermind/Nethermind.EthStats/EthStatsPlugin.cs index b57e083dbe6..1efc571334f 100644 --- a/src/Nethermind/Nethermind.EthStats/EthStatsPlugin.cs +++ b/src/Nethermind/Nethermind.EthStats/EthStatsPlugin.cs @@ -18,9 +18,8 @@ namespace Nethermind.EthStats; -public class EthStatsPlugin : INethermindPlugin +public class EthStatsPlugin(IEthStatsConfig ethStatsConfig) : INethermindPlugin { - private IEthStatsConfig _ethStatsConfig = null!; private IEthStatsClient _ethStatsClient = null!; private IEthStatsIntegration _ethStatsIntegration = null!; private INethermindApi _api = null!; @@ -31,6 +30,7 @@ public class EthStatsPlugin : INethermindPlugin public string Name => "EthStats"; public string Description => "Ethereum Statistics"; public string Author => "Nethermind"; + public bool Enabled => ethStatsConfig.Enabled; public ValueTask DisposeAsync() { @@ -42,10 +42,10 @@ public Task Init(INethermindApi nethermindApi) { _api = nethermindApi; var (getFromAPi, _) = _api.ForInit; - _ethStatsConfig = getFromAPi.Config(); + ethStatsConfig = getFromAPi.Config(); IInitConfig initConfig = getFromAPi.Config(); - _isOn = _ethStatsConfig.Enabled; + _isOn = ethStatsConfig.Enabled; _logger = getFromAPi.LogManager.GetClassLogger(); if (!_isOn) @@ -72,10 +72,10 @@ public async Task InitNetworkProtocol() if (_isOn) { - string instanceId = $"{_ethStatsConfig.Name}-{Keccak.Compute(getFromAPi.Enode!.Info)}"; + string instanceId = $"{ethStatsConfig.Name}-{Keccak.Compute(getFromAPi.Enode!.Info)}"; if (_logger.IsInfo) { - _logger.Info($"Initializing ETH Stats for the instance: {instanceId}, server: {_ethStatsConfig.Server}"); + _logger.Info($"Initializing ETH Stats for the instance: {instanceId}, server: {ethStatsConfig.Server}"); } MessageSender sender = new(instanceId, _api.LogManager); const int reconnectionInterval = 5000; @@ -88,22 +88,22 @@ public async Task InitNetworkProtocol() string protocol = $"{P2PProtocolInfoProvider.DefaultCapabilitiesToString()}"; _ethStatsClient = new EthStatsClient( - _ethStatsConfig.Server, + ethStatsConfig.Server, reconnectionInterval, sender, _api.LogManager); _ethStatsIntegration = new EthStatsIntegration( - _ethStatsConfig.Name!, + ethStatsConfig.Name!, node, port, network, protocol, api, client, - _ethStatsConfig.Contact!, + ethStatsConfig.Contact!, canUpdateHistory, - _ethStatsConfig.Secret!, + ethStatsConfig.Secret!, _ethStatsClient, sender, getFromAPi.TxPool!, @@ -112,7 +112,7 @@ public async Task InitNetworkProtocol() getFromAPi.GasPriceOracle!, getFromAPi.EthSyncingInfo!, initConfig.IsMining, - TimeSpan.FromSeconds(_ethStatsConfig.SendInterval), + TimeSpan.FromSeconds(ethStatsConfig.SendInterval), getFromAPi.LogManager); await _ethStatsIntegration.InitAsync(); diff --git a/src/Nethermind/Nethermind.ExternalSigner.Plugin/ClefSignerPlugin.cs b/src/Nethermind/Nethermind.ExternalSigner.Plugin/ClefSignerPlugin.cs index 9c96f175d1b..c1f004defc3 100644 --- a/src/Nethermind/Nethermind.ExternalSigner.Plugin/ClefSignerPlugin.cs +++ b/src/Nethermind/Nethermind.ExternalSigner.Plugin/ClefSignerPlugin.cs @@ -22,6 +22,7 @@ public class ClefSignerPlugin : INethermindPlugin public string Description => "Enabled signing from a remote Clef instance over Json RPC."; public string Author => "Nethermind"; + public bool Enabled => true; public ValueTask DisposeAsync() => ValueTask.CompletedTask; diff --git a/src/Nethermind/Nethermind.HealthChecks.Test/NodeHealthServiceTests.cs b/src/Nethermind/Nethermind.HealthChecks.Test/NodeHealthServiceTests.cs index 92d9b5bce85..4975d3788fb 100644 --- a/src/Nethermind/Nethermind.HealthChecks.Test/NodeHealthServiceTests.cs +++ b/src/Nethermind/Nethermind.HealthChecks.Test/NodeHealthServiceTests.cs @@ -42,7 +42,7 @@ public void CheckHealth_returns_expected_results([ValueSource(nameof(CheckHealth ISyncConfig syncConfig = Substitute.For(); IHealthHintService healthHintService = Substitute.For(); INethermindApi api = Substitute.For(); - api.SpecProvider = Substitute.For(); + api.SpecProvider.Returns(Substitute.For()); blockchainProcessor.IsProcessingBlocks(Arg.Any()).Returns(test.IsProcessingBlocks); blockProducerRunner.IsProducingBlocks(Arg.Any()).Returns(test.IsProducingBlocks); syncServer.GetPeerCount().Returns(test.PeerCount); @@ -113,7 +113,7 @@ public void post_merge_health_checks([ValueSource(nameof(CheckHealthPostMergeTes drive.TotalSize.Returns((long)(_freeSpaceBytes * 100.0 / test.AvailableDiskSpacePercent)); drive.RootDirectory.FullName.Returns("C:/"); - api.SpecProvider = Substitute.For(); + api.SpecProvider.Returns(Substitute.For()); api.SpecProvider.TerminalTotalDifficulty.Returns(UInt256.Zero); BlockHeaderBuilder GetBlockHeader(int blockNumber) => Build.A.BlockHeader.WithNumber(blockNumber); diff --git a/src/Nethermind/Nethermind.HealthChecks/HealthChecksPlugin.cs b/src/Nethermind/Nethermind.HealthChecks/HealthChecksPlugin.cs index e56363a30e3..8021c7dc676 100644 --- a/src/Nethermind/Nethermind.HealthChecks/HealthChecksPlugin.cs +++ b/src/Nethermind/Nethermind.HealthChecks/HealthChecksPlugin.cs @@ -53,6 +53,7 @@ public async ValueTask DisposeAsync() public string Author => "Nethermind"; public bool MustInitialize => true; + public bool Enabled => true; public FreeDiskSpaceChecker FreeDiskSpaceChecker => LazyInitializer.EnsureInitialized(ref _freeDiskSpaceChecker, () => new FreeDiskSpaceChecker( diff --git a/src/Nethermind/Nethermind.Hive.Test/HivePluginTests.cs b/src/Nethermind/Nethermind.Hive.Test/HivePluginTests.cs index 4b390a0a188..322915ba8ea 100644 --- a/src/Nethermind/Nethermind.Hive.Test/HivePluginTests.cs +++ b/src/Nethermind/Nethermind.Hive.Test/HivePluginTests.cs @@ -11,20 +11,20 @@ public class HivePluginTests [Test] public void Can_create() { - _ = new HivePlugin(); + _ = new HivePlugin(new HiveConfig() { Enabled = true }); } [Test] public void Throws_on_null_api_in_init() { - HivePlugin plugin = new(); + HivePlugin plugin = new(new HiveConfig() { Enabled = true }); Assert.Throws(() => plugin.Init(null)); } [Test] public void Can_initialize() { - HivePlugin plugin = new(); + HivePlugin plugin = new(new HiveConfig() { Enabled = true }); plugin.Init(Runner.Test.Ethereum.Build.ContextWithMocks()); plugin.InitRpcModules(); } diff --git a/src/Nethermind/Nethermind.Hive/HivePlugin.cs b/src/Nethermind/Nethermind.Hive/HivePlugin.cs index 62aaef0a766..d2818d8d3f8 100644 --- a/src/Nethermind/Nethermind.Hive/HivePlugin.cs +++ b/src/Nethermind/Nethermind.Hive/HivePlugin.cs @@ -10,12 +10,12 @@ namespace Nethermind.Hive { - public class HivePlugin : INethermindPlugin + public class HivePlugin(IHiveConfig hiveConfig) : INethermindPlugin { private INethermindApi _api = null!; - private IHiveConfig _hiveConfig = null!; private ILogger _logger; private readonly CancellationTokenSource _disposeCancellationToken = new(); + public bool Enabled => Environment.GetEnvironmentVariable("NETHERMIND_HIVE_ENABLED")?.ToLowerInvariant() == "true" || hiveConfig.Enabled; public ValueTask DisposeAsync() { @@ -33,11 +33,8 @@ public ValueTask DisposeAsync() public Task Init(INethermindApi api) { _api = api ?? throw new ArgumentNullException(nameof(api)); - _hiveConfig = _api.ConfigProvider.GetConfig(); _logger = _api.LogManager.GetClassLogger(); - Enabled = Environment.GetEnvironmentVariable("NETHERMIND_HIVE_ENABLED")?.ToLowerInvariant() == "true" || _hiveConfig.Enabled; - return Task.CompletedTask; } @@ -73,7 +70,5 @@ public Task InitRpcModules() { return Task.CompletedTask; } - - private bool Enabled { get; set; } } } diff --git a/src/Nethermind/Nethermind.Init.Snapshot/SnapshotPlugin.cs b/src/Nethermind/Nethermind.Init.Snapshot/SnapshotPlugin.cs index 52449d70f0b..9e024c2757d 100644 --- a/src/Nethermind/Nethermind.Init.Snapshot/SnapshotPlugin.cs +++ b/src/Nethermind/Nethermind.Init.Snapshot/SnapshotPlugin.cs @@ -1,9 +1,12 @@ +using Autofac; +using Autofac.Core; using Nethermind.Api; using Nethermind.Api.Extensions; +using Nethermind.Init.Steps; namespace Nethermind.Init.Snapshot; -public class SnapshotPlugin : IInitializationPlugin +public class SnapshotPlugin(ISnapshotConfig snapshotConfig) : INethermindPlugin { public string Name => "Snapshot"; @@ -15,8 +18,19 @@ public class SnapshotPlugin : IInitializationPlugin public Task InitNetworkProtocol() => Task.CompletedTask; public Task InitRpcModules() => Task.CompletedTask; - public bool ShouldRunSteps(INethermindApi api) => - api.Config() is { Enabled: true, DownloadUrl: not null }; + public bool Enabled => + snapshotConfig is { Enabled: true, DownloadUrl: not null }; + + public IModule? ContainerModule => new SnapshotPluginModule(); public ValueTask DisposeAsync() => ValueTask.CompletedTask; + + private class SnapshotPluginModule : Module + { + protected override void Load(ContainerBuilder builder) + { + base.Load(builder); + builder.AddIStepsFromAssembly(GetType().Assembly); + } + } } diff --git a/src/Nethermind/Nethermind.Init/Steps/EthereumStepsLoader.cs b/src/Nethermind/Nethermind.Init/Steps/EthereumStepsLoader.cs index 1fb0ac15acf..9d63bc23be9 100644 --- a/src/Nethermind/Nethermind.Init/Steps/EthereumStepsLoader.cs +++ b/src/Nethermind/Nethermind.Init/Steps/EthereumStepsLoader.cs @@ -4,83 +4,47 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Reflection; -using Nethermind.Api; namespace Nethermind.Init.Steps { public class EthereumStepsLoader : IEthereumStepsLoader { - private readonly IEnumerable _stepsAssemblies; - private readonly Type _baseApiType = typeof(INethermindApi); + private readonly IReadOnlyList _steps; - public EthereumStepsLoader(params Assembly[] stepsAssemblies) - : this((IEnumerable)stepsAssemblies) { } - - public EthereumStepsLoader(IEnumerable stepsAssemblies) + public EthereumStepsLoader(IReadOnlyList steps) { - _stepsAssemblies = stepsAssemblies; + _steps = steps; } - public IEnumerable LoadSteps(Type apiType) + public IEnumerable LoadSteps() { - if (!apiType.GetInterfaces().Contains(_baseApiType)) - { - throw new NotSupportedException($"api type must implement {_baseApiType.Name}"); - } - - List allStepTypes = new List(); - foreach (Assembly stepsAssembly in _stepsAssemblies) - { - allStepTypes.AddRange(stepsAssembly.GetExportedTypes() - .Where(t => !t.IsInterface && !t.IsAbstract && IsStepType(t))); - } - - return allStepTypes - .Select(s => new StepInfo(s, GetStepBaseType(s))) + return _steps .GroupBy(s => s.StepBaseType) - .Select(g => SelectImplementation(g.ToArray(), apiType)) + .Select(g => SelectImplementation(g.ToArray(), g.Key)) .Where(s => s is not null) .Select(s => s!); } - private static bool HasConstructorWithParameter(Type type, Type parameterType) + private StepInfo? SelectImplementation(StepInfo[] stepsWithTheSameBase, Type baseType) { - Type[] expectedParams = { parameterType }; - return type.GetConstructors().Any( - c => c.GetParameters().Select(p => p.ParameterType).SequenceEqual(expectedParams)); - } - - private StepInfo? SelectImplementation(StepInfo[] stepsWithTheSameBase, Type apiType) - { - StepInfo[] stepsWithMatchingApiType = stepsWithTheSameBase - .Where(t => HasConstructorWithParameter(t.StepType, apiType)).ToArray(); - - if (stepsWithMatchingApiType.Length == 0) + // In case of multiple step declaration, make sure that there is one final step that is the most specific + // implementation. + StepInfo[] stepWithNoParent = stepsWithTheSameBase.Where((currentStep) => { - // base API type this time - stepsWithMatchingApiType = stepsWithTheSameBase - .Where(t => HasConstructorWithParameter(t.StepType, _baseApiType)).ToArray(); - } + return !stepsWithTheSameBase.Any(otherStep => + otherStep != currentStep && currentStep.StepType.IsAssignableFrom(otherStep.StepType)); + }).ToArray(); - if (stepsWithMatchingApiType.Length > 1) + if (stepWithNoParent.Length != 1) { - Array.Sort(stepsWithMatchingApiType, (t1, t2) => t1.StepType.IsAssignableFrom(t2.StepType) ? 1 : -1); + throw new InvalidOperationException( + $"Unable to find unique step for group {baseType.FullName}. Current steps: {stepWithNoParent}"); } - return stepsWithMatchingApiType.FirstOrDefault(); + return stepWithNoParent[0]; } private static bool IsStepType(Type t) => typeof(IStep).IsAssignableFrom(t); - private static Type GetStepBaseType(Type type) - { - while (type.BaseType is not null && IsStepType(type.BaseType)) - { - type = type.BaseType; - } - - return type; - } } } diff --git a/src/Nethermind/Nethermind.Init/Steps/EthereumStepsManager.cs b/src/Nethermind/Nethermind.Init/Steps/EthereumStepsManager.cs index 337729eb705..903cea88893 100644 --- a/src/Nethermind/Nethermind.Init/Steps/EthereumStepsManager.cs +++ b/src/Nethermind/Nethermind.Init/Steps/EthereumStepsManager.cs @@ -9,6 +9,7 @@ using System.Runtime.ExceptionServices; using System.Threading; using System.Threading.Tasks; +using Autofac; using Nethermind.Api; using Nethermind.Core.Extensions; using Nethermind.Logging; @@ -20,22 +21,19 @@ public class EthereumStepsManager private readonly ILogger _logger; private readonly AutoResetEvent _autoResetEvent = new AutoResetEvent(true); - private readonly INethermindApi _api; + private readonly ILifetimeScope _container; private readonly List _allSteps; private readonly Dictionary _allStepsByBaseType; public EthereumStepsManager( IEthereumStepsLoader loader, - INethermindApi context, - ILogManager logManager) + ILifetimeScope container, + ILogger logger) { - ArgumentNullException.ThrowIfNull(loader); + _container = container; + _logger = logger; - _api = context ?? throw new ArgumentNullException(nameof(context)); - _logger = logManager?.GetClassLogger() - ?? throw new ArgumentNullException(nameof(logManager)); - - _allSteps = loader.LoadSteps(_api.GetType()).ToList(); + _allSteps = loader.LoadSteps().ToList(); _allStepsByBaseType = _allSteps.ToDictionary(s => s.StepBaseType, s => s); } @@ -147,14 +145,14 @@ private void RunOneRoundOfInitialization(CancellationToken cancellationToken) private async Task ExecuteStep(IStep step, StepInfo stepInfo, CancellationToken cancellationToken) { - long startTime = Stopwatch.GetTimestamp(); + Stopwatch stopwatch = Stopwatch.StartNew(); try { await step.Execute(cancellationToken); if (_logger.IsDebug) _logger.Debug( - $"Step {step.GetType().Name.PadRight(24)} executed in {Stopwatch.GetElapsedTime(startTime).TotalMilliseconds:N0}ms"); + $"Step {step.GetType().Name.PadRight(24)} executed in {stopwatch.ElapsedMilliseconds}ms"); stepInfo.Stage = StepInitializationStage.Complete; } @@ -164,7 +162,7 @@ private async Task ExecuteStep(IStep step, StepInfo stepInfo, CancellationToken { if (_logger.IsError) _logger.Error( - $"Step {step.GetType().Name.PadRight(24)} failed after {Stopwatch.GetElapsedTime(startTime).TotalMilliseconds:N0}ms", + $"Step {step.GetType().Name.PadRight(24)} failed after {stopwatch.ElapsedMilliseconds}ms", exception); stepInfo.Stage = StepInitializationStage.Failed; @@ -174,12 +172,13 @@ private async Task ExecuteStep(IStep step, StepInfo stepInfo, CancellationToken if (_logger.IsWarn) { _logger.Warn( - $"Step {step.GetType().Name.PadRight(24)} failed after {Stopwatch.GetElapsedTime(startTime).TotalMilliseconds:N0}ms {exception}"); + $"Step {step.GetType().Name.PadRight(24)} failed after {stopwatch.ElapsedMilliseconds}ms {exception}"); } stepInfo.Stage = StepInitializationStage.Complete; } finally { + stopwatch.Stop(); _autoResetEvent.Set(); if (_logger.IsDebug) _logger.Debug($"{step.GetType().Name.PadRight(24)} complete"); @@ -191,7 +190,7 @@ private async Task ExecuteStep(IStep step, StepInfo stepInfo, CancellationToken IStep? step = null; try { - step = Activator.CreateInstance(stepInfo.StepType, _api) as IStep; + step = (IStep)_container.Resolve(stepInfo.StepType); } catch (Exception e) { diff --git a/src/Nethermind/Nethermind.Init/Steps/IEthereumRunnerStep.cs b/src/Nethermind/Nethermind.Init/Steps/IEthereumRunnerStep.cs index df856ac2e03..3ddff573e3c 100644 --- a/src/Nethermind/Nethermind.Init/Steps/IEthereumRunnerStep.cs +++ b/src/Nethermind/Nethermind.Init/Steps/IEthereumRunnerStep.cs @@ -1,8 +1,14 @@ // SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only +using System; +using System.Linq; +using System.Reflection; using System.Threading; using System.Threading.Tasks; +using Autofac; +using Autofac.Features.AttributeFilters; +using Nethermind.Core.Container; namespace Nethermind.Init.Steps { @@ -12,4 +18,40 @@ public interface IStep public bool MustInitialize => true; } + + public static class ContainerBuilderExtensions + { + public static ContainerBuilder AddIStepsFromAssembly(this ContainerBuilder builder, Assembly assembly) + { + foreach (Type stepType in assembly.GetExportedTypes().Where(IsStepType)) + { + AddIStep(builder, stepType); + } + + return builder; + } + + public static ContainerBuilder AddIStep(this ContainerBuilder builder, Type stepType) + { + builder.RegisterType(stepType) + .AsSelf() + .As() + .WithAttributeFiltering(); + + StepInfo info = new StepInfo(stepType, GetStepBaseType(stepType)); + return builder.AddInstance(info); + } + + private static bool IsStepType(Type t) => !t.IsInterface && !t.IsAbstract && typeof(IStep).IsAssignableFrom((Type?)(Type?)t); + private static bool IsBaseStepType(Type t) => t != typeof(IStep) && typeof(IStep).IsAssignableFrom((Type?)t); + private static Type GetStepBaseType(Type type) + { + while (type.BaseType is not null && IsBaseStepType(type.BaseType)) + { + type = type.BaseType; + } + + return type; + } + } } diff --git a/src/Nethermind/Nethermind.Init/Steps/IEthereumStepsLoader.cs b/src/Nethermind/Nethermind.Init/Steps/IEthereumStepsLoader.cs index fac08caa63a..58a44f5139b 100644 --- a/src/Nethermind/Nethermind.Init/Steps/IEthereumStepsLoader.cs +++ b/src/Nethermind/Nethermind.Init/Steps/IEthereumStepsLoader.cs @@ -8,6 +8,6 @@ namespace Nethermind.Init.Steps { public interface IEthereumStepsLoader { - public IEnumerable LoadSteps(Type apiType); + public IEnumerable LoadSteps(); } } diff --git a/src/Nethermind/Nethermind.Init/Steps/InitializeNetwork.cs b/src/Nethermind/Nethermind.Init/Steps/InitializeNetwork.cs index db2854c0003..f419e6f4db2 100644 --- a/src/Nethermind/Nethermind.Init/Steps/InitializeNetwork.cs +++ b/src/Nethermind/Nethermind.Init/Steps/InitializeNetwork.cs @@ -2,19 +2,17 @@ // SPDX-License-Identifier: LGPL-3.0-only 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; -using Nethermind.Blockchain.Utils; using Nethermind.Core; +using Nethermind.Core.Container; +using Nethermind.Core.Timers; using Nethermind.Crypto; using Nethermind.Db; using Nethermind.Facade.Eth; @@ -32,14 +30,15 @@ using Nethermind.Network.Rlpx; using Nethermind.Network.Rlpx.Handshake; using Nethermind.Network.StaticNodes; +using Nethermind.Specs.ChainSpecStyle; +using Nethermind.Stats; using Nethermind.Stats.Model; using Nethermind.Synchronization; -using Nethermind.Synchronization.Blocks; using Nethermind.Synchronization.ParallelSync; using Nethermind.Synchronization.Peers; using Nethermind.Synchronization.SnapSync; using Nethermind.Synchronization.Trie; -using Nethermind.TxPool; +using Module = Autofac.Module; namespace Nethermind.Init.Steps; @@ -58,13 +57,12 @@ public static long Estimate(uint arenaCount, int arenaOrder) typeof(LoadGenesisBlock), typeof(UpdateDiscoveryConfig), typeof(SetupKeyStore), - typeof(InitializeNodeStats), typeof(ResolveIps), typeof(InitializePlugins), typeof(InitializeBlockchain))] public class InitializeNetwork : IStep { - private const string PeersDbPath = "peers"; + public const string PeersDbPath = "peers"; protected readonly IApiWithNetwork _api; private readonly ILogger _logger; @@ -86,9 +84,6 @@ public async Task Execute(CancellationToken cancellationToken) private async Task Initialize(CancellationToken cancellationToken) { - if (_api.DbProvider is null) throw new StepDependencyException(nameof(_api.DbProvider)); - if (_api.BlockTree is null) throw new StepDependencyException(nameof(_api.BlockTree)); - if (_networkConfig.DiagTracerEnabled) { NetworkDiagTracer.IsEnabled = true; @@ -99,77 +94,48 @@ private async Task Initialize(CancellationToken cancellationToken) NetworkDiagTracer.Start(_api.LogManager); } - _api.BetterPeerStrategy = new TotalDifficultyBetterPeerStrategy(_api.LogManager); - int maxPeersCount = _networkConfig.ActivePeersMaxCount; - int maxPriorityPeersCount = _networkConfig.PriorityPeersMaxCount; Network.Metrics.PeerLimit = maxPeersCount; - SyncPeerPool apiSyncPeerPool = new(_api.BlockTree, _api.NodeStatsManager!, _api.BetterPeerStrategy, _api.LogManager, maxPeersCount, maxPriorityPeersCount); - - _api.SyncPeerPool = apiSyncPeerPool; - _api.PeerDifficultyRefreshPool = apiSyncPeerPool; - _api.DisposeStack.Push(_api.SyncPeerPool); - - if (_api.TrieStore is HealingTrieStore healingTrieStore) - { - healingTrieStore.InitializeNetwork(new GetNodeDataTrieNodeRecovery(apiSyncPeerPool, _api.LogManager)); - } - - if (_api.WorldState is HealingWorldState healingWorldState) - { - healingWorldState.InitializeNetwork(new SnapTrieNodeRecovery(apiSyncPeerPool, _api.LogManager)); - } - IEnumerable synchronizationPlugins = _api.GetSynchronizationPlugins(); + ISynchronizationPlugin[] synchronizationPlugins = _api.GetSynchronizationPlugins().ToArray(); foreach (ISynchronizationPlugin plugin in synchronizationPlugins) { await plugin.InitSynchronization(); } - _api.Pivot ??= new Pivot(_syncConfig); + // TODO: Plugins can change something in `InitSynchronization`, so these need to be delayed + SyncedTxGossipPolicy txGossipPolicy = _api.BaseContainer.Resolve(); + ISyncServer _ = _api.BaseContainer.Resolve(); + IDiscoveryApp discoveryApp = _api.BaseContainer.Resolve(); + IPeerPool peerPool = _api.BaseContainer.Resolve(); + IPeerManager peerManager = _api.BaseContainer.Resolve(); + ISessionMonitor sessionMonitor = _api.BaseContainer.Resolve(); + IRlpxHost rlpxHost = _api.BaseContainer.Resolve(); + IStaticNodesManager staticNodesManager = _api.BaseContainer.Resolve(); + Func nodeSourceToDiscV4Feeder = _api.BaseContainer.Resolve>(); + IProtocolsManager protocolsManager = _api.BaseContainer.Resolve(); + SnapCapabilitySwitcher snapCapabilitySwitcher = _api.BaseContainer.Resolve(); + ISyncPeerPool syncPeerPool = _api.BaseContainer.Resolve(); + ISynchronizer synchronizer = _api.BaseContainer.Resolve(); + + _api.TxGossipPolicy.Policies.Add(txGossipPolicy); - if (_api.Synchronizer is null) + if (_api.TrieStore is HealingTrieStore healingTrieStore) { - if (_api.ChainSpec.SealEngineType == SealEngineType.Clique) - _syncConfig.NeedToWaitForHeader = true; // Should this be in chainspec itself? - - ContainerBuilder builder = new ContainerBuilder(); - _api.ConfigureContainerBuilderFromApiWithNetwork(builder) - .AddSingleton(No.BeaconSync); - builder.RegisterModule(new SynchronizerModule(_syncConfig)); - IContainer container = builder.Build(); + healingTrieStore.InitializeNetwork(_api.BaseContainer.Resolve()); + } - _api.ApiWithNetworkServiceContainer = container; - _api.DisposeStack.Append(container); + if (_api.WorldState is HealingWorldState healingWorldState) + { + healingWorldState.InitializeNetwork(_api.BaseContainer.Resolve()); } - _api.EthSyncingInfo = new EthSyncingInfo(_api.BlockTree, _api.ReceiptStorage!, _syncConfig, - _api.SyncModeSelector!, _api.SyncProgressResolver!, _api.LogManager); - _api.TxGossipPolicy.Policies.Add(new SyncedTxGossipPolicy(_api.SyncModeSelector)); - - ISyncServer syncServer = _api.SyncServer = new SyncServer( - _api.TrieStore!.TrieNodeRlpStore, - _api.DbProvider.CodeDb, - _api.BlockTree, - _api.ReceiptStorage!, - _api.BlockValidator!, - _api.SealValidator!, - _api.SyncPeerPool, - _api.SyncModeSelector, - _api.Config(), - _api.GossipPolicy, - _api.SpecProvider!, - _api.LogManager); - - _api.DisposeStack.Push(syncServer); - - InitDiscovery(); if (cancellationToken.IsCancellationRequested) { return; } - await InitPeer().ContinueWith(initPeerTask => + await InitPeer(rlpxHost, staticNodesManager, nodeSourceToDiscV4Feeder, protocolsManager).ContinueWith(initPeerTask => { if (initPeerTask.IsFaulted) { @@ -179,8 +145,6 @@ await InitPeer().ContinueWith(initPeerTask => if (_syncConfig.SnapSync && _syncConfig.SnapServingEnabled != true) { - SnapCapabilitySwitcher snapCapabilitySwitcher = - new(_api.ProtocolsManager, _api.SyncModeSelector, _api.LogManager); snapCapabilitySwitcher.EnableSnapCapabilityUntilSynced(); } @@ -191,7 +155,7 @@ await InitPeer().ContinueWith(initPeerTask => return; } - await StartSync().ContinueWith(initNetTask => + await StartSync(syncPeerPool, synchronizer).ContinueWith(initNetTask => { if (initNetTask.IsFaulted) { @@ -204,7 +168,7 @@ await StartSync().ContinueWith(initNetTask => return; } - await StartDiscovery().ContinueWith(initDiscoveryTask => + await StartDiscovery(discoveryApp).ContinueWith(initDiscoveryTask => { if (initDiscoveryTask.IsFaulted) { @@ -219,7 +183,7 @@ await StartDiscovery().ContinueWith(initDiscoveryTask => return; } - StartPeer(); + StartPeer(peerPool, peerManager, sessionMonitor); } catch (Exception e) { @@ -237,10 +201,8 @@ await StartDiscovery().ContinueWith(initDiscoveryTask => ThisNodeInfo.AddInfo("Node address :", $"{_api.Enode.Address} (do not use as an account)"); } - private Task StartDiscovery() + private Task StartDiscovery(IDiscoveryApp discoveryApp) { - if (_api.DiscoveryApp is null) throw new StepDependencyException(nameof(_api.DiscoveryApp)); - if (!_api.Config().DiscoveryEnabled) { if (_logger.IsWarn) _logger.Warn($"Skipping discovery init due to {nameof(IInitConfig.DiscoveryEnabled)} set to false"); @@ -248,68 +210,36 @@ private Task StartDiscovery() } if (_logger.IsDebug) _logger.Debug("Starting discovery process."); - _ = _api.DiscoveryApp.StartAsync(); + _ = discoveryApp.StartAsync(); if (_logger.IsDebug) _logger.Debug("Discovery process started."); return Task.CompletedTask; } - private void StartPeer() + private void StartPeer(IPeerPool peerPool, IPeerManager peerManager, ISessionMonitor sessionMonitor) { - if (_api.PeerManager is null) throw new StepDependencyException(nameof(_api.PeerManager)); - if (_api.SessionMonitor is null) throw new StepDependencyException(nameof(_api.SessionMonitor)); - if (_api.PeerPool is null) throw new StepDependencyException(nameof(_api.PeerPool)); - if (!_api.Config().PeerManagerEnabled) { if (_logger.IsWarn) _logger.Warn($"Skipping peer manager init due to {nameof(IInitConfig.PeerManagerEnabled)} set to false"); } if (_logger.IsDebug) _logger.Debug("Initializing peer manager"); - _api.PeerPool.Start(); - _api.PeerManager.Start(); - _api.SessionMonitor.Start(); + peerPool.Start(); + peerManager.Start(); + sessionMonitor.Start(); if (_logger.IsDebug) _logger.Debug("Peer manager initialization completed"); } - private void InitDiscovery() + private Task StartSync(ISyncPeerPool syncPeerPool, ISynchronizer synchronizer) { - if (_api.NodeStatsManager is null) throw new StepDependencyException(nameof(_api.NodeStatsManager)); - if (_api.Timestamper is null) throw new StepDependencyException(nameof(_api.Timestamper)); - if (_api.NodeKey is null) throw new StepDependencyException(nameof(_api.NodeKey)); - if (_api.CryptoRandom is null) throw new StepDependencyException(nameof(_api.CryptoRandom)); - if (_api.EthereumEcdsa is null) throw new StepDependencyException(nameof(_api.EthereumEcdsa)); - - if (!_api.Config().DiscoveryEnabled) - { - _api.DiscoveryApp = new NullDiscoveryApp(); - return; - } - - _api.DiscoveryApp = new CompositeDiscoveryApp(_api.NodeKey, - _networkConfig, _api.Config(), _api.Config(), - _api.EthereumEcdsa, _api.MessageSerializationService, - _api.LogManager, _api.Timestamper, _api.CryptoRandom, - _api.NodeStatsManager, _api.IpResolver - ); - - _api.DiscoveryApp.Initialize(_api.NodeKey.PublicKey); - } - - private Task StartSync() - { - if (_api.SyncPeerPool is null) throw new StepDependencyException(nameof(_api.SyncPeerPool)); - if (_api.Synchronizer is null) throw new StepDependencyException(nameof(_api.Synchronizer)); - if (_api.BlockTree is null) throw new StepDependencyException(nameof(_api.BlockTree)); - ISyncConfig syncConfig = _api.Config(); if (syncConfig.NetworkingEnabled) { - _api.SyncPeerPool!.Start(); + syncPeerPool.Start(); if (syncConfig.SynchronizationEnabled) { - if (_logger.IsDebug) _logger.Debug($"Starting synchronization from block {_api.BlockTree.Head?.Header.ToString(BlockHeader.Format.Short)}."); - _api.Synchronizer!.Start(); + if (_logger.IsDebug) _logger.Debug($"Starting synchronization from block {_api.BlockTree!.Head?.Header.ToString(BlockHeader.Format.Short)}."); + synchronizer.Start(); } else { @@ -322,29 +252,16 @@ private Task StartSync() return Task.CompletedTask; } - private async Task InitPeer() + private async Task InitPeer( + IRlpxHost rlpxHost, + IStaticNodesManager staticNodesManager, + Func nodeSourceToDiscV4Feeder, + IProtocolsManager protocolsManager + ) { - if (_api.DbProvider is null) throw new StepDependencyException(nameof(_api.DbProvider)); - if (_api.BlockTree is null) throw new StepDependencyException(nameof(_api.BlockTree)); - if (_api.ReceiptStorage is null) throw new StepDependencyException(nameof(_api.ReceiptStorage)); - if (_api.BlockValidator is null) throw new StepDependencyException(nameof(_api.BlockValidator)); - if (_api.SyncPeerPool is null) throw new StepDependencyException(nameof(_api.SyncPeerPool)); - if (_api.Synchronizer is null) throw new StepDependencyException(nameof(_api.Synchronizer)); - if (_api.Enode is null) throw new StepDependencyException(nameof(_api.Enode)); - if (_api.NodeKey is null) throw new StepDependencyException(nameof(_api.NodeKey)); - if (_api.MainBlockProcessor is null) throw new StepDependencyException(nameof(_api.MainBlockProcessor)); - if (_api.NodeStatsManager is null) throw new StepDependencyException(nameof(_api.NodeStatsManager)); - if (_api.KeyStore is null) throw new StepDependencyException(nameof(_api.KeyStore)); - if (_api.Wallet is null) throw new StepDependencyException(nameof(_api.Wallet)); - if (_api.EthereumEcdsa is null) throw new StepDependencyException(nameof(_api.EthereumEcdsa)); if (_api.SpecProvider is null) throw new StepDependencyException(nameof(_api.SpecProvider)); - if (_api.TxPool is null) throw new StepDependencyException(nameof(_api.TxPool)); - if (_api.TxSender is null) throw new StepDependencyException(nameof(_api.TxSender)); - if (_api.EthereumJsonSerializer is null) throw new StepDependencyException(nameof(_api.EthereumJsonSerializer)); - if (_api.DiscoveryApp is null) throw new StepDependencyException(nameof(_api.DiscoveryApp)); /* rlpx */ - EciesCipher eciesCipher = new(_api.CryptoRandom); Eip8MessagePad eip8Pad = new(_api.CryptoRandom); _api.MessageSerializationService.Register(new AuthEip8MessageSerializer(eip8Pad)); _api.MessageSerializationService.Register(new AckEip8MessageSerializer(eip8Pad)); @@ -353,122 +270,181 @@ private async Task InitPeer() _api.MessageSerializationService.Register(receiptsMessageSerializer); _api.MessageSerializationService.Register(new Network.P2P.Subprotocols.Eth.V66.Messages.ReceiptsMessageSerializer(receiptsMessageSerializer)); - HandshakeService encryptionHandshakeServiceA = new( - _api.MessageSerializationService, - eciesCipher, - _api.CryptoRandom, - _api.EthereumEcdsa, - _api.NodeKey.Unprotect(), - _api.LogManager); - IDiscoveryConfig discoveryConfig = _api.Config(); // TODO: hack, but changing it in all the documentation would be a nightmare _networkConfig.Bootnodes = discoveryConfig.Bootnodes; - IInitConfig initConfig = _api.Config(); - - _api.DisconnectsAnalyzer = new MetricsDisconnectsAnalyzer(); - _api.SessionMonitor = new SessionMonitor(_networkConfig, _api.LogManager); - _api.RlpxPeer = new RlpxHost( - _api.MessageSerializationService, - _api.NodeKey.PublicKey, - _networkConfig.ProcessingThreadCount, - _networkConfig.P2PPort, - _networkConfig.LocalIp, - _networkConfig.ConnectTimeoutMs, - encryptionHandshakeServiceA, - _api.SessionMonitor, - _api.DisconnectsAnalyzer, - _api.LogManager, - TimeSpan.FromMilliseconds(_networkConfig.SimulateSendLatencyMs) - ); - - await _api.RlpxPeer.Init(); - - _api.StaticNodesManager = new StaticNodesManager(initConfig.StaticNodesPath, _api.LogManager); - await _api.StaticNodesManager.InitAsync(); - - // ToDo: PeersDB is registered outside dbProvider - string dbName = "PeersDB"; - IFullDb peersDb = initConfig.DiagnosticMode == DiagnosticMode.MemDb - ? new MemDb(dbName) - : new SimpleFilePublicKeyDb(dbName, PeersDbPath.GetApplicationResourcePath(initConfig.BaseDbPath), - _api.LogManager); - - NetworkStorage peerStorage = new(peersDb, _api.LogManager); - ISyncServer syncServer = _api.SyncServer!; - ForkInfo forkInfo = new(_api.SpecProvider!, syncServer.Genesis.Hash!); - - ProtocolValidator protocolValidator = new(_api.NodeStatsManager!, _api.BlockTree, forkInfo, _api.LogManager); - PooledTxsRequestor pooledTxsRequestor = new(_api.TxPool!, _api.Config()); - - ISnapServer? snapServer = null; + await rlpxHost.Init(); + await staticNodesManager.InitAsync(); + if (_syncConfig.SnapServingEnabled == true) { - // TODO: Add a proper config for the state persistence depth. - snapServer = new SnapServer(_api.TrieStore!.AsReadOnly(), _api.DbProvider.CodeDb, new LastNStateRootTracker(_api.BlockTree, 128), _api.LogManager); + protocolsManager.AddSupportedCapability(new Capability(Protocol.Snap, 1)); } - _api.ProtocolsManager = new ProtocolsManager( - _api.SyncPeerPool!, - syncServer, - _api.BackgroundTaskScheduler, - _api.TxPool, - pooledTxsRequestor, - _api.DiscoveryApp, - _api.MessageSerializationService, - _api.RlpxPeer, - _api.NodeStatsManager, - protocolValidator, - peerStorage, - forkInfo, - _api.GossipPolicy, - _networkConfig, - snapServer, - _api.LogManager, - _api.TxGossipPolicy); + if (!_networkConfig.DisableDiscV4DnsFeeder) + { + // Feed some nodes into discoveryApp in case all bootnodes is faulty. + _ = nodeSourceToDiscV4Feeder().Run(_api.ProcessExit!.Token); + } - if (_syncConfig.SnapServingEnabled == true) + foreach (INethermindPlugin plugin in _api.Plugins) { - _api.ProtocolsManager!.AddSupportedCapability(new Capability(Protocol.Snap, 1)); + await plugin.InitNetworkProtocol(); } + } +} - _api.ProtocolValidator = protocolValidator; +public class NetworkModule(INetworkConfig networkConfig, ISyncConfig syncConfig) : Module +{ + protected override void Load(ContainerBuilder builder) + { + base.Load(builder); - NodesLoader nodesLoader = new(_networkConfig, _api.NodeStatsManager, peerStorage, _api.RlpxPeer, _api.LogManager); + builder + .RegisterBuildCallback(ctx => + { + if (ctx.Resolve().SealEngineType == SealEngineType.Clique) + syncConfig.NeedToWaitForHeader = true; // Should this be in chainspec itself? + }); - // I do not use the key here -> API is broken - no sense to use the node signer here - NodeRecordSigner nodeRecordSigner = new(_api.EthereumEcdsa, new PrivateKeyGenerator().Generate()); - EnrRecordParser enrRecordParser = new(nodeRecordSigner); + builder.RegisterModule(new SynchronizerModule(syncConfig)); - if (_networkConfig.DiscoveryDns == null) - { - string chainName = BlockchainIds.GetBlockchainName(_api.ChainSpec!.NetworkId).ToLowerInvariant(); - _networkConfig.DiscoveryDns = $"all.{chainName}.ethdisco.net"; - } + builder + .Register(ctx => + { + // Had to manually construct as the network config is not referrable by NodeStatsManagerv + ITimerFactory timerFactory = ctx.Resolve(); + ILogManager logManager = ctx.Resolve(); + INetworkConfig config = ctx.Resolve(); + return new NodeStatsManager(timerFactory, logManager, config.MaxCandidatePeerCount); + }) + .As() + .SingleInstance(); + + builder + .AddSingleton() + .AddInstance(No.BeaconSync) + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + ; + + builder + .RegisterType() + .As() + .As() + .SingleInstance(); + + + builder + .AddSingleton() + .AddSingleton(); + + builder + .Register(ctx => (IDiscoveryApp)(ctx.Resolve().DiscoveryEnabled + ? ctx.Resolve() + : ctx.Resolve())) + .As() + .SingleInstance(); - EnrDiscovery enrDiscovery = new(enrRecordParser, _networkConfig, _api.LogManager); // initialize with a proper network + /* rlpx */ + builder + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton(); + + builder + .Register(ctx => + { + // TOOD: Move StaticNodesPath to NetworkConfig. + IInitConfig initConfig = ctx.Resolve(); + ILogManager logManager = ctx.Resolve(); + return new StaticNodesManager(initConfig.StaticNodesPath, logManager); + }) + .As() + .SingleInstance(); + + builder + .Register(ctx => + { + IInitConfig initConfig = ctx.Resolve(); + ILogManager logManager = ctx.Resolve(); + + // ToDo: PeersDB is registered outside dbProvider + string dbName = "PeersDB"; + IFullDb peersDb = initConfig.DiagnosticMode == DiagnosticMode.MemDb + ? new MemDb(dbName) + : new SimpleFilePublicKeyDb(dbName, + InitializeNetwork.PeersDbPath.GetApplicationResourcePath(initConfig.BaseDbPath), + logManager); + + return peersDb; + }) + .Named(nameof(NetworkStorage)); + + + builder + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton(); + + builder + .Register(ctx => + { + IEthereumEcdsa ecdsa = ctx.Resolve(); + ILogManager logManager = ctx.Resolve(); + ChainSpec chainSpec = ctx.Resolve(); - if (!_networkConfig.DisableDiscV4DnsFeeder) - { - // Feed some nodes into discoveryApp in case all bootnodes is faulty. - _ = new NodeSourceToDiscV4Feeder(enrDiscovery, _api.DiscoveryApp, 50).Run(_api.ProcessExit!.Token); - } + // I do not use the key here -> API is broken - no sense to use the node signer here + NodeRecordSigner nodeRecordSigner = new(ecdsa, new PrivateKeyGenerator().Generate()); + EnrRecordParser enrRecordParser = new(nodeRecordSigner); - CompositeNodeSource nodeSources = _networkConfig.OnlyStaticPeers - ? new(_api.StaticNodesManager, nodesLoader) - : new(_api.StaticNodesManager, nodesLoader, enrDiscovery, _api.DiscoveryApp); - _api.PeerPool = new PeerPool(nodeSources, _api.NodeStatsManager, peerStorage, _networkConfig, _api.LogManager); - _api.PeerManager = new PeerManager( - _api.RlpxPeer, - _api.PeerPool, - _api.NodeStatsManager, - _networkConfig, - _api.LogManager); + if (networkConfig.DiscoveryDns == null) + { + string chainName = BlockchainIds.GetBlockchainName(chainSpec.NetworkId).ToLowerInvariant(); + networkConfig.DiscoveryDns = $"all.{chainName}.ethdisco.net"; + } - foreach (INethermindPlugin plugin in _api.Plugins) + EnrDiscovery enrDiscovery = new(enrRecordParser, networkConfig, logManager); // initialize with a proper network + + return enrDiscovery; + }) + .AsSelf() + .Named(INodeSource.EnrSource) + .SingleInstance(); + + if (!networkConfig.OnlyStaticPeers) { - await plugin.InitNetworkProtocol(); + builder + .Bind() + .Bind(); } + else + { + builder + .Bind() + .Bind() + .Bind() + .Bind(); + } + + builder + .RegisterComposite(); + + builder + .AddSingleton() + .AddSingleton() + .AddSingleton(); } } diff --git a/src/Nethermind/Nethermind.Init/Steps/InitializeNodeStats.cs b/src/Nethermind/Nethermind.Init/Steps/InitializeNodeStats.cs deleted file mode 100644 index ddf6d80d99f..00000000000 --- a/src/Nethermind/Nethermind.Init/Steps/InitializeNodeStats.cs +++ /dev/null @@ -1,36 +0,0 @@ -// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited -// SPDX-License-Identifier: LGPL-3.0-only - -using System.Threading; -using System.Threading.Tasks; -using Nethermind.Api; -using Nethermind.Network.Config; -using Nethermind.Stats; - -namespace Nethermind.Init.Steps -{ - [RunnerStepDependencies] - public class InitializeNodeStats : IStep - { - private readonly IApiWithNetwork _api; - - public InitializeNodeStats(INethermindApi api) - { - _api = api; - } - - public Task Execute(CancellationToken _) - { - INetworkConfig config = _api.Config(); - - // create shared objects between discovery and peer manager - NodeStatsManager nodeStatsManager = new(_api.TimerFactory, _api.LogManager, config.MaxCandidatePeerCount); - _api.NodeStatsManager = nodeStatsManager; - _api.DisposeStack.Push(nodeStatsManager); - - return Task.CompletedTask; - } - - public bool MustInitialize => false; - } -} diff --git a/src/Nethermind/Nethermind.JsonRpc.TraceStore/TraceStorePlugin.cs b/src/Nethermind/Nethermind.JsonRpc.TraceStore/TraceStorePlugin.cs index 42978992818..91b832a9c08 100644 --- a/src/Nethermind/Nethermind.JsonRpc.TraceStore/TraceStorePlugin.cs +++ b/src/Nethermind/Nethermind.JsonRpc.TraceStore/TraceStorePlugin.cs @@ -11,11 +11,10 @@ namespace Nethermind.JsonRpc.TraceStore; -public class TraceStorePlugin : INethermindPlugin +public class TraceStorePlugin(ITraceStoreConfig config) : INethermindPlugin { private const string DbName = "TraceStore"; private INethermindApi _api = null!; - private ITraceStoreConfig _config = null!; private IJsonRpcConfig _jsonRpcConfig = null!; private IDb? _db; private TraceStorePruner? _pruner; @@ -25,29 +24,29 @@ public class TraceStorePlugin : INethermindPlugin public string Name => DbName; public string Description => "Allows to serve traces without the block state, by saving historical traces to DB."; public string Author => "Nethermind"; - private bool Enabled => _config?.Enabled == true; + public bool Enabled => config.Enabled; public Task Init(INethermindApi nethermindApi) { _api = nethermindApi; _logManager = _api.LogManager; - _config = _api.Config(); + config = _api.Config(); _jsonRpcConfig = _api.Config(); _logger = _logManager.GetClassLogger(); if (Enabled) { // Setup serialization - _traceSerializer = new ParityLikeTraceSerializer(_logManager, _config.MaxDepth, _config.VerifySerialized); + _traceSerializer = new ParityLikeTraceSerializer(_logManager, config.MaxDepth, config.VerifySerialized); // Setup DB _db = _api.DbFactory!.CreateDb(new DbSettings(DbName, DbName.ToLower())); _api.DbProvider!.RegisterDb(DbName, _db); //Setup pruning if configured - if (_config.BlocksToKeep != 0) + if (config.BlocksToKeep != 0) { - _pruner = new TraceStorePruner(_api.BlockTree!, _db, _config.BlocksToKeep, _logManager); + _pruner = new TraceStorePruner(_api.BlockTree!, _db, config.BlocksToKeep, _logManager); } } @@ -58,10 +57,10 @@ public Task InitNetworkProtocol() { if (Enabled) { - if (_logger.IsInfo) _logger.Info($"Starting TraceStore with {_config.TraceTypes} traces."); + if (_logger.IsInfo) _logger.Info($"Starting TraceStore with {config.TraceTypes} traces."); // Setup tracing - ParityLikeBlockTracer parityTracer = new(_config.TraceTypes); + ParityLikeBlockTracer parityTracer = new(config.TraceTypes); DbPersistingBlockTracer dbPersistingTracer = new(parityTracer, _db!, _traceSerializer!, _logManager); _api.BlockchainProcessor!.Tracers.Add(dbPersistingTracer); @@ -78,7 +77,7 @@ public Task InitRpcModules() IRpcModuleProvider apiRpcModuleProvider = _api.RpcModuleProvider!; if (apiRpcModuleProvider.GetPool(ModuleType.Trace) is IRpcModulePool traceModulePool) { - TraceStoreModuleFactory traceModuleFactory = new(traceModulePool.Factory, _db!, _api.BlockTree!, _api.ReceiptFinder!, _traceSerializer!, _logManager, _config.DeserializationParallelization); + TraceStoreModuleFactory traceModuleFactory = new(traceModulePool.Factory, _db!, _api.BlockTree!, _api.ReceiptFinder!, _traceSerializer!, _logManager, config.DeserializationParallelization); apiRpcModuleProvider.RegisterBoundedByCpuCount(traceModuleFactory, _jsonRpcConfig.Timeout); } } diff --git a/src/Nethermind/Nethermind.Merge.AuRa.Test/AuRaMergeEngineModuleTests.cs b/src/Nethermind/Nethermind.Merge.AuRa.Test/AuRaMergeEngineModuleTests.cs index b2d1e4c26ab..93d1ac7705d 100644 --- a/src/Nethermind/Nethermind.Merge.AuRa.Test/AuRaMergeEngineModuleTests.cs +++ b/src/Nethermind/Nethermind.Merge.AuRa.Test/AuRaMergeEngineModuleTests.cs @@ -3,6 +3,8 @@ using System; using System.Threading.Tasks; +using Autofac; +using Nethermind.Api; using Nethermind.Blockchain.BeaconBlockRoot; using Nethermind.Blockchain.Blocks; using Nethermind.Blockchain.Synchronization; @@ -19,6 +21,7 @@ using Nethermind.Consensus.Rewards; using Nethermind.Consensus.Transactions; using Nethermind.Core; +using Nethermind.Core.Container; using Nethermind.Core.Crypto; using Nethermind.Core.Specs; using Nethermind.Core.Test.Blockchain; @@ -118,25 +121,29 @@ protected override Task Build(ISpecProvider? specProvider = null return base.Build(specProvider, initialValues, addBlockOnStart); } - protected override IBlockProcessor CreateBlockProcessor() + protected override void ConfigureContainer(ContainerBuilder builder) { - _api = new(new ConfigProvider(), new EthereumJsonSerializer(), LogManager, - new ChainSpec + base.ConfigureContainer(builder); + builder + .AddInstance(new ChainSpec + { + AuRa = new() { - AuRa = new() - { - WithdrawalContractAddress = new("0xbabe2bed00000000000000000000000000000003") - }, - Parameters = new() - }) - { - BlockTree = BlockTree, - DbProvider = DbProvider, - WorldStateManager = WorldStateManager, - SpecProvider = SpecProvider, - TransactionComparerProvider = TransactionComparerProvider, - TxPool = TxPool - }; + WithdrawalContractAddress = new("0xbabe2bed00000000000000000000000000000003") + }, + Parameters = new() + }) + .AddModule(new AuraModule()); + } + + protected override IBlockProcessor CreateBlockProcessor() + { + _api = Container.Resolve(); + _api.BlockTree = BlockTree; + _api.DbProvider = DbProvider; + _api.WorldStateManager = WorldStateManager; + _api.TransactionComparerProvider = TransactionComparerProvider; + _api.TxPool = TxPool; WithdrawalContractFactory withdrawalContractFactory = new(_api.ChainSpec!.AuRa, _api.AbiEncoder); WithdrawalProcessor = new AuraWithdrawalProcessor( diff --git a/src/Nethermind/Nethermind.Merge.AuRa/AuRaMergePlugin.cs b/src/Nethermind/Nethermind.Merge.AuRa/AuRaMergePlugin.cs index 5e6b55a5ff4..4bb51f2b410 100644 --- a/src/Nethermind/Nethermind.Merge.AuRa/AuRaMergePlugin.cs +++ b/src/Nethermind/Nethermind.Merge.AuRa/AuRaMergePlugin.cs @@ -3,6 +3,8 @@ using System; using System.Threading.Tasks; +using Autofac; +using Autofac.Core; using Nethermind.Api; using Nethermind.Api.Extensions; using Nethermind.Blockchain; @@ -12,8 +14,10 @@ using Nethermind.Consensus.AuRa.Transactions; using Nethermind.Consensus.Transactions; using Nethermind.Core; +using Nethermind.Init.Steps; using Nethermind.Merge.Plugin; using Nethermind.Merge.Plugin.BlockProduction; +using Nethermind.Specs.ChainSpecStyle; namespace Nethermind.Merge.AuRa { @@ -21,23 +25,25 @@ namespace Nethermind.Merge.AuRa /// Plugin for AuRa -> PoS migration /// /// IMPORTANT: this plugin should always come before MergePlugin - public class AuRaMergePlugin : MergePlugin, IInitializationPlugin + public class AuRaMergePlugin(IMergeConfig mergeConfig, ChainSpec chainSpec) : MergePlugin(mergeConfig, chainSpec) { private AuRaNethermindApi? _auraApi; + private readonly ChainSpec _chainSpec = chainSpec; + private readonly IMergeConfig _mergeConfig = mergeConfig; public override string Name => "AuRaMerge"; public override string Description => "AuRa Merge plugin for ETH1-ETH2"; - protected override bool MergeEnabled => ShouldRunSteps(_api); + protected override bool MergeEnabled => Enabled; + public override bool Enabled => _mergeConfig.Enabled && _chainSpec.SealEngineType == SealEngineType.AuRa; + public override IModule? ContainerModule => new AuraMergeModule(); public override async Task Init(INethermindApi nethermindApi) { _api = nethermindApi; - _mergeConfig = nethermindApi.Config(); if (MergeEnabled) { await base.Init(nethermindApi); _auraApi = (AuRaNethermindApi)nethermindApi; - _auraApi.PoSSwitcher = _poSSwitcher; // this runs before all init steps that use tx filters TxAuRaFilterBuilders.CreateFilter = (originalFilter, fallbackFilter) => @@ -82,10 +88,13 @@ protected override IBlockFinalizationManager InitializeMergeFinilizationManager( _poSSwitcher); } - public bool ShouldRunSteps(INethermindApi api) + private class AuraMergeModule : Module { - _mergeConfig = api.Config(); - return _mergeConfig.Enabled && api.ChainSpec.SealEngineType == SealEngineType.AuRa; + protected override void Load(ContainerBuilder builder) + { + base.Load(builder); + builder.AddIStepsFromAssembly(GetType().Assembly); + } } } } diff --git a/src/Nethermind/Nethermind.Merge.Plugin.Test/MergePluginTests.cs b/src/Nethermind/Nethermind.Merge.Plugin.Test/MergePluginTests.cs index d93e6c8a649..78da07dfcf8 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin.Test/MergePluginTests.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin.Test/MergePluginTests.cs @@ -3,6 +3,7 @@ using System; using System.Threading.Tasks; +using Autofac; using FluentAssertions; using Nethermind.Api; using Nethermind.Blockchain.Synchronization; @@ -36,8 +37,10 @@ public void Setup() BlocksConfig? miningConfig = new(); IJsonRpcConfig jsonRpcConfig = new JsonRpcConfig() { Enabled = true, EnabledModules = [ModuleType.Engine] }; - _context = Build.ContextWithMocks(); - _context.SealEngineType = SealEngineType.Clique; + _context = Build.ContextWithMocks(containerConfigurer: (builder) => + { + builder.RegisterModule(new MergeModule()); + }); _context.ConfigProvider.GetConfig().Returns(_mergeConfig); _context.ConfigProvider.GetConfig().Returns(new SyncConfig()); _context.ConfigProvider.GetConfig().Returns(miningConfig); @@ -56,16 +59,14 @@ public void Setup() _context.TransactionComparerProvider!, miningConfig, _context.LogManager!); - _context.ProcessExit = Substitute.For(); _context.ChainSpec.SealEngineType = SealEngineType.Clique; _context.ChainSpec!.Clique = new CliqueParameters() { Epoch = CliqueConfig.Default.Epoch, Period = CliqueConfig.Default.BlockPeriod }; - _plugin = new MergePlugin(); - - _consensusPlugin = new(); + _plugin = new MergePlugin(_mergeConfig, _context.ChainSpec); + _consensusPlugin = new(_context.ChainSpec); } [TearDown] @@ -95,6 +96,7 @@ public void Init_merge_plugin_does_not_throw_exception(bool enabled) Assert.DoesNotThrowAsync(async () => await _consensusPlugin!.Init(_context)); Assert.DoesNotThrowAsync(async () => await _plugin.Init(_context)); Assert.DoesNotThrowAsync(async () => await _plugin.InitNetworkProtocol()); + Assert.DoesNotThrowAsync(async () => await _plugin.InitSynchronization()); Assert.DoesNotThrow(() => _plugin.InitBlockProducer(_consensusPlugin!, null)); Assert.DoesNotThrowAsync(async () => await _plugin.InitRpcModules()); diff --git a/src/Nethermind/Nethermind.Merge.Plugin/MergePlugin.BlockProducer.cs b/src/Nethermind/Nethermind.Merge.Plugin/MergePlugin.BlockProducer.cs index d17d39b5599..b499460ecc6 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin/MergePlugin.BlockProducer.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin/MergePlugin.BlockProducer.cs @@ -71,6 +71,6 @@ public IBlockProducerRunner InitBlockProducerRunner(IBlockProducerRunner baseRun // this looks redundant but Enabled actually comes from IConsensusWrapperPlugin // while MergeEnabled comes from merge config - public bool Enabled => MergeEnabled; + public bool ConsensusWrapperEnabled => MergeEnabled; } } diff --git a/src/Nethermind/Nethermind.Merge.Plugin/MergePlugin.cs b/src/Nethermind/Nethermind.Merge.Plugin/MergePlugin.cs index 81b83425ace..8661000b76b 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin/MergePlugin.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin/MergePlugin.cs @@ -9,6 +9,7 @@ using Autofac; using Autofac.Core; using Autofac.Extensions.DependencyInjection; +using Autofac.Features.AttributeFilters; using Microsoft.Extensions.DependencyInjection; using Nethermind.Api; using Nethermind.Api.Extensions; @@ -21,6 +22,7 @@ using Nethermind.Consensus.Rewards; using Nethermind.Consensus.Validators; using Nethermind.Core; +using Nethermind.Core.Container; using Nethermind.Core.Exceptions; using Nethermind.Db; using Nethermind.Facade.Proxy; @@ -34,6 +36,7 @@ using Nethermind.Merge.Plugin.Handlers; using Nethermind.Merge.Plugin.InvalidChainTracker; using Nethermind.Merge.Plugin.Synchronization; +using Nethermind.Specs.ChainSpecStyle; using Nethermind.Synchronization; using Nethermind.Synchronization.Blocks; using Nethermind.Synchronization.ParallelSync; @@ -41,11 +44,10 @@ namespace Nethermind.Merge.Plugin; -public partial class MergePlugin : IConsensusWrapperPlugin, ISynchronizationPlugin +public partial class MergePlugin(IMergeConfig mergeConfig, ChainSpec chainSpec) : IConsensusWrapperPlugin, ISynchronizationPlugin { protected INethermindApi _api = null!; private ILogger _logger; - protected IMergeConfig _mergeConfig = null!; private ISyncConfig _syncConfig = null!; protected IBlocksConfig _blocksConfig = null!; protected ITxPoolConfig _txPoolConfig = null!; @@ -63,22 +65,21 @@ public partial class MergePlugin : IConsensusWrapperPlugin, ISynchronizationPlug public virtual string Description => "Merge plugin for ETH1-ETH2"; public string Author => "Nethermind"; - protected virtual bool MergeEnabled => _mergeConfig.Enabled && - _api.ChainSpec.SealEngineType is SealEngineType.BeaconChain or SealEngineType.Clique or SealEngineType.Ethash; + protected virtual bool MergeEnabled => Enabled; + public virtual bool Enabled => mergeConfig.Enabled && chainSpec.SealEngineType is SealEngineType.BeaconChain or SealEngineType.Clique or SealEngineType.Ethash; + public int Priority => PluginPriorities.Merge; - // Don't remove default constructor. It is used by reflection when we're loading plugins - public MergePlugin() { } + public virtual IModule? ContainerModule => new MergeModule(); public virtual Task Init(INethermindApi nethermindApi) { _api = nethermindApi; - _mergeConfig = nethermindApi.Config(); _syncConfig = nethermindApi.Config(); _blocksConfig = nethermindApi.Config(); _txPoolConfig = nethermindApi.Config(); - MigrateSecondsPerSlot(_blocksConfig, _mergeConfig); + MigrateSecondsPerSlot(_blocksConfig, mergeConfig); _logger = _api.LogManager.GetClassLogger(); @@ -95,22 +96,9 @@ public virtual Task Init(INethermindApi nethermindApi) EnsureJsonRpcUrl(); EnsureReceiptAvailable(); - _blockCacheService = new BlockCacheService(); - _poSSwitcher = new PoSSwitcher( - _mergeConfig, - _syncConfig, - _api.DbProvider.GetDb(DbNames.Metadata), - _api.BlockTree, - _api.SpecProvider, - _api.ChainSpec, - _api.LogManager); - _invalidChainTracker = new InvalidChainTracker.InvalidChainTracker( - _poSSwitcher, - _api.BlockTree, - _blockCacheService, - _api.LogManager); - _api.PoSSwitcher = _poSSwitcher; - _api.DisposeStack.Push(_invalidChainTracker); + _blockCacheService = _api.BaseContainer.Resolve(); + _poSSwitcher = _api.BaseContainer.Resolve(); + _invalidChainTracker = _api.BaseContainer.Resolve(); _blockFinalizationManager = new ManualBlockFinalizationManager(); if (_txPoolConfig.BlobsSupport.SupportsReorgs()) { @@ -135,7 +123,7 @@ public virtual Task Init(INethermindApi nethermindApi) private void EnsureNotConflictingSettings() { - if (!_mergeConfig.Enabled && _mergeConfig.TerminalTotalDifficulty is not null) + if (!mergeConfig.Enabled && mergeConfig.TerminalTotalDifficulty is not null) { throw new InvalidConfigurationException( $"{nameof(MergeConfig)}.{nameof(MergeConfig.TerminalTotalDifficulty)} cannot be set when {nameof(MergeConfig)}.{nameof(MergeConfig.Enabled)} is false.", @@ -229,7 +217,7 @@ private void EnsureEngineModuleIsConfigured() private bool HasTtd() { - return _api.SpecProvider?.TerminalTotalDifficulty is not null || _mergeConfig.TerminalTotalDifficulty is not null; + return _api.SpecProvider?.TerminalTotalDifficulty is not null || mergeConfig.TerminalTotalDifficulty is not null; } public Task InitNetworkProtocol() @@ -287,7 +275,6 @@ public Task InitRpcModules() if (_api.BlockTree is null) throw new ArgumentNullException(nameof(_api.BlockTree)); if (_api.BlockchainProcessor is null) throw new ArgumentNullException(nameof(_api.BlockchainProcessor)); if (_api.HeaderValidator is null) throw new ArgumentNullException(nameof(_api.HeaderValidator)); - if (_api.EthSyncingInfo is null) throw new ArgumentNullException(nameof(_api.EthSyncingInfo)); if (_api.Sealer is null) throw new ArgumentNullException(nameof(_api.Sealer)); if (_api.BlockValidator is null) throw new ArgumentNullException(nameof(_api.BlockValidator)); if (_api.BlockProcessingQueue is null) throw new ArgumentNullException(nameof(_api.BlockProcessingQueue)); @@ -308,13 +295,13 @@ public Task InitRpcModules() IBlockImprovementContextFactory CreateBlockImprovementContextFactory() { - if (string.IsNullOrEmpty(_mergeConfig.BuilderRelayUrl)) + if (string.IsNullOrEmpty(mergeConfig.BuilderRelayUrl)) { return new BlockImprovementContextFactory(_api.BlockProducer!, TimeSpan.FromSeconds(_blocksConfig.SecondsPerSlot)); } DefaultHttpClient httpClient = new(new HttpClient(), _api.EthereumJsonSerializer, _api.LogManager, retryDelayMilliseconds: 100); - IBoostRelay boostRelay = new BoostRelay(httpClient, _mergeConfig.BuilderRelayUrl); + IBoostRelay boostRelay = new BoostRelay(httpClient, mergeConfig.BuilderRelayUrl); return new BoostBlockImprovementContextFactory(_api.BlockProducer!, TimeSpan.FromSeconds(_blocksConfig.SecondsPerSlot), boostRelay, _api.StateReader); } @@ -346,7 +333,7 @@ IBlockImprovementContextFactory CreateBlockImprovementContextFactory() _invalidChainTracker, _beaconSync, _api.LogManager, - TimeSpan.FromSeconds(_mergeConfig.NewPayloadTimeout), + TimeSpan.FromSeconds(mergeConfig.NewPayloadTimeout), _api.Config().StoreReceipts), new ForkchoiceUpdatedHandler( _api.BlockTree, @@ -372,7 +359,7 @@ IBlockImprovementContextFactory CreateBlockImprovementContextFactory() new ExchangeCapabilitiesHandler(_api.RpcCapabilitiesProvider, _api.LogManager), new GetBlobsHandler(_api.TxPool), _api.SpecProvider, - new GCKeeper(new NoSyncGcRegionStrategy(_api.SyncModeSelector, _mergeConfig), _api.LogManager), + new GCKeeper(new NoSyncGcRegionStrategy(_api.SyncModeSelector, mergeConfig), _api.LogManager), _api.LogManager); RegisterEngineRpcModule(engineRpcModule); @@ -394,25 +381,16 @@ public Task InitSynchronization() if (MergeEnabled) { if (_api.SpecProvider is null) throw new ArgumentNullException(nameof(_api.SpecProvider)); - if (_api.SyncPeerPool is null) throw new ArgumentNullException(nameof(_api.SyncPeerPool)); if (_api.BlockTree is null) throw new ArgumentNullException(nameof(_api.BlockTree)); if (_api.DbProvider is null) throw new ArgumentNullException(nameof(_api.DbProvider)); if (_api.BlockProcessingQueue is null) throw new ArgumentNullException(nameof(_api.BlockProcessingQueue)); if (_blockCacheService is null) throw new ArgumentNullException(nameof(_blockCacheService)); - if (_api.BetterPeerStrategy is null) throw new ArgumentNullException(nameof(_api.BetterPeerStrategy)); if (_api.SealValidator is null) throw new ArgumentNullException(nameof(_api.SealValidator)); if (_api.UnclesValidator is null) throw new ArgumentNullException(nameof(_api.UnclesValidator)); - if (_api.NodeStatsManager is null) throw new ArgumentNullException(nameof(_api.NodeStatsManager)); if (_api.HeaderValidator is null) throw new ArgumentNullException(nameof(_api.HeaderValidator)); - if (_api.PeerDifficultyRefreshPool is null) throw new ArgumentNullException(nameof(_api.PeerDifficultyRefreshPool)); if (_api.StateReader is null) throw new ArgumentNullException(nameof(_api.StateReader)); // ToDo strange place for validators initialization - PeerRefresher peerRefresher = new(_api.PeerDifficultyRefreshPool, _api.TimerFactory, _api.LogManager); - _peerRefresher = peerRefresher; - _api.DisposeStack.Push(peerRefresher); - _beaconPivot = new BeaconPivot(_syncConfig, _api.DbProvider.MetadataDb, _api.BlockTree, _api.PoSSwitcher, _api.LogManager); - MergeHeaderValidator headerValidator = new( _poSSwitcher, _api.HeaderValidator, @@ -436,36 +414,11 @@ public Task InitSynchronization() _api.LogManager), _invalidChainTracker, _api.LogManager); - _beaconSync = new BeaconSync(_beaconPivot, _api.BlockTree, _syncConfig, _blockCacheService, _poSSwitcher, _api.LogManager); - - _api.BetterPeerStrategy = new MergeBetterPeerStrategy(_api.BetterPeerStrategy, _poSSwitcher, _beaconPivot, _api.LogManager); - _api.Pivot = _beaconPivot; - - ContainerBuilder builder = new ContainerBuilder(); - - _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, - _api.SyncModeSelector, - _api.SyncPeerPool, - _syncConfig, - _blockCacheService, - _beaconSync, - _api.DbProvider.MetadataDb, - _api.LogManager); + _peerRefresher = _api.BaseContainer.Resolve(); + _beaconPivot = _api.BaseContainer.Resolve(); + _beaconSync = _api.BaseContainer.Resolve(); + _api.BaseContainer.Resolve(); } return Task.CompletedTask; @@ -475,3 +428,42 @@ public Task InitSynchronization() public bool MustInitialize { get => true; } } + +public class MergeModule : Module +{ + protected override void Load(ContainerBuilder builder) + { + base.Load(builder); + + builder + .AddModule(new MergeNetworkModule()) + .AddSingleton() + .AddSingleton() + .AddSingleton(); + } +} + +public class MergeNetworkModule : Module +{ + protected override void Load(ContainerBuilder builder) + { + base.Load(builder); + builder + .AddSingleton() + .AddSingleton() + .AddSingleton(); + + builder + .RegisterType() + .As() + .As() + .WithAttributeFiltering() + .SingleInstance(); + + builder + .RegisterDecorator(); + + builder + .RegisterModule(new MergeSynchronizerModule()); + } +} diff --git a/src/Nethermind/Nethermind.Merge.Plugin/PoSSwitcher.cs b/src/Nethermind/Nethermind.Merge.Plugin/PoSSwitcher.cs index ff0758cc01b..0f5d118a011 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin/PoSSwitcher.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin/PoSSwitcher.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; @@ -54,7 +55,7 @@ public class PoSSwitcher : IPoSSwitcher public PoSSwitcher( IMergeConfig mergeConfig, ISyncConfig syncConfig, - IDb metadataDb, + [KeyFilter(DbNames.Metadata)] IDb metadataDb, IBlockTree blockTree, ISpecProvider specProvider, ChainSpec chainSpec, diff --git a/src/Nethermind/Nethermind.Merge.Plugin/Synchronization/BeaconPivot.cs b/src/Nethermind/Nethermind.Merge.Plugin/Synchronization/BeaconPivot.cs index dbbb4eeb778..2cab05a9beb 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin/Synchronization/BeaconPivot.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin/Synchronization/BeaconPivot.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.Consensus; @@ -45,7 +46,7 @@ private BlockHeader? CurrentBeaconPivot public BeaconPivot( ISyncConfig syncConfig, - IDb metadataDb, + [KeyFilter(DbNames.Metadata)] IDb metadataDb, IBlockTree blockTree, IPoSSwitcher poSSwitcher, ILogManager logManager) diff --git a/src/Nethermind/Nethermind.Merge.Plugin/Synchronization/MergeSynchronizer.cs b/src/Nethermind/Nethermind.Merge.Plugin/Synchronization/MergeSynchronizer.cs index ac3ad98313f..8d4365842e3 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin/Synchronization/MergeSynchronizer.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin/Synchronization/MergeSynchronizer.cs @@ -8,6 +8,7 @@ using Autofac.Features.AttributeFilters; using Nethermind.Blockchain.Synchronization; using Nethermind.Core; +using Nethermind.Core.Container; using Nethermind.Logging; using Nethermind.Synchronization; using Nethermind.Synchronization.Blocks; diff --git a/src/Nethermind/Nethermind.Merge.Plugin/Synchronization/PivotUpdator.cs b/src/Nethermind/Nethermind.Merge.Plugin/Synchronization/PivotUpdator.cs index d4f874d75fb..63f5aef3101 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin/Synchronization/PivotUpdator.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin/Synchronization/PivotUpdator.cs @@ -4,6 +4,7 @@ using System; using System.Threading; using System.Threading.Tasks; +using Autofac.Features.AttributeFilters; using Nethermind.Blockchain; using Nethermind.Blockchain.Synchronization; using Nethermind.Consensus.Validators; @@ -44,7 +45,7 @@ public PivotUpdator(IBlockTree blockTree, ISyncConfig syncConfig, IBlockCacheService blockCacheService, IBeaconSyncStrategy beaconSyncStrategy, - IDb metadataDb, + [KeyFilter(DbNames.Metadata)] IDb metadataDb, ILogManager logManager) { _blockTree = blockTree ?? throw new ArgumentNullException(nameof(blockTree)); diff --git a/src/Nethermind/Nethermind.Network/Config/INetworkConfig.cs b/src/Nethermind/Nethermind.Network.Contract/Config/INetworkConfig.cs similarity index 100% rename from src/Nethermind/Nethermind.Network/Config/INetworkConfig.cs rename to src/Nethermind/Nethermind.Network.Contract/Config/INetworkConfig.cs diff --git a/src/Nethermind/Nethermind.Network/Config/NetworkConfig.cs b/src/Nethermind/Nethermind.Network.Contract/Config/NetworkConfig.cs similarity index 100% rename from src/Nethermind/Nethermind.Network/Config/NetworkConfig.cs rename to src/Nethermind/Nethermind.Network.Contract/Config/NetworkConfig.cs diff --git a/src/Nethermind/Nethermind.Network.Contract/Nethermind.Network.Contract.csproj b/src/Nethermind/Nethermind.Network.Contract/Nethermind.Network.Contract.csproj index e8a4d7f0d10..8bd6fa5f4ce 100644 --- a/src/Nethermind/Nethermind.Network.Contract/Nethermind.Network.Contract.csproj +++ b/src/Nethermind/Nethermind.Network.Contract/Nethermind.Network.Contract.csproj @@ -3,4 +3,7 @@ annotations + + + diff --git a/src/Nethermind/Nethermind.Network.Discovery/CompositeDiscoveryApp.cs b/src/Nethermind/Nethermind.Network.Discovery/CompositeDiscoveryApp.cs index af7018c4a1a..f25e44e670f 100644 --- a/src/Nethermind/Nethermind.Network.Discovery/CompositeDiscoveryApp.cs +++ b/src/Nethermind/Nethermind.Network.Discovery/CompositeDiscoveryApp.cs @@ -3,11 +3,13 @@ using System.Net.Sockets; using System.Runtime.InteropServices; +using Autofac.Features.AttributeFilters; using DotNetty.Transport.Bootstrapping; using DotNetty.Transport.Channels; using DotNetty.Transport.Channels.Sockets; using Nethermind.Api; using Nethermind.Core; +using Nethermind.Core.Container; using Nethermind.Core.Crypto; using Nethermind.Crypto; using Nethermind.Db; @@ -48,7 +50,7 @@ public class CompositeDiscoveryApp : IDiscoveryApp private IDiscoveryApp? _v5; private INodeSource _compositeNodeSource = null!; - public CompositeDiscoveryApp(ProtectedPrivateKey? nodeKey, + public CompositeDiscoveryApp([KeyFilter(ComponentKey.NodeKey)] ProtectedPrivateKey? nodeKey, INetworkConfig networkConfig, IDiscoveryConfig discoveryConfig, IInitConfig initConfig, IEthereumEcdsa? ethereumEcdsa, IMessageSerializationService? serializationService, ILogManager? logManager, ITimestamper? timestamper, ICryptoRandom? cryptoRandom, @@ -67,11 +69,8 @@ public CompositeDiscoveryApp(ProtectedPrivateKey? nodeKey, _nodeStatsManager = nodeStatsManager ?? throw new ArgumentNullException(nameof(nodeStatsManager)); _ipResolver = ipResolver ?? throw new ArgumentNullException(nameof(ipResolver)); _connections = new DiscoveryConnectionsPool(logManager.GetClassLogger(), _networkConfig, _discoveryConfig); - } - public void Initialize(PublicKey masterPublicKey) - { - var nodeKeyProvider = new SameKeyGenerator(_nodeKey.Unprotect()); + SameKeyGenerator nodeKeyProvider = new SameKeyGenerator(_nodeKey.Unprotect()); List allNodeSources = new(); if ((_discoveryConfig.DiscoveryVersion & DiscoveryVersion.V4) != 0) @@ -189,9 +188,8 @@ private void InitDiscoveryV4(IDiscoveryConfig discoveryConfig, SameKeyGenerator _networkConfig, discoveryConfig, _timestamper, + _nodeKey.PublicKey, _logManager); - - _v4.Initialize(_nodeKey.PublicKey); } private void InitDiscoveryV5(SameKeyGenerator privateKeyProvider) @@ -202,7 +200,6 @@ private void InitDiscoveryV5(SameKeyGenerator privateKeyProvider) _logManager); _v5 = new DiscoveryV5App(privateKeyProvider, _ipResolver, _networkConfig, _discoveryConfig, discv5DiscoveryDb, _logManager); - _v5.Initialize(_nodeKey.PublicKey); } private NodeRecord PrepareNodeRecord(SameKeyGenerator privateKeyProvider) diff --git a/src/Nethermind/Nethermind.Network.Discovery/DiscoveryApp.cs b/src/Nethermind/Nethermind.Network.Discovery/DiscoveryApp.cs index 0dbfb89798d..180b728781e 100644 --- a/src/Nethermind/Nethermind.Network.Discovery/DiscoveryApp.cs +++ b/src/Nethermind/Nethermind.Network.Discovery/DiscoveryApp.cs @@ -48,6 +48,7 @@ public DiscoveryApp(INodesLocator nodesLocator, INetworkConfig? networkConfig, IDiscoveryConfig? discoveryConfig, ITimestamper? timestamper, + PublicKey masterPublicKey, ILogManager? logManager) { _logManager = logManager ?? throw new ArgumentNullException(nameof(logManager)); @@ -63,10 +64,7 @@ public DiscoveryApp(INodesLocator nodesLocator, _discoveryStorage = discoveryStorage ?? throw new ArgumentNullException(nameof(discoveryStorage)); _networkConfig = networkConfig ?? throw new ArgumentNullException(nameof(networkConfig)); _discoveryStorage.StartBatch(); - } - public void Initialize(PublicKey masterPublicKey) - { _discoveryManager.NodeDiscovered += OnNodeDiscovered; _nodeTable.Initialize(masterPublicKey); if (_nodeTable.MasterNode is null) diff --git a/src/Nethermind/Nethermind.Network.Discovery/Discv5/DiscoveryV5App.cs b/src/Nethermind/Nethermind.Network.Discovery/Discv5/DiscoveryV5App.cs index 149284c8a6b..a402924f759 100644 --- a/src/Nethermind/Nethermind.Network.Discovery/Discv5/DiscoveryV5App.cs +++ b/src/Nethermind/Nethermind.Network.Discovery/Discv5/DiscoveryV5App.cs @@ -190,8 +190,6 @@ private bool TryGetNodeFromEnr(IEnr enr, [NotNullWhen(true)] out Node? node) public event EventHandler? NodeRemoved; - public void Initialize(PublicKey masterPublicKey) { } - public void InitializeChannel(IChannel channel) { var handler = _serviceProvider.GetRequiredService(); @@ -291,6 +289,9 @@ static int[] GetDistances(byte[] srcNodeId, byte[] destNodeId) await Task.WhenAll(discoverTasks); } + catch (OperationCanceledException) + { + } catch (Exception ex) { if (_logger.IsError) _logger.Error($"Discovery via custom random walk failed.", ex); diff --git a/src/Nethermind/Nethermind.Network.Discovery/NodeSourceToDiscV4Feeder.cs b/src/Nethermind/Nethermind.Network.Discovery/NodeSourceToDiscV4Feeder.cs index ba13003b0e0..fccba8d30da 100644 --- a/src/Nethermind/Nethermind.Network.Discovery/NodeSourceToDiscV4Feeder.cs +++ b/src/Nethermind/Nethermind.Network.Discovery/NodeSourceToDiscV4Feeder.cs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LGPL-3.0-only using Nethermind.Stats.Model; +using Autofac.Features.AttributeFilters; namespace Nethermind.Network.Discovery; @@ -11,6 +12,11 @@ public class NodeSourceToDiscV4Feeder private readonly IDiscoveryApp _discoveryApp; private readonly int _maxNodes; + public NodeSourceToDiscV4Feeder([KeyFilter(INodeSource.EnrSource)] INodeSource nodeSource, IDiscoveryApp discoveryApp) + : this(nodeSource, discoveryApp, 50) + { + } + public NodeSourceToDiscV4Feeder(INodeSource nodeSource, IDiscoveryApp discoveryApp, int maxNodes) { _nodeSource = nodeSource; diff --git a/src/Nethermind/Nethermind.Network/ForkInfo.cs b/src/Nethermind/Nethermind.Network/ForkInfo.cs index 6bf1941e7f0..08e27c6b427 100644 --- a/src/Nethermind/Nethermind.Network/ForkInfo.cs +++ b/src/Nethermind/Nethermind.Network/ForkInfo.cs @@ -12,6 +12,7 @@ using Nethermind.Core.Crypto; using Nethermind.Core.Specs; using Nethermind.Specs; +using Nethermind.Synchronization; namespace Nethermind.Network { @@ -21,6 +22,11 @@ public class ForkInfo private (ForkActivation Activation, ForkId Id)[] Forks { get; } private readonly bool _hasTimestampFork; + public ForkInfo(ISpecProvider specProvider, ISyncServer syncServer) + : this(specProvider, syncServer.Genesis.Hash!) + { + } + public ForkInfo(ISpecProvider specProvider, Hash256 genesisHash) { _hasTimestampFork = specProvider.TimestampFork != ISpecProvider.TimestampForkNever; diff --git a/src/Nethermind/Nethermind.Network/IDiscoveryApp.cs b/src/Nethermind/Nethermind.Network/IDiscoveryApp.cs index 1e473ba424e..3d8cab8c00e 100644 --- a/src/Nethermind/Nethermind.Network/IDiscoveryApp.cs +++ b/src/Nethermind/Nethermind.Network/IDiscoveryApp.cs @@ -11,7 +11,6 @@ namespace Nethermind.Network { public interface IDiscoveryApp : INodeSource { - void Initialize(PublicKey masterPublicKey); void InitializeChannel(IChannel channel); Task StartAsync(); Task StopAsync(); diff --git a/src/Nethermind/Nethermind.Network/INodeSource.cs b/src/Nethermind/Nethermind.Network/INodeSource.cs index 4270bbc40e8..ad9d46677a5 100644 --- a/src/Nethermind/Nethermind.Network/INodeSource.cs +++ b/src/Nethermind/Nethermind.Network/INodeSource.cs @@ -12,4 +12,6 @@ public interface INodeSource { IAsyncEnumerable DiscoverNodes(CancellationToken cancellationToken); event EventHandler NodeRemoved; + + public const string EnrSource = nameof(EnrSource); } diff --git a/src/Nethermind/Nethermind.Network/NetworkStorage.cs b/src/Nethermind/Nethermind.Network/NetworkStorage.cs index 166c2d38206..d78170e2cbb 100644 --- a/src/Nethermind/Nethermind.Network/NetworkStorage.cs +++ b/src/Nethermind/Nethermind.Network/NetworkStorage.cs @@ -4,7 +4,7 @@ using System; using System.Collections.Generic; using System.Text; - +using Autofac.Features.AttributeFilters; using Nethermind.Config; using Nethermind.Core; using Nethermind.Core.Crypto; @@ -25,7 +25,7 @@ public class NetworkStorage : INetworkStorage private long _removeCounter; private NetworkNode[]? _nodes; - public NetworkStorage(IFullDb? fullDb, ILogManager? logManager) + public NetworkStorage([KeyFilter(nameof(NetworkStorage))] IFullDb? fullDb, ILogManager? logManager) { _fullDb = fullDb ?? throw new ArgumentNullException(nameof(fullDb)); _logger = logManager?.GetClassLogger() ?? throw new ArgumentNullException(nameof(logManager)); diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/SnapProtocolHandler.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/SnapProtocolHandler.cs index 171e83e89c7..ea3751af6e5 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/SnapProtocolHandler.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/SnapProtocolHandler.cs @@ -21,6 +21,7 @@ using Nethermind.State.Snap; using Nethermind.Stats; using Nethermind.Stats.Model; +using Nethermind.Synchronization; using Nethermind.Synchronization.SnapSync; namespace Nethermind.Network.P2P.Subprotocols.Snap @@ -71,7 +72,7 @@ public SnapProtocolHandler(ISession session, _getTrieNodesRequests = new(Send); SyncServer = snapServer; BackgroundTaskScheduler = new BackgroundTaskSchedulerWrapper(this, backgroundTaskScheduler); - ServingEnabled = SyncServer is not null; + ServingEnabled = SyncServer is not null && SyncServer.IsEnabled; } public override event EventHandler? ProtocolInitialized; diff --git a/src/Nethermind/Nethermind.Network/Rlpx/Handshake/HandshakeService.cs b/src/Nethermind/Nethermind.Network/Rlpx/Handshake/HandshakeService.cs index f1657f241a2..55baa206b1b 100644 --- a/src/Nethermind/Nethermind.Network/Rlpx/Handshake/HandshakeService.cs +++ b/src/Nethermind/Nethermind.Network/Rlpx/Handshake/HandshakeService.cs @@ -2,8 +2,10 @@ // SPDX-License-Identifier: LGPL-3.0-only using System; +using Autofac.Features.AttributeFilters; using DotNetty.Buffers; using DotNetty.Common.Utilities; +using Nethermind.Core.Container; using Nethermind.Core.Crypto; using Nethermind.Core.Extensions; using Nethermind.Crypto; @@ -29,6 +31,17 @@ public class HandshakeService : IHandshakeService private readonly ILogger _logger; private readonly IEcdsa _ecdsa; + public HandshakeService( + IMessageSerializationService messageSerializationService, + IEciesCipher eciesCipher, + ICryptoRandom cryptoRandom, + IEcdsa ecdsa, + [KeyFilter(ComponentKey.NodeKey)] ProtectedPrivateKey privateKey, + ILogManager logManager) + : this(messageSerializationService, eciesCipher, cryptoRandom, ecdsa, privateKey.Unprotect(), logManager) + { + } + public HandshakeService( IMessageSerializationService messageSerializationService, IEciesCipher eciesCipher, diff --git a/src/Nethermind/Nethermind.Network/Rlpx/RlpxHost.cs b/src/Nethermind/Nethermind.Network/Rlpx/RlpxHost.cs index 7917c84cd84..4478fddb068 100644 --- a/src/Nethermind/Nethermind.Network/Rlpx/RlpxHost.cs +++ b/src/Nethermind/Nethermind.Network/Rlpx/RlpxHost.cs @@ -6,13 +6,16 @@ using System.Net.Sockets; using System.Threading; using System.Threading.Tasks; +using Autofac.Features.AttributeFilters; using DotNetty.Common.Concurrency; using DotNetty.Handlers.Logging; using DotNetty.Transport.Bootstrapping; using DotNetty.Transport.Channels; using DotNetty.Transport.Channels.Sockets; +using Nethermind.Core.Container; using Nethermind.Core.Crypto; using Nethermind.Core.Extensions; +using Nethermind.Crypto; using Nethermind.Logging; using Nethermind.Network.Config; using Nethermind.Network.P2P; @@ -44,6 +47,21 @@ public class RlpxHost : IRlpxHost private readonly TimeSpan _sendLatency; private readonly TimeSpan _connectTimeout; + public RlpxHost( + IMessageSerializationService serializationService, + [KeyFilter(ComponentKey.NodeKey)] + ProtectedPrivateKey nodeKey, + INetworkConfig networkConfig, + IHandshakeService handshakeService, + ISessionMonitor sessionMonitor, + IDisconnectsAnalyzer disconnectsAnalyzer, + ILogManager logManager + ) : this(serializationService, nodeKey.PublicKey, networkConfig.ProcessingThreadCount, networkConfig.P2PPort, + networkConfig.LocalIp, networkConfig.ConnectTimeoutMs, handshakeService, sessionMonitor, disconnectsAnalyzer, + logManager, TimeSpan.FromMilliseconds(networkConfig.SimulateSendLatencyMs)) + { + } + public RlpxHost(IMessageSerializationService serializationService, PublicKey localNodeId, int networkProcessingThread, diff --git a/src/Nethermind/Nethermind.Optimism/OptimismNethermindApi.cs b/src/Nethermind/Nethermind.Optimism/OptimismNethermindApi.cs index 8e1e8f4002d..b8c956b0c88 100644 --- a/src/Nethermind/Nethermind.Optimism/OptimismNethermindApi.cs +++ b/src/Nethermind/Nethermind.Optimism/OptimismNethermindApi.cs @@ -1,6 +1,7 @@ // SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only +using Autofac; using Nethermind.Api; using Nethermind.Config; using Nethermind.Logging; @@ -12,15 +13,11 @@ namespace Nethermind.Optimism; public class OptimismNethermindApi : NethermindApi { - public OptimismNethermindApi( - IConfigProvider configProvider, - IJsonSerializer jsonSerializer, - ILogManager logManager, - ChainSpec chainSpec) : base(configProvider, jsonSerializer, logManager, chainSpec) + public OptimismNethermindApi(ILifetimeScope lifetimeScope) : base(lifetimeScope) { } - public IInvalidChainTracker? InvalidChainTracker { get; set; } + public IInvalidChainTracker? InvalidChainTracker => BaseContainer.Resolve(); public OPL1CostHelper? L1CostHelper { get; set; } public OptimismSpecHelper? SpecHelper { get; set; } } diff --git a/src/Nethermind/Nethermind.Optimism/OptimismPlugin.cs b/src/Nethermind/Nethermind.Optimism/OptimismPlugin.cs index 33615392a99..530a4618421 100644 --- a/src/Nethermind/Nethermind.Optimism/OptimismPlugin.cs +++ b/src/Nethermind/Nethermind.Optimism/OptimismPlugin.cs @@ -2,9 +2,9 @@ // SPDX-License-Identifier: LGPL-3.0-only using System; -using System.Linq; using System.Threading.Tasks; using Autofac; +using Autofac.Core; using Nethermind.Api; using Nethermind.Api.Extensions; using Nethermind.Consensus; @@ -24,17 +24,17 @@ using Nethermind.Consensus.Rewards; using Nethermind.Consensus.Validators; using Nethermind.Core; +using Nethermind.Core.Container; using Nethermind.Merge.Plugin.Synchronization; using Nethermind.HealthChecks; -using Nethermind.Serialization.Json; +using Nethermind.Init.Steps; using Nethermind.Specs.ChainSpecStyle; using Nethermind.Serialization.Rlp; using Nethermind.Optimism.Rpc; -using Nethermind.Synchronization; namespace Nethermind.Optimism; -public class OptimismPlugin : IConsensusPlugin, ISynchronizationPlugin, IInitializationPlugin +public class OptimismPlugin(ChainSpec chainSpec) : IConsensusPlugin, ISynchronizationPlugin { public string Author => "Nethermind"; public string Name => "Optimism"; @@ -52,14 +52,15 @@ public class OptimismPlugin : IConsensusPlugin, ISynchronizationPlugin, IInitial private IBeaconPivot? _beaconPivot; private BeaconSync? _beaconSync; - public bool ShouldRunSteps(INethermindApi api) => api.ChainSpec.SealEngineType == SealEngineType; - #region IConsensusPlugin public string SealEngineType => Core.SealEngineType.Optimism; public IBlockProductionTrigger DefaultBlockProductionTrigger => NeverProduceTrigger.Instance; + public bool Enabled => chainSpec.SealEngineType == SealEngineType; + public IModule? ContainerModule => new OptimismModule(); + public IBlockProducer InitBlockProducer(ITxSource? additionalTxSource = null) { if (additionalTxSource is not null) @@ -74,13 +75,9 @@ public IBlockProducer InitBlockProducer(ITxSource? additionalTxSource = null) #endregion - public INethermindApi CreateApi(IConfigProvider configProvider, IJsonSerializer jsonSerializer, - ILogManager logManager, ChainSpec chainSpec) => - new OptimismNethermindApi(configProvider, jsonSerializer, logManager, chainSpec); - public void InitTxTypesAndRlpDecoders(INethermindApi api) { - if (ShouldRunSteps(api)) + if (Enabled) { api.RegisterTxType(new OptimismTxDecoder(), Always.Valid); Rlp.RegisterDecoders(typeof(OptimismReceiptMessageDecoder).Assembly, true); @@ -89,7 +86,7 @@ public void InitTxTypesAndRlpDecoders(INethermindApi api) public Task Init(INethermindApi api) { - if (!ShouldRunSteps(api)) + if (!Enabled) return Task.CompletedTask; _api = (OptimismNethermindApi)api; @@ -103,17 +100,9 @@ public Task Init(INethermindApi api) ArgumentNullException.ThrowIfNull(_api.SpecProvider); - _api.PoSSwitcher = new OptimismPoSSwitcher(_api.SpecProvider, _api.ChainSpec.Optimism.BedrockBlockNumber); - - _blockCacheService = new BlockCacheService(); + _blockCacheService = _api.BaseContainer.Resolve(); _api.EthereumEcdsa = new OptimismEthereumEcdsa(_api.EthereumEcdsa); - _api.InvalidChainTracker = _invalidChainTracker = new InvalidChainTracker( - _api.PoSSwitcher, - _api.BlockTree, - _blockCacheService, - _api.LogManager); - _api.DisposeStack.Push(_invalidChainTracker); - + _invalidChainTracker = _api.BaseContainer.Resolve(); _api.FinalizationManager = _blockFinalizationManager = new ManualBlockFinalizationManager(); _api.RewardCalculatorSource = NoBlockRewards.Instance; @@ -127,63 +116,25 @@ public Task Init(INethermindApi api) public Task InitSynchronization() { - if (_api is null || !ShouldRunSteps(_api)) + if (_api is null || !Enabled) return Task.CompletedTask; - ArgumentNullException.ThrowIfNull(_api.SpecProvider); - ArgumentNullException.ThrowIfNull(_api.BlockTree); - ArgumentNullException.ThrowIfNull(_api.DbProvider); - ArgumentNullException.ThrowIfNull(_api.PeerDifficultyRefreshPool); - ArgumentNullException.ThrowIfNull(_api.SyncPeerPool); - ArgumentNullException.ThrowIfNull(_api.NodeStatsManager); ArgumentNullException.ThrowIfNull(_api.BlockchainProcessor); - ArgumentNullException.ThrowIfNull(_api.BetterPeerStrategy); - - ArgumentNullException.ThrowIfNull(_blockCacheService); ArgumentNullException.ThrowIfNull(_invalidChainTracker); _invalidChainTracker.SetupBlockchainProcessorInterceptor(_api.BlockchainProcessor); - _peerRefresher = new PeerRefresher(_api.PeerDifficultyRefreshPool, _api.TimerFactory, _api.LogManager); - _api.DisposeStack.Push((PeerRefresher)_peerRefresher); - - _beaconPivot = new BeaconPivot(_syncConfig, _api.DbProvider.MetadataDb, _api.BlockTree, _api.PoSSwitcher, _api.LogManager); - _beaconSync = new BeaconSync(_beaconPivot, _api.BlockTree, _syncConfig, _blockCacheService, _api.PoSSwitcher, _api.LogManager); - _api.BetterPeerStrategy = new MergeBetterPeerStrategy(_api.BetterPeerStrategy, _api.PoSSwitcher, _beaconPivot, _api.LogManager); - _api.Pivot = _beaconPivot; - - ContainerBuilder builder = new ContainerBuilder(); - ((INethermindApi)_api).ConfigureContainerBuilderFromApiWithNetwork(builder) - .AddSingleton(_beaconSync) - .AddSingleton(_beaconPivot) - .AddSingleton(_api.PoSSwitcher) - .AddSingleton(_mergeConfig) - .AddSingleton(_invalidChainTracker); - - 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.SyncModeSelector, - _api.SyncPeerPool, - _syncConfig, - _blockCacheService, - _beaconSync, - _api.DbProvider.MetadataDb, - _api.LogManager); + _peerRefresher = _api.BaseContainer.Resolve(); + _beaconPivot = _api.BaseContainer.Resolve(); + _beaconSync = _api.BaseContainer.Resolve(); + _ = _api.BaseContainer.Resolve(); return Task.CompletedTask; } public async Task InitRpcModules() { - if (_api is null || !ShouldRunSteps(_api)) + if (_api is null || !Enabled) return; ArgumentNullException.ThrowIfNull(_api.SpecProvider); @@ -289,4 +240,18 @@ public IBlockProducerRunner CreateBlockProducerRunner() public ValueTask DisposeAsync() => ValueTask.CompletedTask; public bool MustInitialize => true; + + private class OptimismModule : Module + { + protected override void Load(ContainerBuilder builder) + { + + base.Load(builder); + builder + .AddModule(new MergeModule()) + .AddSingleton() + .AddSingleton() + .AddIStepsFromAssembly(GetType().Assembly); + } + } } diff --git a/src/Nethermind/Nethermind.Optimism/OptimismPoSSwitcher.cs b/src/Nethermind/Nethermind.Optimism/OptimismPoSSwitcher.cs index 8dd42874806..be848008989 100644 --- a/src/Nethermind/Nethermind.Optimism/OptimismPoSSwitcher.cs +++ b/src/Nethermind/Nethermind.Optimism/OptimismPoSSwitcher.cs @@ -5,9 +5,14 @@ using Nethermind.Core.Specs; using Nethermind.Int256; using Nethermind.Optimism; +using Nethermind.Specs.ChainSpecStyle; public class OptimismPoSSwitcher(ISpecProvider specProvider, long bedrockBlockNumber) : IPoSSwitcher { + public OptimismPoSSwitcher(ISpecProvider specProvider, ChainSpec chainSpec) : this(specProvider, chainSpec.Optimism.BedrockBlockNumber) + { + } + public UInt256? TerminalTotalDifficulty => specProvider.TerminalTotalDifficulty; public UInt256? FinalTotalDifficulty => TerminalTotalDifficulty; diff --git a/src/Nethermind/Nethermind.Runner.Test/Ethereum/ContextWithMocks.cs b/src/Nethermind/Nethermind.Runner.Test/Ethereum/ContextWithMocks.cs index 9b0a4f49d77..9b03d4b11ed 100644 --- a/src/Nethermind/Nethermind.Runner.Test/Ethereum/ContextWithMocks.cs +++ b/src/Nethermind/Nethermind.Runner.Test/Ethereum/ContextWithMocks.cs @@ -1,12 +1,14 @@ // SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only +#nullable enable +using System; +using System.IO; using System.IO.Abstractions; using Autofac; using Nethermind.Api; using Nethermind.Blockchain; using Nethermind.Blockchain.Filters; -using Nethermind.Blockchain.Find; using Nethermind.Blockchain.Receipts; using Nethermind.Blockchain.Services; using Nethermind.Config; @@ -43,94 +45,95 @@ using Nethermind.Wallet; using Nethermind.Sockets; using Nethermind.Specs; -using Nethermind.Synchronization.SnapSync; using Nethermind.Trie; using NSubstitute; using Nethermind.Blockchain.Blocks; +using Nethermind.Blockchain.Synchronization; +using Nethermind.Consensus.Scheduler; using Nethermind.Core; +using Nethermind.Core.Container; using Nethermind.Facade.Find; +using Nethermind.Runner.Modules; +using Nethermind.Core.Test.Builders; +using Nethermind.Init.Steps; +using Nethermind.Network.Config; +using Nethermind.Network.P2P.Analyzers; namespace Nethermind.Runner.Test.Ethereum { public static class Build { - public static NethermindApi ContextWithMocks() + public static NethermindApi ContextWithMocks(INetworkConfig? networkConfig = null, ISyncConfig? syncConfig = null, Action? containerConfigurer = null) { - var api = new NethermindApi(Substitute.For(), Substitute.For(), LimboLogs.Instance, - new ChainSpec()) - { - Enode = Substitute.For(), - TxPool = Substitute.For(), - Wallet = Substitute.For(), - BlockTree = Substitute.For(), - SyncServer = Substitute.For(), - DbProvider = TestMemDbProvider.Init(), - PeerManager = Substitute.For(), - PeerPool = Substitute.For(), - SpecProvider = Substitute.For(), - EthereumEcdsa = Substitute.For(), - MainBlockProcessor = Substitute.For(), - ReceiptStorage = Substitute.For(), - ReceiptFinder = Substitute.For(), - BlockValidator = Substitute.For(), - RewardCalculatorSource = Substitute.For(), - TxPoolInfoProvider = Substitute.For(), - StaticNodesManager = Substitute.For(), - BloomStorage = Substitute.For(), - Sealer = Substitute.For(), - BlockchainProcessor = Substitute.For(), - BlockProducer = Substitute.For(), - DiscoveryApp = Substitute.For(), - EngineSigner = Substitute.For(), - FileSystem = Substitute.For(), - FilterManager = Substitute.For(), - FilterStore = Substitute.For(), - GrpcServer = Substitute.For(), - HeaderValidator = Substitute.For(), - IpResolver = Substitute.For(), - KeyStore = Substitute.For(), - LogFinder = Substitute.For(), - MonitoringService = Substitute.For(), - ProtocolsManager = Substitute.For(), - ProtocolValidator = Substitute.For(), - RlpxPeer = Substitute.For(), - SealValidator = Substitute.For(), - SessionMonitor = Substitute.For(), - WorldState = Substitute.For(), - StateReader = Substitute.For(), - TransactionProcessor = Substitute.For(), - TxSender = Substitute.For(), - BlockProcessingQueue = Substitute.For(), - EngineSignerStore = Substitute.For(), - NodeStatsManager = Substitute.For(), - RpcModuleProvider = Substitute.For(), - SyncPeerPool = Substitute.For(), - PeerDifficultyRefreshPool = Substitute.For(), - WebSocketsManager = Substitute.For(), - ChainLevelInfoRepository = Substitute.For(), - TrieStore = Substitute.For(), - BlockProducerEnvFactory = Substitute.For(), - TransactionComparerProvider = Substitute.For(), - GasPriceOracle = Substitute.For(), - EthSyncingInfo = Substitute.For(), - HealthHintService = Substitute.For(), - TxValidator = new TxValidator(MainnetSpecProvider.Instance.ChainId), - UnclesValidator = Substitute.For(), - BlockProductionPolicy = Substitute.For(), - BetterPeerStrategy = Substitute.For(), - ReceiptMonitor = Substitute.For(), - BadBlocksStore = Substitute.For(), + ContainerBuilder containerBuilder = new ContainerBuilder() + .AddInstance(Substitute.For()) + .AddInstance(Substitute.For()) + .AddInstance(LimboLogs.Instance) + .AddSingleton() + .AddModule(new BaseModule()) + .AddModule(new CoreModule()) + .AddModule(new RunnerModule()) + .AddModule(new NetworkModule(networkConfig ?? new NetworkConfig(), syncConfig ?? new SyncConfig())) + .AddModule(new DbModule()) + .AddInstance(Substitute.For()) + .AddInstance(Substitute.For()); // need more complete chainspec to use ISpecProvider - ApiWithNetworkServiceContainer = new ContainerBuilder() - .AddSingleton(Substitute.For()) - .AddSingleton(Substitute.For()) - .AddSingleton(Substitute.For()) - .Build(), - }; + containerConfigurer?.Invoke(containerBuilder); + IContainer container = containerBuilder.Build(); + var api = container.Resolve(); + api.Enode = Substitute.For(); + api.TxPool = Substitute.For(); + api.Wallet = Substitute.For(); + api.BlockTree = Substitute.For(); + api.DbProvider = TestMemDbProvider.Init(); + api.EthereumEcdsa = Substitute.For(); + api.MainBlockProcessor = Substitute.For(); + api.ReceiptStorage = Substitute.For(); + api.ReceiptFinder = Substitute.For(); + api.BlockValidator = Substitute.For(); + api.RewardCalculatorSource = Substitute.For(); + api.TxPoolInfoProvider = Substitute.For(); + api.BloomStorage = Substitute.For(); + api.Sealer = Substitute.For(); + api.BlockchainProcessor = Substitute.For(); + api.BlockProducer = Substitute.For(); + api.EngineSigner = Substitute.For(); + api.FileSystem = Substitute.For(); + api.FilterManager = Substitute.For(); + api.FilterStore = Substitute.For(); + api.GrpcServer = Substitute.For(); + api.HeaderValidator = Substitute.For(); + api.IpResolver = Substitute.For(); + api.KeyStore = Substitute.For(); + api.LogFinder = Substitute.For(); + api.MonitoringService = Substitute.For(); + api.SealValidator = Substitute.For(); + api.WorldState = Substitute.For(); + api.StateReader = Substitute.For(); + api.TransactionProcessor = Substitute.For(); + api.TxSender = Substitute.For(); + api.BlockProcessingQueue = Substitute.For(); + api.EngineSignerStore = Substitute.For(); + api.RpcModuleProvider = Substitute.For(); + api.WebSocketsManager = Substitute.For(); + api.ChainLevelInfoRepository = Substitute.For(); + api.TrieStore = Substitute.For(); + api.BlockProducerEnvFactory = Substitute.For(); + api.TransactionComparerProvider = Substitute.For(); + api.GasPriceOracle = Substitute.For(); + api.HealthHintService = Substitute.For(); + api.TxValidator = new TxValidator(MainnetSpecProvider.Instance.ChainId); + api.UnclesValidator = Substitute.For(); + api.BlockProductionPolicy = Substitute.For(); + api.ReceiptMonitor = Substitute.For(); + api.BadBlocksStore = Substitute.For(); api.WorldStateManager = new ReadOnlyWorldStateManager(api.DbProvider, Substitute.For(), LimboLogs.Instance); api.NodeStorageFactory = new NodeStorageFactory(INodeStorage.KeyScheme.HalfPath, LimboLogs.Instance); - return api; + api.NodeKey = new ProtectedPrivateKey(TestItem.PrivateKeyA, Path.GetTempPath()); + api.ConfigProvider.GetConfig().Returns(syncConfig ?? new SyncConfig()); // The default get config substitute set nullable string to empty string causing issues. + + return (NethermindApi)api; } } } diff --git a/src/Nethermind/Nethermind.Runner.Test/Ethereum/Steps/EthereumStepsManagerTests.cs b/src/Nethermind/Nethermind.Runner.Test/Ethereum/Steps/EthereumStepsManagerTests.cs index 1a058d86cfa..6400a9b64f5 100644 --- a/src/Nethermind/Nethermind.Runner.Test/Ethereum/Steps/EthereumStepsManagerTests.cs +++ b/src/Nethermind/Nethermind.Runner.Test/Ethereum/Steps/EthereumStepsManagerTests.cs @@ -4,15 +4,15 @@ using System; using System.Threading; using System.Threading.Tasks; +using Autofac; +using Autofac.Core; using FluentAssertions; using FluentAssertions.Execution; using Nethermind.Api; -using Nethermind.Config; -using Nethermind.Consensus.AuRa.InitializationSteps; +using Nethermind.Core.Container; using Nethermind.Init.Steps; using Nethermind.Logging; -using Nethermind.Serialization.Json; -using Nethermind.Specs.ChainSpecStyle; +using Nethermind.Runner.Modules; using NUnit.Framework; namespace Nethermind.Runner.Test.Ethereum.Steps @@ -20,31 +20,11 @@ namespace Nethermind.Runner.Test.Ethereum.Steps [TestFixture, Parallelizable(ParallelScope.All)] public class EthereumStepsManagerTests { - [Test] - public async Task When_no_assemblies_defined() - { - NethermindApi runnerContext = CreateNethermindApi(); - - IEthereumStepsLoader stepsLoader = new EthereumStepsLoader(); - EthereumStepsManager stepsManager = new EthereumStepsManager( - stepsLoader, - runnerContext, - LimboLogs.Instance); - - using CancellationTokenSource source = new CancellationTokenSource(TimeSpan.FromSeconds(1)); - await stepsManager.InitializeAll(source.Token); - } - [Test] public async Task With_steps_from_here() { - NethermindApi runnerContext = CreateNethermindApi(); - - IEthereumStepsLoader stepsLoader = new EthereumStepsLoader(GetType().Assembly); - EthereumStepsManager stepsManager = new EthereumStepsManager( - stepsLoader, - runnerContext, - LimboLogs.Instance); + IContainer runnerContext = CreateNethermindApi(); + EthereumStepsManager stepsManager = runnerContext.Resolve(); using CancellationTokenSource source = new CancellationTokenSource(TimeSpan.FromSeconds(1)); @@ -65,13 +45,8 @@ public async Task With_steps_from_here() [Retry(3)] public async Task With_steps_from_here_AuRa() { - AuRaNethermindApi runnerContext = CreateAuraApi(); - - IEthereumStepsLoader stepsLoader = new EthereumStepsLoader(GetType().Assembly); - EthereumStepsManager stepsManager = new EthereumStepsManager( - stepsLoader, - runnerContext, - LimboLogs.Instance); + IContainer runnerContext = CreateAuraApi(); + EthereumStepsManager stepsManager = runnerContext.Resolve(); using CancellationTokenSource source = new CancellationTokenSource(TimeSpan.FromSeconds(5)); @@ -88,13 +63,8 @@ public async Task With_steps_from_here_AuRa() [Test] public async Task With_failing_steps() { - NethermindApi runnerContext = CreateNethermindApi(); - - IEthereumStepsLoader stepsLoader = new EthereumStepsLoader(GetType().Assembly); - EthereumStepsManager stepsManager = new EthereumStepsManager( - stepsLoader, - runnerContext, - LimboLogs.Instance); + IContainer runnerContext = CreateNethermindApi(); + EthereumStepsManager stepsManager = runnerContext.Resolve(); using CancellationTokenSource source = new CancellationTokenSource(TimeSpan.FromSeconds(2)); @@ -111,10 +81,40 @@ public async Task With_failing_steps() } } - private static NethermindApi CreateNethermindApi() => - new(new ConfigProvider(), new EthereumJsonSerializer(), LimboLogs.Instance, new ChainSpec()); - private static AuRaNethermindApi CreateAuraApi() => - new(new ConfigProvider(), new EthereumJsonSerializer(), LimboLogs.Instance, new ChainSpec()); + private static ContainerBuilder CreateBaseContainerBuilder() + { + return new ContainerBuilder() + .AddInstance(LimboLogs.Instance) + .AddModule(new BaseModule()) + .AddModule(new RunnerModule()); + } + + private static IContainer CreateEmptyContainer() + { + return CreateBaseContainerBuilder() + .Build(); + } + + private static IContainer CreateNethermindApi() + { + return CreateBaseContainerBuilder() + .AddIStep(typeof(StepLong)) + .AddIStep(typeof(StepForever)) + .AddIStep(typeof(StepA)) + .AddIStep(typeof(StepB)) + .AddIStep(typeof(StepCStandard)) + .Build(); + } + private static IContainer CreateAuraApi() + { + return CreateBaseContainerBuilder() + .AddIStep(typeof(StepLong)) + .AddIStep(typeof(StepForever)) + .AddIStep(typeof(StepA)) + .AddIStep(typeof(StepB)) + .AddIStep(typeof(StepCAuRa)) + .Build(); + } } public class StepLong : IStep @@ -187,7 +187,7 @@ public virtual Task Execute(CancellationToken cancellationToken) /// public class StepCAuRa : StepC { - public StepCAuRa(AuRaNethermindApi runnerContext) + public StepCAuRa() { } @@ -199,7 +199,7 @@ public override async Task Execute(CancellationToken cancellationToken) public class StepCStandard : StepC { - public StepCStandard(NethermindApi runnerContext) + public StepCStandard() { } } diff --git a/src/Nethermind/Nethermind.Runner.Test/EthereumRunnerTests.cs b/src/Nethermind/Nethermind.Runner.Test/EthereumRunnerTests.cs index 2b2c1afbcf9..5b1f3c99b34 100644 --- a/src/Nethermind/Nethermind.Runner.Test/EthereumRunnerTests.cs +++ b/src/Nethermind/Nethermind.Runner.Test/EthereumRunnerTests.cs @@ -7,13 +7,21 @@ using System.Collections.Concurrent; using System.IO; using System.IO.Abstractions; +using System.Net; using System.Runtime.Loader; using System.Threading; using System.Threading.Tasks; +using Autofac; using Nethermind.Api; +using Nethermind.Blockchain.Receipts; using Nethermind.Blockchain.Synchronization; using Nethermind.Config; +using Nethermind.Consensus.Scheduler; +using Nethermind.Consensus.Validators; +using Nethermind.Core.Test.Builders; using Nethermind.Core.Test.IO; +using Nethermind.Crypto; +using Nethermind.Db; using Nethermind.Db.Rocks.Config; using Nethermind.EthStats; using Nethermind.JsonRpc; @@ -23,8 +31,19 @@ using Nethermind.Network.Config; using Nethermind.Runner.Ethereum; using Nethermind.Db.Blooms; +using Nethermind.Init.Steps; +using Nethermind.Network; +using Nethermind.Network.Discovery; +using Nethermind.Network.Rlpx; using Nethermind.Runner.Ethereum.Api; +using Nethermind.State; +using Nethermind.Synchronization; +using Nethermind.Synchronization.ParallelSync; +using Nethermind.Synchronization.Peers; +using Nethermind.Trie; +using Nethermind.Trie.Pruning; using Nethermind.TxPool; +using NSubstitute; using NUnit.Framework; namespace Nethermind.Runner.Test; @@ -96,6 +115,65 @@ public async Task Smoke_cancel((string file, ConfigProvider configProvider) test await SmokeTest(testCase.configProvider, testIndex, 30430, true); } + [TestCaseSource(nameof(ChainSpecRunnerTests))] + public void BuildTest((string file, ConfigProvider configProvider) testCase, int _) + { + if (testCase.configProvider is null) + { + // some weird thing, not worth investigating + return; + } + + using IContainer container = new ApiBuilder(testCase.configProvider, Substitute.For(), LimboLogs.Instance) + .Create(Array.Empty()); + + { + // Ideally, we don't have any of there blocks. + INethermindApi nethermindApi = container.Resolve(); + nethermindApi.BlockTree = Build.A.BlockTree().OfChainLength(1).TestObject; + nethermindApi.StateReader = Substitute.For(); + nethermindApi.NodeStorageFactory = new NodeStorageFactory(INodeStorage.KeyScheme.Current, LimboLogs.Instance); + nethermindApi.DbProvider = TestMemDbProvider.Init(); + nethermindApi.ReceiptStorage = Substitute.For(); + nethermindApi.ReceiptFinder = Substitute.For(); + nethermindApi.BlockValidator = Substitute.For(); + nethermindApi.NodeKey = new ProtectedPrivateKey(TestItem.PrivateKeyA, Path.GetTempPath()); + nethermindApi.EthereumEcdsa = new EthereumEcdsa(0); + nethermindApi.BackgroundTaskScheduler = Substitute.For(); + nethermindApi.TxPool = Substitute.For(); + nethermindApi.TrieStore = Substitute.For(); + + IIPResolver ipResolver = Substitute.For(); + ipResolver.ExternalIp.Returns(IPAddress.Loopback); + nethermindApi.IpResolver = ipResolver; + + INetworkConfig networkConfig = container.Resolve(); + networkConfig.ExternalIp = "127.0.0.1"; + networkConfig.LocalIp = "127.0.0.1"; + } + + container.Resolve(); + foreach (StepInfo loadStep in container.Resolve().LoadSteps()) + { + container.Resolve(loadStep.StepType); + } + + // TODO: Ideally, these should not be here and declared in the constructor of the steps. But until we stop + // resolving things manually because of steps manually updating api, we can't really do much. + container.Resolve(); + container.Resolve(); + container.Resolve(); + container.Resolve(); + container.Resolve(); + container.Resolve(); + container.Resolve(); + container.Resolve(); + container.Resolve>(); + container.Resolve(); + container.Resolve(); + container.Resolve(); + } + private static async Task SmokeTest(ConfigProvider configProvider, int testIndex, int basePort, bool cancel = false) { Type type1 = typeof(ITxPoolConfig); @@ -128,9 +206,9 @@ private static async Task SmokeTest(ConfigProvider configProvider, int testIndex networkConfig.P2PPort = port; networkConfig.DiscoveryPort = port; - INethermindApi nethermindApi = new ApiBuilder(configProvider, LimboLogs.Instance).Create(); - nethermindApi.RpcModuleProvider = new RpcModuleProvider(new FileSystem(), new JsonRpcConfig(), LimboLogs.Instance); - EthereumRunner runner = new(nethermindApi); + IContainer container = new ApiBuilder(configProvider, Substitute.For(), LimboLogs.Instance).Create(Array.Empty()); + container.Resolve().RpcModuleProvider = new RpcModuleProvider(new FileSystem(), new JsonRpcConfig(), LimboLogs.Instance); + EthereumRunner runner = container.Resolve(); using CancellationTokenSource cts = new(); diff --git a/src/Nethermind/Nethermind.Runner.Test/Modules/BaseModuleTests.cs b/src/Nethermind/Nethermind.Runner.Test/Modules/BaseModuleTests.cs new file mode 100644 index 00000000000..c14a0323b49 --- /dev/null +++ b/src/Nethermind/Nethermind.Runner.Test/Modules/BaseModuleTests.cs @@ -0,0 +1,58 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using Autofac; +using FluentAssertions; +using Nethermind.Api; +using Nethermind.Config; +using Nethermind.Core.Container; +using Nethermind.Logging; +using Nethermind.Runner.Modules; +using Nethermind.Serialization.Json; +using Nethermind.Specs.ChainSpecStyle; +using NSubstitute; +using NUnit.Framework; + +namespace Nethermind.Runner.Test.Modules; + +public class BaseModuleTests +{ + [Test] + public void Can_Resolve() + { + IConfigProvider configProvider = Substitute.For(); + IProcessExitSource processExitSource = Substitute.For(); + ChainSpec chainSpec = new(); + IJsonSerializer jsonSerializer = new EthereumJsonSerializer(); + ILogManager logManager = Substitute.For(); + + configProvider.GetConfig().Returns(new InitConfig()); + logManager.GetClassLogger(typeof(TestClass)).Returns(LimboLogs.Instance.GetClassLogger()); + + using IContainer container = new ContainerBuilder() + .AddInstance(configProvider) + .AddInstance(processExitSource) + .AddInstance(chainSpec) + .AddInstance(jsonSerializer) + .AddInstance(logManager) + .AddModule(new BaseModule()) + .AddSingleton() + .Build(); + + TestClass testObj = container.Resolve(); + testObj.Logger.Should().NotBeNull(); + testObj.InitConfig.Should().NotBeNull(); + } + + private class TestClass + { + public IInitConfig InitConfig; + public ILogger Logger; + + public TestClass(IInitConfig initConfig, ILogger logger) + { + InitConfig = initConfig; + Logger = logger; + } + } +} diff --git a/src/Nethermind/Nethermind.Runner/Ethereum/Api/ApiBuilder.cs b/src/Nethermind/Nethermind.Runner/Ethereum/Api/ApiBuilder.cs index 9d17ac28787..9f06dd8a3b4 100644 --- a/src/Nethermind/Nethermind.Runner/Ethereum/Api/ApiBuilder.cs +++ b/src/Nethermind/Nethermind.Runner/Ethereum/Api/ApiBuilder.cs @@ -4,15 +4,18 @@ using System; using System.Collections.Generic; using System.IO; -using System.Linq; using System.Threading; +using Autofac; using Nethermind.Api; using Nethermind.Api.Extensions; +using Nethermind.Blockchain.Synchronization; using Nethermind.Config; -using Nethermind.Consensus; using Nethermind.Core; -using Nethermind.Facade.Eth.RpcTransaction; +using Nethermind.Core.Container; +using Nethermind.Init.Steps; using Nethermind.Logging; +using Nethermind.Network.Config; +using Nethermind.Runner.Modules; using Nethermind.Serialization.Json; using Nethermind.Specs.ChainSpecStyle; @@ -23,22 +26,21 @@ public class ApiBuilder private readonly IConfigProvider _configProvider; private readonly IJsonSerializer _jsonSerializer; private readonly ILogManager _logManager; - private readonly Nethermind.Logging.ILogger _logger; + private readonly ILogger _logger; + private readonly IProcessExitSource _processExitSource; private readonly IInitConfig _initConfig; - public ApiBuilder(IConfigProvider configProvider, ILogManager logManager) + public ApiBuilder(IConfigProvider configProvider, IProcessExitSource processExitSource, ILogManager logManager) { _logManager = logManager ?? throw new ArgumentNullException(nameof(logManager)); _logger = _logManager.GetClassLogger(); _configProvider = configProvider ?? throw new ArgumentNullException(nameof(configProvider)); _initConfig = configProvider.GetConfig(); + _processExitSource = processExitSource; _jsonSerializer = new EthereumJsonSerializer(); } - public INethermindApi Create(params IConsensusPlugin[] consensusPlugins) => - Create((IEnumerable)consensusPlugins); - - public INethermindApi Create(IEnumerable consensusPlugins) + public IContainer Create(IEnumerable plugins) { ChainSpec chainSpec = LoadChainSpec(_jsonSerializer); bool wasCreated = Interlocked.CompareExchange(ref _apiCreated, 1, 0) == 1; @@ -47,19 +49,58 @@ public INethermindApi Create(IEnumerable consensusPlugins) throw new NotSupportedException("Creation of multiple APIs not supported."); } - string engine = chainSpec.SealEngineType; - IConsensusPlugin? enginePlugin = consensusPlugins.FirstOrDefault(p => p.SealEngineType == engine); + ContainerBuilder containerBuilder = new ContainerBuilder() + .AddInstance(_configProvider) + .AddInstance(_processExitSource) + .AddInstance(_jsonSerializer) + .AddInstance(_logManager) + .AddInstance(chainSpec) + .AddModule(new BaseModule()) + .AddModule(new CoreModule()) + .AddModule(new RunnerModule()) + .AddModule(new NetworkModule(_configProvider.GetConfig(), _configProvider.GetConfig())) + .AddModule(new DbModule()); + ApplyPluginModule(plugins, chainSpec, containerBuilder); + + return containerBuilder.Build(); + } - INethermindApi nethermindApi = - enginePlugin?.CreateApi(_configProvider, _jsonSerializer, _logManager, chainSpec) ?? - new NethermindApi(_configProvider, _jsonSerializer, _logManager, chainSpec); - nethermindApi.SealEngineType = engine; - nethermindApi.SpecProvider = new ChainSpecBasedSpecProvider(chainSpec, _logManager); - nethermindApi.GasLimitCalculator = new FollowOtherMiners(nethermindApi.SpecProvider); + private void ApplyPluginModule(IEnumerable plugins, ChainSpec chainSpec, ContainerBuilder containerBuilder) + { + ContainerBuilder pluginLoaderBuilder = new ContainerBuilder() + .AddInstance(_configProvider) + .AddInstance(_processExitSource) + .AddInstance(_jsonSerializer) + .AddInstance(_logManager) + .AddInstance(chainSpec) + .AddModule(new BaseModule()); + + foreach (Type plugin in plugins) + { + pluginLoaderBuilder.RegisterType(plugin) + .As() + .ExternallyOwned(); + } - SetLoggerVariables(chainSpec); + // This is just to load the plugins in a way that its constructor injectable with related config. + // The plugins need to have enough information in order for it to know that it should enable itself or not. + using IContainer pluginLoader = pluginLoaderBuilder.Build(); - return nethermindApi; + foreach (INethermindPlugin nethermindPlugin in pluginLoader.Resolve>()) + { + if (_logger.IsDebug) _logger.Warn($"Plugin {nethermindPlugin.Name} enabled: {nethermindPlugin.Enabled}"); + if (!nethermindPlugin.Enabled) + { + continue; + } + + containerBuilder.AddInstance(nethermindPlugin); + + if (nethermindPlugin.ContainerModule is Module module) + { + containerBuilder.AddModule(nethermindPlugin.ContainerModule); + } + } } private int _apiCreated; @@ -81,6 +122,7 @@ private ChainSpec LoadChainSpec(IJsonSerializer ethereumJsonSerializer) IChainSpecLoader loader = new ChainSpecLoader(ethereumJsonSerializer); ChainSpec chainSpec = loader.LoadEmbeddedOrFromFile(chainSpecFile, _logger); + SetLoggerVariables(chainSpec); return chainSpec; } diff --git a/src/Nethermind/Nethermind.Runner/Ethereum/EthereumRunner.cs b/src/Nethermind/Nethermind.Runner/Ethereum/EthereumRunner.cs index 5e79b03e1cb..6c88d0731a0 100644 --- a/src/Nethermind/Nethermind.Runner/Ethereum/EthereumRunner.cs +++ b/src/Nethermind/Nethermind.Runner/Ethereum/EthereumRunner.cs @@ -2,13 +2,9 @@ // SPDX-License-Identifier: LGPL-3.0-only using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; using System.Threading; using System.Threading.Tasks; using Nethermind.Api; -using Nethermind.Api.Extensions; using Nethermind.Core; using Nethermind.Init.Steps; using Nethermind.Logging; @@ -18,40 +14,26 @@ namespace Nethermind.Runner.Ethereum public class EthereumRunner { private readonly INethermindApi _api; - private readonly ILogger _logger; + private readonly EthereumStepsManager _stepManager; - public EthereumRunner(INethermindApi api) + public EthereumRunner(INethermindApi api, EthereumStepsManager stepsManager, ILogger logger) { _api = api; - _logger = api.LogManager.GetClassLogger(); + _stepManager = stepsManager; + _logger = logger; } public async Task Start(CancellationToken cancellationToken) { if (_logger.IsDebug) _logger.Debug("Initializing Ethereum"); - EthereumStepsLoader stepsLoader = new EthereumStepsLoader(GetStepsAssemblies(_api)); - EthereumStepsManager stepsManager = new EthereumStepsManager(stepsLoader, _api, _api.LogManager); - await stepsManager.InitializeAll(cancellationToken); + await _stepManager.InitializeAll(cancellationToken); string infoScreen = ThisNodeInfo.BuildNodeInfoScreen(); if (_logger.IsInfo) _logger.Info(infoScreen); } - private IEnumerable GetStepsAssemblies(INethermindApi api) - { - yield return typeof(IStep).Assembly; - yield return GetType().Assembly; - IEnumerable enabledInitializationPlugins = - _api.Plugins.OfType().Where(p => p.ShouldRunSteps(api)); - - foreach (IInitializationPlugin initializationPlugin in enabledInitializationPlugins) - { - yield return initializationPlugin.GetType().Assembly; - } - } - public async Task StopAsync() { Stop(() => _api.SessionMonitor?.Stop(), "Stopping session monitor"); @@ -66,11 +48,6 @@ public async Task StopAsync() Task rlpxPeerTask = Stop(() => _api.RlpxPeer?.Shutdown(), "Stopping rlpx peer"); await Task.WhenAll(discoveryStopTask, rlpxPeerTask, peerManagerTask, synchronizerTask, syncPeerPoolTask, peerPoolTask, blockchainProcessorTask, blockProducerTask); - foreach (INethermindPlugin plugin in _api.Plugins) - { - await Stop(async () => await plugin.DisposeAsync(), $"Disposing plugin {plugin.Name}"); - } - while (_api.DisposeStack.Count != 0) { IAsyncDisposable disposable = _api.DisposeStack.Pop(); diff --git a/src/Nethermind/Nethermind.Runner/Modules/BaseModule.cs b/src/Nethermind/Nethermind.Runner/Modules/BaseModule.cs new file mode 100644 index 00000000000..416a7e454a1 --- /dev/null +++ b/src/Nethermind/Nethermind.Runner/Modules/BaseModule.cs @@ -0,0 +1,130 @@ +// SPDX-FileCopyrightText: 2024 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 Autofac.Core; +using Autofac.Core.Activators.Delegate; +using Autofac.Core.Lifetime; +using Autofac.Core.Registration; +using Autofac.Core.Resolving.Pipeline; +using Autofac.Features.ResolveAnything; +using Nethermind.Api; +using Nethermind.Config; +using Nethermind.Core; +using Nethermind.Core.Container; +using Nethermind.Core.Specs; +using Nethermind.Core.Timers; +using Nethermind.Crypto; +using Nethermind.Logging; +using Nethermind.Serialization.Json; +using Nethermind.Specs.ChainSpecStyle; +using Module = Autofac.Module; + +namespace Nethermind.Runner.Modules; + +/// +/// Basic common behaviour such as instrumentation and system related stuff. Should be completely compatible in all +/// situation and can be run in tests. Probably should be called `PrePluginModule` as it is also run without +/// having plugins. +/// +public class BaseModule : Module +{ + protected override void Load(ContainerBuilder builder) + { + base.Load(builder); + + builder.RegisterSource(new ConfigRegistrationSource()); + LoggerMiddleware.Configure(builder); + + builder + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddInstance(TimerFactory.Default) + .AddInstance(Timestamper.Default) + .AddSingleton(); + } + + /// + /// Dynamically resolve IConfig + /// + private class ConfigRegistrationSource : IRegistrationSource + { + public IEnumerable RegistrationsFor(Service service, Func> registrationAccessor) + { + IServiceWithType swt = service as IServiceWithType; + if (swt == null || !typeof(IConfig).IsAssignableFrom(swt.ServiceType)) + { + // It's not a request for the base handler type, so skip it. + return Enumerable.Empty(); + } + + // Dynamically resolve IConfig + ComponentRegistration registration = new ComponentRegistration( + Guid.NewGuid(), + new DelegateActivator(swt.ServiceType, (c, p) => + { + IConfigProvider configProvider = c.Resolve(); + object config = typeof(IConfigProvider) + .GetMethod("GetConfig") + .MakeGenericMethod(swt.ServiceType) + .Invoke(configProvider, new object[] { }); + return config; + }), + new RootScopeLifetime(), + InstanceSharing.Shared, + InstanceOwnership.OwnedByLifetimeScope, + new[] { service }, + new Dictionary()); + + return new IComponentRegistration[] { registration }; + } + + public bool IsAdapterForIndividualComponents => false; + } + + /// + /// For automatically resolving ILogger + /// + private class LoggerMiddleware : IResolveMiddleware + { + private LoggerMiddleware() + { + } + + public PipelinePhase Phase => PipelinePhase.ParameterSelection; + + public void Execute(ResolveRequestContext context, Action next) + { + // Add our parameters. + context.ChangeParameters(context.Parameters.Union( + new[] + { + new ResolvedParameter( + (p, i) => p.ParameterType == typeof(ILogger), + (p, i) => i.Resolve().GetClassLogger(p.Member.DeclaringType) + ), + })); + + // Continue the resolve. + next(context); + } + + public static void Configure(ContainerBuilder builder) + { + LoggerMiddleware loggerMiddleware = new LoggerMiddleware(); + builder.ComponentRegistryBuilder.Registered += (senter, args) => + { + args.ComponentRegistration.PipelineBuilding += (sender2, pipeline) => + { + pipeline.Use(loggerMiddleware); + }; + }; + } + } + +} diff --git a/src/Nethermind/Nethermind.Runner/Modules/CoreModule.cs b/src/Nethermind/Nethermind.Runner/Modules/CoreModule.cs new file mode 100644 index 00000000000..bd3b83b2521 --- /dev/null +++ b/src/Nethermind/Nethermind.Runner/Modules/CoreModule.cs @@ -0,0 +1,47 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using Autofac; +using Nethermind.Api; +using Nethermind.Blockchain; +using Nethermind.Blockchain.Find; +using Nethermind.Consensus; +using Nethermind.Core.Container; +using Nethermind.Crypto; +using Nethermind.Db; +using Nethermind.Trie; +using Nethermind.Trie.Pruning; +using Module = Autofac.Module; + +namespace Nethermind.Runner.Modules; + +/// +/// CoreModule should be something Nethermind specific +/// +public class CoreModule : Module +{ + protected override void Load(ContainerBuilder builder) + { + base.Load(builder); + + builder + .AddSingleton() + .AddSingleton() + .AddInstance(NoPoS.Instance) + .Bind() + .Bind(); + + builder.Register(ctx => + { + var nodeStorageFactory = ctx.Resolve(); + var stateDb = ctx.Resolve().StateDb; + return nodeStorageFactory.WrapKeyValueStore(stateDb); + }) + .As(); + + builder.Register(ctx => ctx.Resolve().AsReadOnly()) + .As(); + + builder.RegisterSource(new FallbackToFieldFromApi()); + } +} diff --git a/src/Nethermind/Nethermind.Runner/Modules/DbModule.cs b/src/Nethermind/Nethermind.Runner/Modules/DbModule.cs new file mode 100644 index 00000000000..d4745e5bf4c --- /dev/null +++ b/src/Nethermind/Nethermind.Runner/Modules/DbModule.cs @@ -0,0 +1,90 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using Autofac; +using Nethermind.Core; +using Nethermind.Db; +using Nethermind.Trie; + +namespace Nethermind.Runner.Modules; + +public class DbModule : Module +{ + protected override void Load(ContainerBuilder builder) + { + base.Load(builder); + + builder + .Register(ctx => + { + INodeStorageFactory nodeStorageFactory = ctx.Resolve(); + IDb stateDb = ctx.Resolve().StateDb; + return nodeStorageFactory.WrapKeyValueStore(stateDb); + }) + .As(); + + // TODO: Have hooks that automatically get these. + // TODO: Make these lazy + 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) + { + ConfigureDatabase(builder, dbName); + } + + // Special case for receipt which uses columns + ConfigureColumnDb(builder, DbNames.Receipts); + } + + private void ConfigureDatabase(ContainerBuilder builder, string dbName) + { + builder + .Register(ctx => + { + IDbProvider? dbProvider = ctx.Resolve(); + return dbProvider.GetDb(dbName); + }) + .Named(dbName) + .Named(dbName) + .Named(dbName) + .Named(dbName); + + builder + .Register(ctx => + { + IDbProvider? dbProvider = ctx.Resolve(); + IDb? db = dbProvider.GetDb(dbName); + return db as ITunableDb ?? new NoopTunableDb(); + }) + .Named(dbName); + } + + private void ConfigureColumnDb(ContainerBuilder builder, string dbName) + { + builder + .Register(ctx => + { + IDbProvider? dbProvider = ctx.Resolve(); + return dbProvider.GetColumnDb(dbName); + }) + .Named>(dbName); + + builder + .Register(ctx => + { + IDbProvider? dbProvider = ctx.Resolve(); + IColumnsDb? db = dbProvider.GetColumnDb(dbName); + return db as ITunableDb ?? new NoopTunableDb(); + }) + .Named(dbName); + } +} diff --git a/src/Nethermind/Nethermind.Runner/Modules/RunnerModule.cs b/src/Nethermind/Nethermind.Runner/Modules/RunnerModule.cs new file mode 100644 index 00000000000..4cb7562d065 --- /dev/null +++ b/src/Nethermind/Nethermind.Runner/Modules/RunnerModule.cs @@ -0,0 +1,25 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using Autofac; +using Nethermind.Core; +using Nethermind.Core.Container; +using Nethermind.Init.Steps; +using Nethermind.Runner.Ethereum; + +namespace Nethermind.Runner.Modules; + +public class RunnerModule : Module +{ + protected override void Load(ContainerBuilder builder) + { + base.Load(builder); + + builder + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddIStepsFromAssembly(typeof(IStep).Assembly) + .AddIStepsFromAssembly(GetType().Assembly); + } +} diff --git a/src/Nethermind/Nethermind.Runner/Program.cs b/src/Nethermind/Nethermind.Runner/Program.cs index fef352adc11..064e38ae738 100644 --- a/src/Nethermind/Nethermind.Runner/Program.cs +++ b/src/Nethermind/Nethermind.Runner/Program.cs @@ -14,6 +14,7 @@ using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; +using Autofac; #if !DEBUG using DotNetty.Common; #endif @@ -176,32 +177,13 @@ private static void Run(string[] args) if (_logger.IsDebug) _logger.Debug($"Nethermind config:{Environment.NewLine}{serializer.Serialize(initConfig, true)}{Environment.NewLine}"); if (_logger.IsInfo) _logger.Info($"RocksDb Version: {DbOnTheRocks.GetRocksDbVersion()}"); - ApiBuilder apiBuilder = new(configProvider, logManager); - - IList plugins = new List(); - foreach (Type pluginType in pluginLoader.PluginTypes) - { - try - { - if (Activator.CreateInstance(pluginType) is INethermindPlugin plugin) - { - plugins.Add(plugin); - } - } - catch (Exception e) - { - if (_logger.IsError) _logger.Error($"Failed to create plugin {pluginType.FullName}", e); - } - } - - INethermindApi nethermindApi = apiBuilder.Create(plugins.OfType()); - ((List)nethermindApi.Plugins).AddRange(plugins); - nethermindApi.ProcessExit = _processExitSource; - + ApiBuilder nethermindContainerBuilder = new(configProvider, _processExitSource, logManager); + IContainer container = nethermindContainerBuilder.Create(pluginLoader.PluginTypes); + EthereumRunner ethereumRunner = null; _appClosed.Reset(); - EthereumRunner ethereumRunner = new(nethermindApi); try { + ethereumRunner = container.Resolve(); await ethereumRunner.Start(_processExitSource.Token); await _processExitSource.ExitTask; diff --git a/src/Nethermind/Nethermind.Shutter/Nethermind.Shutter.csproj b/src/Nethermind/Nethermind.Shutter/Nethermind.Shutter.csproj index 5f7acfe37b8..1f8291a1331 100644 --- a/src/Nethermind/Nethermind.Shutter/Nethermind.Shutter.csproj +++ b/src/Nethermind/Nethermind.Shutter/Nethermind.Shutter.csproj @@ -36,6 +36,7 @@ + diff --git a/src/Nethermind/Nethermind.Shutter/ShutterPlugin.cs b/src/Nethermind/Nethermind.Shutter/ShutterPlugin.cs index 04b6a444699..908db505485 100644 --- a/src/Nethermind/Nethermind.Shutter/ShutterPlugin.cs +++ b/src/Nethermind/Nethermind.Shutter/ShutterPlugin.cs @@ -15,21 +15,24 @@ using System.IO; using Nethermind.Serialization.Json; using System.Threading; +using Autofac; using Nethermind.Config; +using Nethermind.Init.Steps; +using Nethermind.Specs.ChainSpecStyle; namespace Nethermind.Shutter; -public class ShutterPlugin : IConsensusWrapperPlugin, IInitializationPlugin +public class ShutterPlugin(IShutterConfig shutterConfig, IMergeConfig mergeConfig, ChainSpec chainSpec) : IConsensusWrapperPlugin { public string Name => "Shutter"; public string Description => "Shutter plugin for AuRa post-merge chains"; public string Author => "Nethermind"; - public bool Enabled => ShouldRunSteps(_api!); + public bool ConsensusWrapperEnabled => Enabled; + public bool Enabled => shutterConfig!.Enabled && mergeConfig!.Enabled && chainSpec.SealEngineType is SealEngineType.AuRa; + public int Priority => PluginPriorities.Shutter; private INethermindApi? _api; - private IMergeConfig? _mergeConfig; - private IShutterConfig? _shutterConfig; private IBlocksConfig? _blocksConfig; private ShutterApi? _shutterApi; private ILogger _logger; @@ -41,8 +44,6 @@ public Task Init(INethermindApi nethermindApi) { _api = nethermindApi; _blocksConfig = _api.Config(); - _mergeConfig = _api.Config(); - _shutterConfig = _api.Config(); _logger = _api.LogManager.GetClassLogger(); if (_logger.IsInfo) _logger.Info($"Initializing Shutter plugin."); return Task.CompletedTask; @@ -50,7 +51,7 @@ public Task Init(INethermindApi nethermindApi) public Task InitRpcModules() { - if (Enabled) + if (ConsensusWrapperEnabled) { if (_api!.BlockProducer is null) throw new ArgumentNullException(nameof(_api.BlockProducer)); @@ -62,7 +63,7 @@ public Task InitRpcModules() public IBlockProducer InitBlockProducer(IBlockProducerFactory consensusPlugin, ITxSource? txSource) { - if (Enabled) + if (ConsensusWrapperEnabled) { if (_api!.BlockTree is null) throw new ArgumentNullException(nameof(_api.BlockTree)); if (_api.EthereumEcdsa is null) throw new ArgumentNullException(nameof(_api.SpecProvider)); @@ -75,7 +76,7 @@ public IBlockProducer InitBlockProducer(IBlockProducerFactory consensusPlugin, I try { - _shutterConfig!.Validate(); + shutterConfig!.Validate(); } catch (ArgumentException e) { @@ -83,11 +84,11 @@ public IBlockProducer InitBlockProducer(IBlockProducerFactory consensusPlugin, I } Dictionary validatorsInfo = []; - if (_shutterConfig!.ValidatorInfoFile is not null) + if (shutterConfig!.ValidatorInfoFile is not null) { try { - validatorsInfo = LoadValidatorInfo(_shutterConfig!.ValidatorInfoFile); + validatorsInfo = LoadValidatorInfo(shutterConfig!.ValidatorInfoFile); } catch (Exception e) { @@ -105,7 +106,7 @@ public IBlockProducer InitBlockProducer(IBlockProducerFactory consensusPlugin, I _api.SpecProvider, _api.Timestamper, _api.WorldStateManager, - _shutterConfig, + shutterConfig, validatorsInfo, TimeSpan.FromSeconds(_blocksConfig!.SecondsPerSlot) ); @@ -116,13 +117,6 @@ public IBlockProducer InitBlockProducer(IBlockProducerFactory consensusPlugin, I return consensusPlugin.InitBlockProducer(_shutterApi is null ? txSource : _shutterApi.TxSource.Then(txSource)); } - public bool ShouldRunSteps(INethermindApi api) - { - _shutterConfig = api.Config(); - _mergeConfig = api.Config(); - return _shutterConfig!.Enabled && _mergeConfig!.Enabled && api.ChainSpec.SealEngineType is SealEngineType.AuRa; - } - public async ValueTask DisposeAsync() { _cts.Dispose(); @@ -134,4 +128,13 @@ private static Dictionary LoadValidatorInfo(string fp) FileStream fstream = new(fp, FileMode.Open, FileAccess.Read, FileShare.None); return new EthereumJsonSerializer().Deserialize>(fstream); } + + private class ShutterModule : Module + { + protected override void Load(ContainerBuilder builder) + { + base.Load(builder); + builder.AddIStepsFromAssembly(GetType().Assembly); + } + } } diff --git a/src/Nethermind/Nethermind.Synchronization.Test/OldStyleFullSynchronizerTests.cs b/src/Nethermind/Nethermind.Synchronization.Test/OldStyleFullSynchronizerTests.cs index 89bd50a3ca4..030112a8da5 100644 --- a/src/Nethermind/Nethermind.Synchronization.Test/OldStyleFullSynchronizerTests.cs +++ b/src/Nethermind/Nethermind.Synchronization.Test/OldStyleFullSynchronizerTests.cs @@ -2,9 +2,13 @@ // SPDX-License-Identifier: LGPL-3.0-only using System; +using System.Diagnostics; using System.Threading; using System.Threading.Tasks; using Autofac; +using Autofac.Core; +using Autofac.Core.Registration; +using Autofac.Diagnostics; using Autofac.Extensions.DependencyInjection; using FluentAssertions; using Microsoft.Extensions.DependencyInjection; @@ -17,12 +21,16 @@ using Nethermind.Consensus.Validators; using Nethermind.Core; using Nethermind.Core.Collections; +using Nethermind.Core.Container; using Nethermind.Core.Crypto; using Nethermind.Core.Specs; using Nethermind.Core.Test.Builders; using Nethermind.Core.Timers; using Nethermind.Db; +using Nethermind.Init.Steps; using Nethermind.Logging; +using Nethermind.Network.Config; +using Nethermind.Runner.Modules; using Nethermind.Specs; using Nethermind.Specs.ChainSpecStyle; using Nethermind.State; @@ -55,58 +63,39 @@ public async Task Setup() _stateDb = dbProvider.StateDb; _codeDb = dbProvider.CodeDb; _receiptStorage = Substitute.For(); - SyncConfig quickConfig = new() { FastSync = false }; - ITimerFactory timerFactory = Substitute.For(); - NodeStatsManager stats = new(timerFactory, LimboLogs.Instance); - _pool = new SyncPeerPool(_blockTree, stats, new TotalDifficultyBetterPeerStrategy(LimboLogs.Instance), LimboLogs.Instance, 25); - SyncConfig syncConfig = new(); + SyncConfig syncConfig = new() { FastSync = false }; NodeStorage nodeStorage = new NodeStorage(_stateDb); TrieStore trieStore = new(nodeStorage, LimboLogs.Instance); - TotalDifficultyBetterPeerStrategy bestPeerStrategy = new(LimboLogs.Instance); - Pivot pivot = new(syncConfig); IStateReader stateReader = new StateReader(trieStore, _codeDb, 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)); + .AddInstance(dbProvider) + .AddInstance(nodeStorage) + .AddInstance(MainnetSpecProvider.Instance) + .AddInstance(Substitute.For()) + .AddInstance(new NetworkConfig()) + .AddInstance(_blockTree) + .AddInstance(_receiptStorage) + .AddInstance(_receiptStorage) + .AddInstance(syncConfig) + .AddInstance(Always.Valid) + .AddInstance(Always.Valid) + .AddInstance(Substitute.For()) + .AddInstance(new ChainSpec()) + .AddInstance(stateReader) + .AddInstance(Policy.FullGossip) + .AddInstance(LimboLogs.Instance) + .AddModule(new DbModule()) + .AddModule(new NetworkModule(new NetworkConfig(), syncConfig)); IContainer container = builder.Build(); - _synchronizer = container.Resolve(); - - _syncServer = new SyncServer( - trieStore.TrieNodeRlpStore, - _codeDb, - _blockTree, - _receiptStorage, - Always.Valid, - Always.Valid, - _pool, - container.Resolve(), - quickConfig, - Policy.FullGossip, - MainnetSpecProvider.Instance, - LimboLogs.Instance); + _pool = container.Resolve(); + _synchronizer = container.Resolve(); + _syncServer = container.Resolve(); } [TearDown] diff --git a/src/Nethermind/Nethermind.Synchronization.Test/SyncThreadTests.cs b/src/Nethermind/Nethermind.Synchronization.Test/SyncThreadTests.cs index 33e43446a69..ccc272a5179 100644 --- a/src/Nethermind/Nethermind.Synchronization.Test/SyncThreadTests.cs +++ b/src/Nethermind/Nethermind.Synchronization.Test/SyncThreadTests.cs @@ -6,8 +6,6 @@ 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; @@ -34,18 +32,18 @@ using Nethermind.State; using Nethermind.Stats; using Nethermind.Evm.TransactionProcessing; -using Nethermind.Synchronization.Blocks; -using Nethermind.Synchronization.ParallelSync; using Nethermind.Synchronization.Peers; -using Nethermind.Synchronization.Reporting; using Nethermind.Trie.Pruning; using Nethermind.TxPool; using NSubstitute; using NUnit.Framework; using BlockTree = Nethermind.Blockchain.BlockTree; -using Nethermind.Synchronization.SnapSync; using Nethermind.Config; +using Nethermind.Core.Container; using Nethermind.Core.Specs; +using Nethermind.Init.Steps; +using Nethermind.Network.Config; +using Nethermind.Runner.Modules; using Nethermind.Specs.ChainSpecStyle; using Nethermind.Trie; @@ -315,10 +313,6 @@ private SyncTestContext CreateSyncManager(int index) BlockchainProcessor processor = new(tree, blockProcessor, step, stateReader, logManager, BlockchainProcessor.Options.Default); - ITimerFactory timerFactory = Substitute.For(); - NodeStatsManager nodeStatsManager = new(timerFactory, logManager); - SyncPeerPool syncPeerPool = new(tree, nodeStatsManager, new TotalDifficultyBetterPeerStrategy(LimboLogs.Instance), logManager, 25); - WorldState devState = new(trieStore, codeDb, logManager); VirtualMachine devEvm = new(blockhashProvider, specProvider, codeInfoRepository, logManager); TransactionProcessor devTxProcessor = new(specProvider, devState, devEvm, codeInfoRepository, logManager); @@ -358,49 +352,32 @@ private SyncTestContext CreateSyncManager(int index) tree, producer); - TotalDifficultyBetterPeerStrategy bestPeerStrategy = new(LimboLogs.Instance); - Pivot pivot = new(syncConfig); - 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(); + .AddModule(new NetworkModule(new NetworkConfig(), syncConfig)) + .AddModule(new DbModule()) + .AddInstance(dbProvider) + .AddInstance(Substitute.For()) + .AddInstance(new NetworkConfig()) + .AddInstance(new NodeStorage(dbProvider.StateDb)) + .AddInstance(MainnetSpecProvider.Instance) + .AddInstance(tree) + .AddInstance(NullReceiptStorage.Instance) + .AddInstance(NullReceiptStorage.Instance) + .AddInstance(syncConfig) + .AddInstance(blockValidator) + .AddInstance(sealValidator) + .AddInstance(Substitute.For()) + .AddInstance(new ChainSpec()) + .AddInstance(Policy.FullGossip) + .AddInstance(stateReader) + .AddInstance(receiptStorage) + .AddInstance(logManager); - ISyncModeSelector selector = synchronizer.SyncModeSelector; - SyncServer syncServer = new( - trieStore.TrieNodeRlpStore, - codeDb, - tree, - receiptStorage, - Always.Valid, - Always.Valid, - syncPeerPool, - selector, - syncConfig, - Policy.FullGossip, - MainnetSpecProvider.Instance, - logManager); + IContainer container = builder.Build(); + ISynchronizer synchronizer = container.Resolve(); + ISyncPeerPool syncPeerPool = container.Resolve(); + ISyncServer syncServer = container.Resolve(); ManualResetEventSlim waitEvent = new(); tree.NewHeadBlock += (_, _) => waitEvent.Set(); diff --git a/src/Nethermind/Nethermind.Synchronization.Test/SynchronizerTests.cs b/src/Nethermind/Nethermind.Synchronization.Test/SynchronizerTests.cs index 47c721d274c..3e3e1bb9313 100644 --- a/src/Nethermind/Nethermind.Synchronization.Test/SynchronizerTests.cs +++ b/src/Nethermind/Nethermind.Synchronization.Test/SynchronizerTests.cs @@ -9,8 +9,6 @@ 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; @@ -19,11 +17,13 @@ using Nethermind.Consensus.Validators; using Nethermind.Core; using Nethermind.Core.Collections; +using Nethermind.Core.Container; using Nethermind.Core.Crypto; using Nethermind.Core.Specs; using Nethermind.Core.Test.Builders; using Nethermind.Core.Timers; using Nethermind.Db; +using Nethermind.Init.Steps; using Nethermind.Int256; using Nethermind.Logging; using Nethermind.Specs; @@ -31,13 +31,14 @@ using Nethermind.Stats; using Nethermind.Stats.Model; using Nethermind.Merge.Plugin; +using Nethermind.Merge.Plugin.Handlers; using Nethermind.Merge.Plugin.InvalidChainTracker; -using Nethermind.Merge.Plugin.Synchronization; using Nethermind.Merge.Plugin.Test; +using Nethermind.Network.Config; +using Nethermind.Runner.Modules; using Nethermind.Specs.ChainSpecStyle; using Nethermind.State; using Nethermind.Synchronization.Blocks; -using Nethermind.Synchronization.ParallelSync; using Nethermind.Synchronization.Peers; using Nethermind.Trie.Pruning; using NSubstitute; @@ -319,79 +320,55 @@ ISyncConfig GetSyncConfig() => .WithoutSettingHead .TestObject; - ITimerFactory timerFactory = Substitute.For(); - NodeStatsManager stats = new(timerFactory, _logManager); - MergeConfig mergeConfig = new(); if (WithTTD(synchronizerType)) { mergeConfig.TerminalTotalDifficulty = UInt256.MaxValue.ToString(CultureInfo.InvariantCulture); } PoSSwitcher poSSwitcher = new(mergeConfig, syncConfig, dbProvider.MetadataDb, BlockTree, new TestSingleReleaseSpecProvider(Constantinople.Instance), new ChainSpec(), _logManager); - IBeaconPivot beaconPivot = new BeaconPivot(syncConfig, dbProvider.MetadataDb, BlockTree, poSSwitcher, _logManager); - TrieStore trieStore = new(stateDb, LimboLogs.Instance); - TotalDifficultyBetterPeerStrategy totalDifficultyBetterPeerStrategy = new(LimboLogs.Instance); - IBetterPeerStrategy bestPeerStrategy = IsMerge(synchronizerType) - ? new MergeBetterPeerStrategy(totalDifficultyBetterPeerStrategy, poSSwitcher, beaconPivot, LimboLogs.Instance) - : totalDifficultyBetterPeerStrategy; StateReader reader = new StateReader(trieStore, codeDb, LimboLogs.Instance); 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)); + .AddInstance(dbProvider) + .AddInstance(nodeStorage) + .AddInstance(new NetworkConfig()) + .AddInstance(Substitute.For()) + .AddInstance(MainnetSpecProvider.Instance) + .AddInstance(BlockTree) + .AddInstance(NullReceiptStorage.Instance) + .AddInstance(NullReceiptStorage.Instance) + .AddInstance(syncConfig) + .AddInstance(poSSwitcher) + .AddInstance(mergeConfig) + .AddInstance(invalidChainTracker) + .AddInstance(Substitute.For()) + .AddInstance(new ChainSpec()) + .AddInstance(reader) + .AddInstance(Always.Valid) + .AddInstance(Always.Valid) + .AddInstance(Policy.FullGossip) + .AddInstance(new BlockCacheService()) + .AddInstance(_logManager) + .AddModule(new DbModule()) + .AddModule(new NetworkModule(new NetworkConfig(), syncConfig)) + .AddInstance(nodeStorage); if (IsMerge(synchronizerType)) { - builder.RegisterModule(new MergeSynchronizerModule()); + builder.RegisterModule(new MergeNetworkModule()); } IContainer container = builder.Build(); - Synchronizer = container.Resolve(); - SyncServer = new SyncServer( - trieStore.TrieNodeRlpStore, - codeDb, - BlockTree, - NullReceiptStorage.Instance, - Always.Valid, - Always.Valid, - SyncPeerPool, - container.Resolve(), - syncConfig, - Policy.FullGossip, - MainnetSpecProvider.Instance, - _logManager); + Synchronizer = container.Resolve(); + SyncPeerPool = container.Resolve(); + SyncServer = container.Resolve(); SyncPeerPool.Start(); diff --git a/src/Nethermind/Nethermind.Synchronization/Peers/SyncPeerPool.cs b/src/Nethermind/Nethermind.Synchronization/Peers/SyncPeerPool.cs index 2bee35f4e76..13f2a2289c9 100644 --- a/src/Nethermind/Nethermind.Synchronization/Peers/SyncPeerPool.cs +++ b/src/Nethermind/Nethermind.Synchronization/Peers/SyncPeerPool.cs @@ -17,6 +17,7 @@ using Nethermind.Core.Extensions; using Nethermind.Int256; using Nethermind.Logging; +using Nethermind.Network.Config; using Nethermind.Stats; using Nethermind.Stats.Model; using Nethermind.Synchronization.Peers.AllocationStrategies; @@ -59,6 +60,15 @@ public class SyncPeerPool : ISyncPeerPool, IPeerDifficultyRefreshPool private readonly TimeSpan _timeBeforeWakingShallowSleepingPeerUp = TimeSpan.FromMilliseconds(DefaultUpgradeIntervalInMs); private Timer? _upgradeTimer; + public SyncPeerPool(IBlockTree blockTree, + INodeStatsManager nodeStatsManager, + IBetterPeerStrategy betterPeerStrategy, + INetworkConfig networkConfig, + ILogManager logManager) + : this(blockTree, nodeStatsManager, betterPeerStrategy, logManager, networkConfig.ActivePeersMaxCount, networkConfig.PriorityPeersMaxCount) + { + } + public SyncPeerPool(IBlockTree blockTree, INodeStatsManager nodeStatsManager, IBetterPeerStrategy betterPeerStrategy, diff --git a/src/Nethermind/Nethermind.Synchronization/SnapSync/ISnapServer.cs b/src/Nethermind/Nethermind.Synchronization/SnapSync/ISnapServer.cs index b4171153a40..5834b478c1a 100644 --- a/src/Nethermind/Nethermind.Synchronization/SnapSync/ISnapServer.cs +++ b/src/Nethermind/Nethermind.Synchronization/SnapSync/ISnapServer.cs @@ -25,6 +25,8 @@ namespace Nethermind.Synchronization.SnapSync; public interface ISnapServer { + bool IsEnabled { get; } + IOwnedReadOnlyList? GetTrieNodes(IReadOnlyList pathSet, in ValueHash256 rootHash, CancellationToken cancellationToken); IOwnedReadOnlyList GetByteCodes(IReadOnlyList requestedHashes, long byteLimit, CancellationToken cancellationToken); diff --git a/src/Nethermind/Nethermind.Synchronization/SnapSync/SnapServer.cs b/src/Nethermind/Nethermind.Synchronization/SnapSync/SnapServer.cs index e18b9e1e36e..672a24bc530 100644 --- a/src/Nethermind/Nethermind.Synchronization/SnapSync/SnapServer.cs +++ b/src/Nethermind/Nethermind.Synchronization/SnapSync/SnapServer.cs @@ -17,13 +17,16 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Threading; +using Autofac.Features.AttributeFilters; +using Nethermind.Blockchain; +using Nethermind.Blockchain.Synchronization; using Nethermind.Blockchain.Utils; using Nethermind.Core; using Nethermind.Core.Collections; using Nethermind.Core.Crypto; using Nethermind.Core.Extensions; +using Nethermind.Db; using Nethermind.Logging; using Nethermind.Serialization.Rlp; using Nethermind.State; @@ -52,6 +55,15 @@ public class SnapServer : ISnapServer private const long HardResponseByteLimit = 2000000; private const int HardResponseNodeLimit = 100000; + public bool IsEnabled { get; } = true; + + public SnapServer(ISyncConfig syncConfig, IReadOnlyTrieStore trieStore, [KeyFilter(DbNames.Code)] IReadOnlyKeyValueStore codeDb, + IBlockTree blockTree, ILogManager logManager) + : this(trieStore, codeDb, new LastNStateRootTracker(blockTree, 128), logManager) + { + IsEnabled = syncConfig.SnapServingEnabled == true; + } + public SnapServer(IReadOnlyTrieStore trieStore, IReadOnlyKeyValueStore codeDb, ILastNStateRootTracker stateRootTracker, ILogManager logManager) { _store = trieStore ?? throw new ArgumentNullException(nameof(trieStore)); diff --git a/src/Nethermind/Nethermind.Synchronization/SyncServer.cs b/src/Nethermind/Nethermind.Synchronization/SyncServer.cs index 429f27af1be..78f898b6012 100644 --- a/src/Nethermind/Nethermind.Synchronization/SyncServer.cs +++ b/src/Nethermind/Nethermind.Synchronization/SyncServer.cs @@ -9,6 +9,7 @@ using System.Text; using System.Threading; using System.Threading.Tasks; +using Autofac.Features.AttributeFilters; using Nethermind.Blockchain; using Nethermind.Blockchain.Receipts; using Nethermind.Blockchain.Synchronization; @@ -20,6 +21,7 @@ using Nethermind.Core.Collections; using Nethermind.Core.Crypto; using Nethermind.Core.Specs; +using Nethermind.Db; using Nethermind.Int256; using Nethermind.Logging; using Nethermind.Synchronization.FastSync; @@ -54,8 +56,8 @@ public class SyncServer : ISyncServer private BlockHeader? _pivotHeader; public SyncServer( - IReadOnlyKeyValueStore stateDb, - IReadOnlyKeyValueStore codeDb, + [KeyFilter(DbNames.State)] IReadOnlyKeyValueStore stateDb, + [KeyFilter(DbNames.Code)] IReadOnlyKeyValueStore codeDb, IBlockTree blockTree, IReceiptFinder receiptFinder, IBlockValidator blockValidator, diff --git a/src/Nethermind/Nethermind.Synchronization/Synchronizer.cs b/src/Nethermind/Nethermind.Synchronization/Synchronizer.cs index 826406ca9de..9143e6a059f 100644 --- a/src/Nethermind/Nethermind.Synchronization/Synchronizer.cs +++ b/src/Nethermind/Nethermind.Synchronization/Synchronizer.cs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LGPL-3.0-only using System; +using System.Diagnostics; using System.Threading; using System.Threading.Tasks; using Autofac; @@ -9,6 +10,7 @@ using Nethermind.Blockchain.Synchronization; using Nethermind.Config; using Nethermind.Core; +using Nethermind.Core.Container; using Nethermind.Core.Extensions; using Nethermind.Logging; using Nethermind.Stats; @@ -54,8 +56,6 @@ public class Synchronizer( /* sync events are used mainly for managing sync peers reputation */ public event EventHandler? SyncEvent; - public ISyncModeSelector SyncModeSelector => syncModeSelector; - public virtual void Start() { if (!syncConfig.SynchronizationEnabled) @@ -81,12 +81,12 @@ public virtual void Start() if (syncConfig.ExitOnSynced) { - exitSource.WatchForExit(SyncModeSelector, logManager, TimeSpan.FromSeconds(syncConfig.ExitOnSyncedWaitTimeSec)); + exitSource.WatchForExit(syncModeSelector, logManager, TimeSpan.FromSeconds(syncConfig.ExitOnSyncedWaitTimeSec)); } WireMultiSyncModeSelector(); - SyncModeSelector.Changed += syncReport.SyncModeSelectorOnChanged; + syncModeSelector.Changed += syncReport.SyncModeSelectorOnChanged; } private void StartFullSyncComponents() @@ -248,11 +248,11 @@ private void WireMultiSyncModeSelector() public void WireFeedWithModeSelector(ISyncFeed? feed) { if (feed is null) return; - SyncModeSelector.Changed += ((sender, args) => + syncModeSelector.Changed += ((sender, args) => { feed?.SyncModeSelectorOnChanged(args.Current); }); - feed?.SyncModeSelectorOnChanged(SyncModeSelector.Current); + feed?.SyncModeSelectorOnChanged(syncModeSelector.Current); } public void Dispose() diff --git a/src/Nethermind/Nethermind.UPnP.Plugin/UPnPPlugin.cs b/src/Nethermind/Nethermind.UPnP.Plugin/UPnPPlugin.cs index ea06514e3af..adf7abc71ac 100644 --- a/src/Nethermind/Nethermind.UPnP.Plugin/UPnPPlugin.cs +++ b/src/Nethermind/Nethermind.UPnP.Plugin/UPnPPlugin.cs @@ -9,7 +9,7 @@ namespace Nethermind.UPnP.Plugin; -public class UPnPPlugin : INethermindPlugin +public class UPnPPlugin(INetworkConfig networkConfig) : INethermindPlugin { public string Name => "UPnP"; public string Description => "Automatic port forwarding with UPnP"; @@ -22,12 +22,14 @@ public class UPnPPlugin : INethermindPlugin private INetworkConfig _networkConfig = new NetworkConfig(); private ILogger _logger = NullLogger.Instance; + public bool Enabled => networkConfig.EnableUPnP; + public Task Init(INethermindApi api) { _networkConfig = api.Config(); _logger = api.LogManager.GetClassLogger(); - if (_networkConfig.EnableUPnP) + if (Enabled) { Task.Factory.StartNew(RunRefreshLoop, TaskCreationOptions.LongRunning); }