diff --git a/src/Blockcore.sln b/src/Blockcore.sln index 837fd9c39..ca41f8416 100644 --- a/src/Blockcore.sln +++ b/src/Blockcore.sln @@ -135,6 +135,32 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "OpenExo", "OpenExo", "{4B08 EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenExo.Node", "Networks\OpenExo\OpenExo.Node\OpenExo.Node.csproj", "{AAB36899-879B-4098-9060-E69240AB7150}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Persistence", "Persistence", "{64694A14-97E0-4CBC-8032-754F9353B2DD}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Blockcore.Features.BlockStore.Persistence.LevelDb", "Features\Persistence\Blockcore.Features.BlockStore.Persistence.LevelDb\Blockcore.Features.BlockStore.Persistence.LevelDb.csproj", "{AB9A2812-610D-4061-BE71-784AB39FE415}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Blockcore.Features.Consensus.Persistence.LevelDb", "Features\Persistence\Blockcore.Features.Consensus.Persistence.LevelDb\Blockcore.Features.Consensus.Persistence.LevelDb.csproj", "{E4C7723E-F2D1-41A3-A22A-3D5CB3AE6D6C}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Blockcore.Persistence.LevelDb", "Features\Persistence\Blockcore.Persistence.LevelDb\Blockcore.Persistence.LevelDb.csproj", "{7760BAD0-B57D-4A57-95DB-A5C53EED5D54}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Blockcore.Features.Base.Persistence.LevelDb", "Features\Persistence\Blockcore.Features.Base.Persistence.LevelDb\Blockcore.Features.Base.Persistence.LevelDb.csproj", "{5A2AC2B6-0541-4AD2-9BCE-09829C71B3E1}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "LevelDb", "LevelDb", "{640B1C2A-2346-40E6-9755-87B7EB2B3428}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "RocksDb", "RocksDb", "{2A20F4A8-01E8-4C44-A394-65C2DE6FBF28}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Blockcore.Persistence.RocksDb", "Features\Persistence\Blockcore.Persistence.RocksDb\Blockcore.Persistence.RocksDb.csproj", "{7785B6F6-62B3-47D2-8A16-1B92BB993797}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Blockcore.Features.Base.Persistence.RocksDb", "Features\Persistence\Blockcore.Features.Base.Persistence.RocksDb\Blockcore.Features.Base.Persistence.RocksDb.csproj", "{9E72A554-24DD-4AEE-BFC7-FB844F055BE6}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Blockcore.Features.BlockStore.Persistence.RocksDb", "Features\Persistence\Blockcore.Features.BlockStore.Persistence.RocksDb\Blockcore.Features.BlockStore.Persistence.RocksDb.csproj", "{1F1C53EC-AAA1-4028-8CDA-4DF1ED4AF516}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Blockcore.Features.Consensus.Persistence.RocksDb", "Features\Persistence\Blockcore.Features.Consensus.Persistence.RocksDb\Blockcore.Features.Consensus.Persistence.RocksDb.csproj", "{BC0A50DF-0816-4613-B6B1-D1FEC384DFAE}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Blockcore.Features.Persistence.Rocksdb.CorePackage", "Features\Persistence\Blockcore.Features.Persistence.Rocksdb.CorePackage\Blockcore.Features.Persistence.Rocksdb.CorePackage.csproj", "{8098D7F8-8B2F-451C-8DCB-90597B768F96}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Blockcore.Features.Persistence.LevelDb.CorePackage", "Features\Persistence\Blockcore.Features.Persistence.LevelDb.CorePackage\Blockcore.Features.Persistence.LevelDb.CorePackage.csproj", "{4275AF0C-587B-4C9D-A100-0F2DD1702674}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -337,6 +363,46 @@ Global {AAB36899-879B-4098-9060-E69240AB7150}.Debug|Any CPU.Build.0 = Debug|Any CPU {AAB36899-879B-4098-9060-E69240AB7150}.Release|Any CPU.ActiveCfg = Release|Any CPU {AAB36899-879B-4098-9060-E69240AB7150}.Release|Any CPU.Build.0 = Release|Any CPU + {AB9A2812-610D-4061-BE71-784AB39FE415}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AB9A2812-610D-4061-BE71-784AB39FE415}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AB9A2812-610D-4061-BE71-784AB39FE415}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AB9A2812-610D-4061-BE71-784AB39FE415}.Release|Any CPU.Build.0 = Release|Any CPU + {E4C7723E-F2D1-41A3-A22A-3D5CB3AE6D6C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E4C7723E-F2D1-41A3-A22A-3D5CB3AE6D6C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E4C7723E-F2D1-41A3-A22A-3D5CB3AE6D6C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E4C7723E-F2D1-41A3-A22A-3D5CB3AE6D6C}.Release|Any CPU.Build.0 = Release|Any CPU + {7760BAD0-B57D-4A57-95DB-A5C53EED5D54}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7760BAD0-B57D-4A57-95DB-A5C53EED5D54}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7760BAD0-B57D-4A57-95DB-A5C53EED5D54}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7760BAD0-B57D-4A57-95DB-A5C53EED5D54}.Release|Any CPU.Build.0 = Release|Any CPU + {5A2AC2B6-0541-4AD2-9BCE-09829C71B3E1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5A2AC2B6-0541-4AD2-9BCE-09829C71B3E1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5A2AC2B6-0541-4AD2-9BCE-09829C71B3E1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5A2AC2B6-0541-4AD2-9BCE-09829C71B3E1}.Release|Any CPU.Build.0 = Release|Any CPU + {7785B6F6-62B3-47D2-8A16-1B92BB993797}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7785B6F6-62B3-47D2-8A16-1B92BB993797}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7785B6F6-62B3-47D2-8A16-1B92BB993797}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7785B6F6-62B3-47D2-8A16-1B92BB993797}.Release|Any CPU.Build.0 = Release|Any CPU + {9E72A554-24DD-4AEE-BFC7-FB844F055BE6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9E72A554-24DD-4AEE-BFC7-FB844F055BE6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9E72A554-24DD-4AEE-BFC7-FB844F055BE6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9E72A554-24DD-4AEE-BFC7-FB844F055BE6}.Release|Any CPU.Build.0 = Release|Any CPU + {1F1C53EC-AAA1-4028-8CDA-4DF1ED4AF516}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1F1C53EC-AAA1-4028-8CDA-4DF1ED4AF516}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1F1C53EC-AAA1-4028-8CDA-4DF1ED4AF516}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1F1C53EC-AAA1-4028-8CDA-4DF1ED4AF516}.Release|Any CPU.Build.0 = Release|Any CPU + {BC0A50DF-0816-4613-B6B1-D1FEC384DFAE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BC0A50DF-0816-4613-B6B1-D1FEC384DFAE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BC0A50DF-0816-4613-B6B1-D1FEC384DFAE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BC0A50DF-0816-4613-B6B1-D1FEC384DFAE}.Release|Any CPU.Build.0 = Release|Any CPU + {8098D7F8-8B2F-451C-8DCB-90597B768F96}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8098D7F8-8B2F-451C-8DCB-90597B768F96}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8098D7F8-8B2F-451C-8DCB-90597B768F96}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8098D7F8-8B2F-451C-8DCB-90597B768F96}.Release|Any CPU.Build.0 = Release|Any CPU + {4275AF0C-587B-4C9D-A100-0F2DD1702674}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4275AF0C-587B-4C9D-A100-0F2DD1702674}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4275AF0C-587B-4C9D-A100-0F2DD1702674}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4275AF0C-587B-4C9D-A100-0F2DD1702674}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -397,6 +463,19 @@ Global {4F3C67B3-D96D-46A6-9BBC-19EB0A1A8712} = {4B0889C8-78BE-41C2-BB7B-7E82B3B83753} {4B0889C8-78BE-41C2-BB7B-7E82B3B83753} = {3B56C02B-4468-4268-B797-851562789FCC} {AAB36899-879B-4098-9060-E69240AB7150} = {4B0889C8-78BE-41C2-BB7B-7E82B3B83753} + {64694A14-97E0-4CBC-8032-754F9353B2DD} = {15D29FFD-6142-4DC5-AFFD-10BA0CA55C45} + {AB9A2812-610D-4061-BE71-784AB39FE415} = {640B1C2A-2346-40E6-9755-87B7EB2B3428} + {E4C7723E-F2D1-41A3-A22A-3D5CB3AE6D6C} = {640B1C2A-2346-40E6-9755-87B7EB2B3428} + {7760BAD0-B57D-4A57-95DB-A5C53EED5D54} = {640B1C2A-2346-40E6-9755-87B7EB2B3428} + {5A2AC2B6-0541-4AD2-9BCE-09829C71B3E1} = {640B1C2A-2346-40E6-9755-87B7EB2B3428} + {640B1C2A-2346-40E6-9755-87B7EB2B3428} = {64694A14-97E0-4CBC-8032-754F9353B2DD} + {2A20F4A8-01E8-4C44-A394-65C2DE6FBF28} = {64694A14-97E0-4CBC-8032-754F9353B2DD} + {7785B6F6-62B3-47D2-8A16-1B92BB993797} = {2A20F4A8-01E8-4C44-A394-65C2DE6FBF28} + {9E72A554-24DD-4AEE-BFC7-FB844F055BE6} = {2A20F4A8-01E8-4C44-A394-65C2DE6FBF28} + {1F1C53EC-AAA1-4028-8CDA-4DF1ED4AF516} = {2A20F4A8-01E8-4C44-A394-65C2DE6FBF28} + {BC0A50DF-0816-4613-B6B1-D1FEC384DFAE} = {2A20F4A8-01E8-4C44-A394-65C2DE6FBF28} + {8098D7F8-8B2F-451C-8DCB-90597B768F96} = {64694A14-97E0-4CBC-8032-754F9353B2DD} + {4275AF0C-587B-4C9D-A100-0F2DD1702674} = {64694A14-97E0-4CBC-8032-754F9353B2DD} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {6C780ABA-5872-4B83-AD3F-A5BD423AD907} diff --git a/src/Blockcore/Base/BaseFeature.cs b/src/Blockcore/Base/BaseFeature.cs index 3b64cfd61..9f9ff72f0 100644 --- a/src/Blockcore/Base/BaseFeature.cs +++ b/src/Blockcore/Base/BaseFeature.cs @@ -385,6 +385,8 @@ public static IFullNodeBuilder UseBaseFeature(this IFullNodeBuilder fullNodeBuil .AddFeature() .FeatureServices(services => { + fullNodeBuilder.PersistenceProviderManager.RequirePersistence(services); + services.AddSingleton(fullNodeBuilder.Network.Consensus.ConsensusFactory); services.AddSingleton(); services.AddSingleton(fullNodeBuilder.NodeSettings.LoggerFactory); @@ -400,7 +402,6 @@ public static IFullNodeBuilder UseBaseFeature(this IFullNodeBuilder fullNodeBuil services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); - AddDbImplementation(services, fullNodeBuilder.NodeSettings); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); @@ -486,23 +487,5 @@ public static IFullNodeBuilder UseBaseFeature(this IFullNodeBuilder fullNodeBuil return fullNodeBuilder; } - - private static void AddDbImplementation(IServiceCollection services, NodeSettings settings) - { - if (settings.DbType == DbType.Leveldb) - { - services.AddSingleton(); - services.AddSingleton(); - - return; - } - - if (settings.DbType == DbType.Rocksdb) - { - services.AddSingleton(); - services.AddSingleton(); - return; - } - } } } \ No newline at end of file diff --git a/src/Blockcore/Blockcore.csproj b/src/Blockcore/Blockcore.csproj index 445b7cf5f..a3caaa416 100644 --- a/src/Blockcore/Blockcore.csproj +++ b/src/Blockcore/Blockcore.csproj @@ -47,10 +47,7 @@ - - - diff --git a/src/Blockcore/Builder/FullNodeBuilder.cs b/src/Blockcore/Builder/FullNodeBuilder.cs index a5c8c903e..4c6dade60 100644 --- a/src/Blockcore/Builder/FullNodeBuilder.cs +++ b/src/Blockcore/Builder/FullNodeBuilder.cs @@ -6,10 +6,10 @@ using Blockcore.Builder.Feature; using Blockcore.Configuration; using Blockcore.Networks; +using Blockcore.Persistence; using Blockcore.Utilities; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; -using NBitcoin; namespace Blockcore.Builder { @@ -51,6 +51,9 @@ public class FullNodeBuilder : IFullNodeBuilder /// public NodeSettings NodeSettings { get; set; } + /// + public IPersistenceProviderManager PersistenceProviderManager { get; set; } + /// public Network Network { get; set; } @@ -64,7 +67,8 @@ public FullNodeBuilder() : this(new List>(), new List>(), new List>(), - new FeatureCollection()) + new FeatureCollection(), + null) { } @@ -72,11 +76,14 @@ public FullNodeBuilder() : /// Initializes an instance of the object using specific NodeSettings instance and registers required services. /// /// User defined node settings. - public FullNodeBuilder(NodeSettings nodeSettings) + /// Persistence Provider Manager that will help registering needed persistence services. + public FullNodeBuilder(NodeSettings nodeSettings, IPersistenceProviderManager persistenceProviderManager) : this(nodeSettings, new List>(), new List>(), new List>(), - new FeatureCollection()) + new FeatureCollection(), + persistenceProviderManager + ) { } @@ -88,9 +95,10 @@ public FullNodeBuilder(NodeSettings nodeSettings) /// List of delegates that configure the service providers. /// List of delegates that add features to the collection. /// Collection of features to be available to and/or used by the node. + /// Persistence Provider Manager that will help registering needed persistence services. internal FullNodeBuilder(NodeSettings nodeSettings, List> configureServicesDelegates, List> configureDelegates, - List> featuresRegistrationDelegates, IFeatureCollection features) - : this(configureServicesDelegates, configureDelegates, featuresRegistrationDelegates, features) + List> featuresRegistrationDelegates, IFeatureCollection features, IPersistenceProviderManager persistenceProviderManager) + : this(configureServicesDelegates, configureDelegates, featuresRegistrationDelegates, features, persistenceProviderManager) { Guard.NotNull(nodeSettings, nameof(nodeSettings)); @@ -113,8 +121,9 @@ internal FullNodeBuilder(NodeSettings nodeSettings, ListList of delegates that configure the service providers. /// List of delegates that add features to the collection. /// Collection of features to be available to and/or used by the node. + /// Persistence Provider Manager that will help registering needed persistence services. internal FullNodeBuilder(List> configureServicesDelegates, List> configureDelegates, - List> featuresRegistrationDelegates, IFeatureCollection features) + List> featuresRegistrationDelegates, IFeatureCollection features, IPersistenceProviderManager persistenceProviderManager) { Guard.NotNull(configureServicesDelegates, nameof(configureServicesDelegates)); Guard.NotNull(configureDelegates, nameof(configureDelegates)); @@ -125,6 +134,7 @@ internal FullNodeBuilder(List> configureServicesDeleg this.configureDelegates = configureDelegates; this.featuresRegistrationDelegates = featuresRegistrationDelegates; this.Features = features; + this.PersistenceProviderManager = persistenceProviderManager; } /// @@ -166,7 +176,7 @@ public IFullNode Build() // Print command-line help if (this.NodeSettings?.PrintHelpAndExit ?? false) { - NodeSettings.PrintHelp(this.Network); + NodeSettings.PrintHelp(this.Network, this); foreach (IFeatureRegistration featureRegistration in this.Features.FeatureRegistrations) { @@ -180,7 +190,7 @@ public IFullNode Build() } // Create configuration file if required - this.NodeSettings?.CreateDefaultConfigurationFile(this.Features.FeatureRegistrations); + this.NodeSettings?.CreateDefaultConfigurationFile(this.Features.FeatureRegistrations, this); ServiceProvider fullNodeServiceProvider = this.Services.BuildServiceProvider(); this.ConfigureServices(fullNodeServiceProvider); @@ -213,6 +223,13 @@ private IServiceCollection BuildServices() { this.Services = new ServiceCollection(); + // If no persistence provider has been set yet, create a default one + if (this.PersistenceProviderManager == null) + { + this.PersistenceProviderManager = new PersistenceProviderManager(this.NodeSettings); + } + this.PersistenceProviderManager.Initialize(); + // register services before features // as some of the features may depend on independent services foreach (Action configureServices in this.configureServicesDelegates) diff --git a/src/Blockcore/Builder/FullNodeBuilderIPersistenceProviderManagerExtension.cs b/src/Blockcore/Builder/FullNodeBuilderIPersistenceProviderManagerExtension.cs new file mode 100644 index 000000000..3e356df62 --- /dev/null +++ b/src/Blockcore/Builder/FullNodeBuilderIPersistenceProviderManagerExtension.cs @@ -0,0 +1,24 @@ +using Blockcore.Persistence; + +namespace Blockcore.Builder +{ + /// + /// A class providing extension methods for . + /// + public static class FullNodeBuilderIPersistenceProviderManagerExtension + { + /// + /// Makes the full node builder use specific node settings. + /// + /// Full node builder to which inject persistence provider manager. + /// The persistence provider manager to use to. + /// Interface to allow fluent code. + public static IFullNodeBuilder UsePersistenceProviderMananger(this IFullNodeBuilder builder, IPersistenceProviderManager persistenceProviderManager) + { + var nodeBuilder = builder as FullNodeBuilder; + nodeBuilder.PersistenceProviderManager = persistenceProviderManager; + + return builder; + } + } +} diff --git a/src/Blockcore/Builder/IFullNodeBuilder.cs b/src/Blockcore/Builder/IFullNodeBuilder.cs index 0a10b8136..f082414e4 100644 --- a/src/Blockcore/Builder/IFullNodeBuilder.cs +++ b/src/Blockcore/Builder/IFullNodeBuilder.cs @@ -2,8 +2,8 @@ using Blockcore.Builder.Feature; using Blockcore.Configuration; using Blockcore.Networks; +using Blockcore.Persistence; using Microsoft.Extensions.DependencyInjection; -using NBitcoin; namespace Blockcore.Builder { @@ -15,6 +15,9 @@ public interface IFullNodeBuilder /// User defined node settings. NodeSettings NodeSettings { get; } + /// Allows to require implementation of the persistence layer they need. + IPersistenceProviderManager PersistenceProviderManager { get; } + /// Specification of the network the node runs on - regtest/testnet/mainnet. Network Network { get; } diff --git a/src/Blockcore/Configuration/NodeSettings.cs b/src/Blockcore/Configuration/NodeSettings.cs index e10eee7ea..6e7b53afa 100644 --- a/src/Blockcore/Configuration/NodeSettings.cs +++ b/src/Blockcore/Configuration/NodeSettings.cs @@ -4,6 +4,7 @@ using System.Reflection; using System.Runtime.InteropServices; using System.Text; +using Blockcore.Builder; using Blockcore.Builder.Feature; using Blockcore.Configuration.Logging; using Blockcore.Configuration.Settings; @@ -109,7 +110,7 @@ public class NodeSettings : IDisposable /// /// The type of database to use for the node (this includes consensus, store, chain, and the common key value store). /// - public DbType DbType { get; private set; } + public string DbType { get; private set; } /// /// Initializes a new instance of the object. @@ -193,7 +194,7 @@ public NodeSettings(Network network = null, string agent = "Blockcore", // Ensure the network being used is registered and we have the correct Network object reference. this.Network = NetworkRegistration.Register(this.Network); - this.DbType = this.ConfigReader.GetOrDefault("dbtype", DbType.Leveldb, this.Logger); + this.DbType = this.ConfigReader.GetOrDefault("dbtype", null, this.Logger); // Set the full data directory path. if (this.DataDir == null) @@ -262,7 +263,8 @@ public static NodeSettings Default(Network network) /// Creates the configuration file if it does not exist. /// /// The features for which to include settings in the configuration file. - public void CreateDefaultConfigurationFile(List features) + /// The full node builder. + public void CreateDefaultConfigurationFile(List features, IFullNodeBuilder fullNodeBuilder) { // If the config file does not exist yet then create it now. if (!File.Exists(this.ConfigurationFile)) @@ -271,7 +273,7 @@ public void CreateDefaultConfigurationFile(List features) var builder = new StringBuilder(); - BuildDefaultConfigurationFile(builder, this.Network); + BuildDefaultConfigurationFile(builder, this.Network, fullNodeBuilder); foreach (IFeatureRegistration featureRegistration in features) { @@ -364,7 +366,7 @@ private string CreateDefaultDataDirectories(string appName, Network network) /// Displays command-line help. /// /// The network to extract values from. - public static void PrintHelp(Network network) + public static void PrintHelp(Network network, IFullNodeBuilder fullNodeBuilder) { Guard.NotNull(network, nameof(network)); @@ -391,7 +393,7 @@ public static void PrintHelp(Network network) builder.AppendLine($"-fallbackfee= Fallback fee rate. Defaults to {network.FallbackFee}."); builder.AppendLine($"-minrelaytxfee= Minimum relay fee rate. Defaults to {network.MinRelayTxFee}."); - builder.AppendLine($"-dbtype= Which db to use. options: {DbType.Leveldb} (default),{DbType.Rocksdb},{DbType.Faster},{DbType.DBTrie}."); + builder.AppendLine($"-dbtype= Which db to use. Defaults to {fullNodeBuilder.PersistenceProviderManager.GetDefaultProvider()}. Available options: {string.Join(", ", fullNodeBuilder.PersistenceProviderManager.GetAvailableProviders())}."); defaults.Logger.LogInformation(builder.ToString()); @@ -403,7 +405,8 @@ public static void PrintHelp(Network network) /// /// The string builder to add the settings to. /// The network to base the defaults off. - public static void BuildDefaultConfigurationFile(StringBuilder builder, Network network) + /// The full node builder. + public static void BuildDefaultConfigurationFile(StringBuilder builder, Network network, IFullNodeBuilder fullNodeBuilder) { builder.AppendLine("####Node Settings####"); builder.AppendLine($"#Test network. Defaults to 0."); @@ -418,7 +421,7 @@ public static void BuildDefaultConfigurationFile(StringBuilder builder, Network builder.AppendLine($"#Minimum relay fee rate. Defaults to {network.MinRelayTxFee}."); builder.AppendLine($"#minrelaytxfee={network.MinRelayTxFee}"); builder.AppendLine(); - builder.AppendLine($"#Which db to use. options: {DbType.Leveldb} (default),{DbType.Rocksdb},{DbType.Faster},{DbType.DBTrie}."); + builder.AppendLine($"#Which db to use. Defaults to {fullNodeBuilder.PersistenceProviderManager.GetDefaultProvider()}. Available options: {string.Join(", ", fullNodeBuilder.PersistenceProviderManager.GetAvailableProviders())}."); builder.AppendLine($"#dbtype="); builder.AppendLine(); @@ -431,12 +434,4 @@ public void Dispose() this.LoggerFactory.Dispose(); } } - - public enum DbType - { - Leveldb, - DBTrie, - Faster, - Rocksdb - } } \ No newline at end of file diff --git a/src/Blockcore/Persistence/IPersistenceProvider.cs b/src/Blockcore/Persistence/IPersistenceProvider.cs new file mode 100644 index 000000000..380f33027 --- /dev/null +++ b/src/Blockcore/Persistence/IPersistenceProvider.cs @@ -0,0 +1,27 @@ +using System; +using Blockcore.Builder.Feature; +using Microsoft.Extensions.DependencyInjection; + +namespace Blockcore.Persistence +{ + /// + /// Allow features to request a persistence implementation. + /// + public interface IPersistenceProvider + { + /// + /// Gets the tag of the persistence implementation (usually is the name of the db engine used, e.g. "litedb" or "rocksdb"). + /// + string Tag { get; } + + /// + /// Gets the type of the feature for which services will be registered. + /// + Type FeatureType { get; } + + /// + /// Add required services for a specific use case. + /// + void AddRequiredServices(IServiceCollection services); + } +} diff --git a/src/Blockcore/Persistence/IPersistenceProviderManager.cs b/src/Blockcore/Persistence/IPersistenceProviderManager.cs new file mode 100644 index 000000000..51c105521 --- /dev/null +++ b/src/Blockcore/Persistence/IPersistenceProviderManager.cs @@ -0,0 +1,35 @@ +using System.Collections.Generic; +using Blockcore.Builder.Feature; +using Microsoft.Extensions.DependencyInjection; + +namespace Blockcore.Persistence +{ + /// + /// Used by features to require a persistence implementation. + /// + public interface IPersistenceProviderManager + { + /// + /// Requires the persistence implementation for the feature type. + /// + /// The type of the feature. + /// The services collection IPersistenceProvider will use to register persistence component needed by the specified feature. + /// The explicit persistence provider implementation. If null, the one specified by dbtype argument will be used. + void RequirePersistence(IServiceCollection services, string persistenceProviderImplementation = null) where TFeature : IFullNodeFeature; + + /// + /// Initializes the persistence provider manager, loading known persistence implementations based on the implementer strategy. + /// + void Initialize(); + + /// + /// Gets the available providers. + /// + IEnumerable GetAvailableProviders(); + + /// + /// Gets the default provider. + /// + string GetDefaultProvider(); + } +} \ No newline at end of file diff --git a/src/Blockcore/Persistence/PersistenceAttribute.cs b/src/Blockcore/Persistence/PersistenceAttribute.cs new file mode 100644 index 000000000..c0132786e --- /dev/null +++ b/src/Blockcore/Persistence/PersistenceAttribute.cs @@ -0,0 +1,28 @@ +using System; + +namespace Blockcore.Persistence +{ + /// + /// Used to require a persistence implementation. + /// This attribute has to be placed on top of implementation of services interface that manage persistence (e.g. IBlockStoreRepository + /// + [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] + public sealed class PersistenceAttribute : Attribute + { + /// + /// Gets the name of the persistence implementation. + /// This is the value that will be checked against . + /// + /// Case Insensitive. + public string PersistenceImplementation { get; } + + /// + /// Initializes a new instance of the class. + /// + /// The persistence implementation. By convention it's the name of the underlying product that manage persistence (e.g. "LevelDb", "Rocksdb", etc...) + public PersistenceAttribute(string persistenceImplementation) + { + this.PersistenceImplementation = persistenceImplementation; + } + } +} diff --git a/src/Blockcore/Persistence/PersistenceProviderBase.cs b/src/Blockcore/Persistence/PersistenceProviderBase.cs new file mode 100644 index 000000000..5c2560805 --- /dev/null +++ b/src/Blockcore/Persistence/PersistenceProviderBase.cs @@ -0,0 +1,19 @@ +using System; +using Blockcore.Builder.Feature; +using Microsoft.Extensions.DependencyInjection; + +namespace Blockcore.Persistence +{ + /// + public abstract class PersistenceProviderBase : IPersistenceProvider where TFeature : IFullNodeFeature + { + /// + public abstract string Tag { get; } + + /// + public Type FeatureType => typeof(TFeature); + + /// + public abstract void AddRequiredServices(IServiceCollection services); + } +} diff --git a/src/Blockcore/Persistence/PersistenceProviderManager.cs b/src/Blockcore/Persistence/PersistenceProviderManager.cs new file mode 100644 index 000000000..c475cbeaa --- /dev/null +++ b/src/Blockcore/Persistence/PersistenceProviderManager.cs @@ -0,0 +1,122 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using Blockcore.Builder; +using Blockcore.Builder.Feature; +using Blockcore.Configuration; +using Microsoft.Extensions.DependencyInjection; + +namespace Blockcore.Persistence +{ + /// + public class PersistenceProviderManager : IPersistenceProviderManager + { + protected readonly NodeSettings nodeSettings; + protected readonly Dictionary> persistenceProviders; + + /// + /// Initializes a new instance of the class. + /// This class handles the initialization of persistence implementors for specific features on behalf of other features. + /// For example if BlockStore feature requires a persistence, it can call + /// + /// The settings from which obtain the default db type. + public PersistenceProviderManager(NodeSettings nodeSettings) + { + this.nodeSettings = nodeSettings; + this.persistenceProviders = new Dictionary>(); + } + + /// + public IEnumerable GetAvailableProviders() + { + return this.persistenceProviders.Keys; + } + + /// + public string GetDefaultProvider() + { + if (this.persistenceProviders.Count == 0) + { + return null; + } + + return this.persistenceProviders.ContainsKey("leveldb") ? "leveldb" : this.persistenceProviders.Keys.First(); + } + + /// + /// + /// Search for all assemblies that implement the interface IPersistenceProvider in all referenced libraries. + /// Create one instance for each of them and register the instance in the dictionary in order to be found when will be called by any feature + /// + public virtual void Initialize() + { + List persistenceAssemblies = Directory.GetFiles(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), "*.Persistence.*.dll").ToList(); + List loadedPersistenceAssemblies = AppDomain.CurrentDomain.GetAssemblies().Select(a => a.Location).Where(path => path.Contains(".Persistence.")).ToList(); + + List unloadedPersistenceAssemblies = persistenceAssemblies.Except(loadedPersistenceAssemblies).ToList(); + + foreach (string unloadedPersistenceAssembly in unloadedPersistenceAssemblies) + { + this.FindPersistenceAssembly(Assembly.LoadFrom(unloadedPersistenceAssembly)); + } + } + + /// + /// Finds the persistence implementation in an assembly. + /// + /// The assembly to search persistence implementation from. + private void FindPersistenceAssembly(Assembly assembly) + { + var type = typeof(IPersistenceProvider); + + // we could consider to add a parameter in configuration, to specify some rule to skip some of the discovered assemblies + var persistenceProviderTypes = assembly + .GetTypes() + .Where(candidateType => !candidateType.IsAbstract && type.IsAssignableFrom(candidateType)); + + foreach (Type providerType in persistenceProviderTypes) + { + IPersistenceProvider providerInstance = (IPersistenceProvider)Activator.CreateInstance(providerType); + + string implementationName = providerInstance.Tag.ToLowerInvariant(); + + if (!this.persistenceProviders.TryGetValue(implementationName, out List providersList)) + { + providersList = new List(); + this.persistenceProviders.Add(implementationName, providersList); + } + + providersList.Add(providerInstance); + } + } + + /// + public void RequirePersistence(IServiceCollection services, string persistenceProviderImplementation = null) where TFeature : IFullNodeFeature + { + if (persistenceProviderImplementation == null) + { + persistenceProviderImplementation = this.nodeSettings.DbType ?? this.GetDefaultProvider(); + } + + IPersistenceProvider provider = null; + + if (this.persistenceProviders.TryGetValue(persistenceProviderImplementation.ToLowerInvariant(), out List providersList)) + { + provider = providersList.FirstOrDefault(provider => provider.FeatureType == typeof(TFeature)); + + if (provider == null) + { + throw new NodeBuilderException($"Required persistence provider {persistenceProviderImplementation} doesn't implement persistence for {typeof(TFeature).Name}."); + } + + provider.AddRequiredServices(services); + } + else + { + throw new NodeBuilderException($"Required persistence provider implementation {persistenceProviderImplementation} Not found."); + } + } + } +} diff --git a/src/Blockcore/Utilities/LeveldbHelper.cs b/src/Blockcore/Utilities/LeveldbHelper.cs index 56f39a07b..e4c12e69d 100644 --- a/src/Blockcore/Utilities/LeveldbHelper.cs +++ b/src/Blockcore/Utilities/LeveldbHelper.cs @@ -1,7 +1,4 @@ using System; -using System.Collections.Generic; -using LevelDB; -using RocksDbSharp; namespace Blockcore.Utilities { @@ -22,33 +19,5 @@ public static byte[] Key(byte table, ReadOnlySpan key) key.CopyTo(dbkey.Slice(1)); return dbkey.ToArray(); } - - public static Dictionary SelectDictionary(this DB db, byte table) - { - var dict = new Dictionary(); - - var enumerator = db.GetEnumerator(); - while (enumerator.MoveNext()) - { - if (enumerator.Current.Key[0] == table) - dict.Add(enumerator.Current.Key.AsSpan().Slice(1).ToArray(), enumerator.Current.Value); - } - - return dict; - } - - public static Dictionary SelectDictionary(this RocksDb db, byte table) - { - var dict = new Dictionary(); - - var enumerator = db.NewIterator(); - for (enumerator.SeekToFirst(); enumerator.Valid(); enumerator.Next()) - { - if (enumerator.Key()[0] == table) - dict.Add(enumerator.Key().AsSpan().Slice(1).ToArray(), enumerator.Value()); - } - - return dict; - } } } \ No newline at end of file diff --git a/src/Features/Blockcore.Features.BlockStore/BlockStoreFeature.cs b/src/Features/Blockcore.Features.BlockStore/BlockStoreFeature.cs index 37c3b0ab3..8f66a9ab2 100644 --- a/src/Features/Blockcore.Features.BlockStore/BlockStoreFeature.cs +++ b/src/Features/Blockcore.Features.BlockStore/BlockStoreFeature.cs @@ -1,28 +1,23 @@ -using System; -using System.Runtime.CompilerServices; +using System.Runtime.CompilerServices; using System.Text; using System.Threading.Tasks; using Blockcore.Base; using Blockcore.Builder; using Blockcore.Builder.Feature; -using Blockcore.Configuration; using Blockcore.Configuration.Logging; -using Blockcore.Configuration.Settings; using Blockcore.Connection; using Blockcore.Consensus; using Blockcore.Consensus.Chain; using Blockcore.Consensus.Checkpoints; using Blockcore.Features.BlockStore.AddressIndexing; using Blockcore.Features.BlockStore.Pruning; -using Blockcore.Features.BlockStore.Repository; -using Blockcore.Features.Consensus.CoinViews.Coindb; using Blockcore.Interfaces; using Blockcore.Networks; using Blockcore.P2P.Protocol.Payloads; using Blockcore.Utilities; +using Blockcore.Utilities.Store; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; -using NBitcoin; [assembly: InternalsVisibleTo("Blockcore.Features.BlockStore.Tests")] @@ -205,7 +200,7 @@ public static IFullNodeBuilder UseBlockStore(this IFullNodeBuilder fullNodeBuild { services.AddSingleton().AddSingleton(provider => provider.GetService()); - AddDbImplementation(services, fullNodeBuilder.NodeSettings); + fullNodeBuilder.PersistenceProviderManager.RequirePersistence(services); if (fullNodeBuilder.Network.Consensus.IsProofOfStake) services.AddSingleton(); @@ -223,22 +218,5 @@ public static IFullNodeBuilder UseBlockStore(this IFullNodeBuilder fullNodeBuild return fullNodeBuilder; } - - private static void AddDbImplementation(IServiceCollection services, NodeSettings settings) - { - if (settings.DbType == DbType.Leveldb) - { - services.AddSingleton(); - services.AddSingleton(); - return; - } - - if (settings.DbType == DbType.Rocksdb) - { - services.AddSingleton(); - services.AddSingleton(); - return; - } - } } } \ No newline at end of file diff --git a/src/Features/Blockcore.Features.BlockStore/Blockcore.Features.BlockStore.csproj b/src/Features/Blockcore.Features.BlockStore/Blockcore.Features.BlockStore.csproj index 4bf0bced0..3b5e6e3b0 100644 --- a/src/Features/Blockcore.Features.BlockStore/Blockcore.Features.BlockStore.csproj +++ b/src/Features/Blockcore.Features.BlockStore/Blockcore.Features.BlockStore.csproj @@ -15,8 +15,6 @@ - - diff --git a/src/Features/Blockcore.Features.Consensus/Blockcore.Features.Consensus.csproj b/src/Features/Blockcore.Features.Consensus/Blockcore.Features.Consensus.csproj index e4a5331bb..af1705021 100644 --- a/src/Features/Blockcore.Features.Consensus/Blockcore.Features.Consensus.csproj +++ b/src/Features/Blockcore.Features.Consensus/Blockcore.Features.Consensus.csproj @@ -19,8 +19,6 @@ - - diff --git a/src/Features/Blockcore.Features.Consensus/FullNodeBuilderConsensusExtension.cs b/src/Features/Blockcore.Features.Consensus/FullNodeBuilderConsensusExtension.cs index 30c983627..b421d23ca 100644 --- a/src/Features/Blockcore.Features.Consensus/FullNodeBuilderConsensusExtension.cs +++ b/src/Features/Blockcore.Features.Consensus/FullNodeBuilderConsensusExtension.cs @@ -1,20 +1,15 @@ -using System; -using Blockcore.Base; +using Blockcore.Base; using Blockcore.Builder; -using Blockcore.Configuration; using Blockcore.Configuration.Logging; -using Blockcore.Configuration.Settings; using Blockcore.Consensus; -using Blockcore.Consensus.Chain; using Blockcore.Features.Consensus.CoinViews; using Blockcore.Features.Consensus.CoinViews.Coindb; using Blockcore.Features.Consensus.Interfaces; using Blockcore.Features.Consensus.ProvenBlockHeaders; using Blockcore.Features.Consensus.Rules; using Blockcore.Interfaces; -using Blockcore.Utilities; +using Blockcore.Utilities.Store; using Microsoft.Extensions.DependencyInjection; -using NBitcoin; namespace Blockcore.Features.Consensus { @@ -23,7 +18,7 @@ namespace Blockcore.Features.Consensus /// public static class FullNodeBuilderConsensusExtension { - public static IFullNodeBuilder UsePowConsensus(this IFullNodeBuilder fullNodeBuilder, DbType coindbType = DbType.Rocksdb) + public static IFullNodeBuilder UsePowConsensus(this IFullNodeBuilder fullNodeBuilder) { LoggingConfiguration.RegisterFeatureNamespace("powconsensus"); @@ -33,7 +28,8 @@ public static IFullNodeBuilder UsePowConsensus(this IFullNodeBuilder fullNodeBui .AddFeature() .FeatureServices(services => { - AddDbImplementation(services, fullNodeBuilder.NodeSettings); + fullNodeBuilder.PersistenceProviderManager.RequirePersistence(services); + services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); @@ -47,7 +43,7 @@ public static IFullNodeBuilder UsePowConsensus(this IFullNodeBuilder fullNodeBui return fullNodeBuilder; } - public static IFullNodeBuilder UsePosConsensus(this IFullNodeBuilder fullNodeBuilder, DbType coindbType = DbType.Rocksdb) + public static IFullNodeBuilder UsePosConsensus(this IFullNodeBuilder fullNodeBuilder) { LoggingConfiguration.RegisterFeatureNamespace("posconsensus"); @@ -57,7 +53,8 @@ public static IFullNodeBuilder UsePosConsensus(this IFullNodeBuilder fullNodeBui .AddFeature() .FeatureServices(services => { - AddDbImplementation(services, fullNodeBuilder.NodeSettings); + fullNodeBuilder.PersistenceProviderManager.RequirePersistence(services); + services.AddSingleton(provider => (IStakdb)provider.GetService()); services.AddSingleton(); services.AddSingleton().AddSingleton(provider => provider.GetService()); @@ -69,41 +66,10 @@ public static IFullNodeBuilder UsePosConsensus(this IFullNodeBuilder fullNodeBui .AddSingleton(provider => provider.GetService()) .AddSingleton(provider => provider.GetService()); services.AddSingleton(); - AddProvenBlockHeaderImplementation(services, fullNodeBuilder.NodeSettings); }); }); return fullNodeBuilder; } - - private static void AddDbImplementation(IServiceCollection services, NodeSettings settings) - { - if (settings.DbType == DbType.Leveldb) - { - services.AddSingleton(); - return; - } - - if (settings.DbType == DbType.Rocksdb) - { - services.AddSingleton(); - return; - } - } - - private static void AddProvenBlockHeaderImplementation(IServiceCollection services, NodeSettings settings) - { - if (settings.DbType == DbType.Leveldb) - { - services.AddSingleton(); - return; - } - - if (settings.DbType == DbType.Rocksdb) - { - services.AddSingleton(); - return; - } - } } } \ No newline at end of file diff --git a/src/Features/Blockcore.Features.Persistence.Rocksdb/Blockcore.Features.Persistence.Rocksdb.csproj b/src/Features/Blockcore.Features.Persistence.Rocksdb/Blockcore.Features.Persistence.Rocksdb.csproj new file mode 100644 index 000000000..9e8c77cba --- /dev/null +++ b/src/Features/Blockcore.Features.Persistence.Rocksdb/Blockcore.Features.Persistence.Rocksdb.csproj @@ -0,0 +1,30 @@ + + + + Rocksdb persistence feature for Blockcore + Blockcore.Features.Persistence.Rocksdb + Blockcore.Features.Persistence.Rocksdb + Blockcore.Features.Persistence.Rocksdb + False + Blockcore + true + + + + + + + + + + + + + + + + + 1701;1702;1705;IDE0008; + + + \ No newline at end of file diff --git a/src/Features/Blockcore.Features.Consensus/CoinViews/Coindb/RocksdbCoindb .cs b/src/Features/Blockcore.Features.Persistence.Rocksdb/RocksDbCoindb .cs similarity index 97% rename from src/Features/Blockcore.Features.Consensus/CoinViews/Coindb/RocksdbCoindb .cs rename to src/Features/Blockcore.Features.Persistence.Rocksdb/RocksDbCoindb .cs index 81ad1a8e5..94efd6029 100644 --- a/src/Features/Blockcore.Features.Consensus/CoinViews/Coindb/RocksdbCoindb .cs +++ b/src/Features/Blockcore.Features.Persistence.Rocksdb/RocksDbCoindb .cs @@ -16,7 +16,7 @@ namespace Blockcore.Features.Consensus.CoinViews.Coindb /// /// Persistent implementation of coinview using dBreeze database. /// - public class RocksdbCoindb : ICoindb, IStakdb, IDisposable + public class RocksDbCoindb : ICoindb, IStakdb, IDisposable { /// Database key under which the block hash of the coin view's current tip is stored. private static readonly byte[] blockHashKey = new byte[0]; @@ -45,13 +45,13 @@ public class RocksdbCoindb : ICoindb, IStakdb, IDisposable private DataStoreSerializer dataStoreSerializer; - public RocksdbCoindb(Network network, DataFolder dataFolder, IDateTimeProvider dateTimeProvider, + public RocksDbCoindb(Network network, DataFolder dataFolder, IDateTimeProvider dateTimeProvider, ILoggerFactory loggerFactory, INodeStats nodeStats, DataStoreSerializer dataStoreSerializer) : this(network, dataFolder.CoindbPath, dateTimeProvider, loggerFactory, nodeStats, dataStoreSerializer) { } - public RocksdbCoindb(Network network, string folder, IDateTimeProvider dateTimeProvider, + public RocksDbCoindb(Network network, string folder, IDateTimeProvider dateTimeProvider, ILoggerFactory loggerFactory, INodeStats nodeStats, DataStoreSerializer dataStoreSerializer) { Guard.NotNull(network, nameof(network)); @@ -276,7 +276,7 @@ public void GetStake(IEnumerable blocklist) private void AddBenchStats(StringBuilder log) { - log.AppendLine("======Leveldb Bench======"); + log.AppendLine("======LevelDb Bench======"); BackendPerformanceSnapshot snapShot = this.performanceCounter.Snapshot(); diff --git a/src/Features/Blockcore.Features.Persistence.Rocksdb/RocksDbPersistenceProvider.cs b/src/Features/Blockcore.Features.Persistence.Rocksdb/RocksDbPersistenceProvider.cs new file mode 100644 index 000000000..d42d0e91a --- /dev/null +++ b/src/Features/Blockcore.Features.Persistence.Rocksdb/RocksDbPersistenceProvider.cs @@ -0,0 +1,46 @@ +using System; +using Blockcore.Base; +using Blockcore.Builder.Feature; +using Blockcore.Consensus.Chain; +using Blockcore.Features.BlockStore; +using Blockcore.Features.BlockStore.Pruning; +using Blockcore.Features.BlockStore.Repository; +using Blockcore.Features.Consensus; +using Blockcore.Features.Consensus.CoinViews.Coindb; +using Blockcore.Features.Consensus.ProvenBlockHeaders; +using Blockcore.Interfaces; +using Blockcore.Utilities.Store; +using Microsoft.Extensions.DependencyInjection; + +namespace Blockcore.Features.Persistence.Rocksdb +{ + public class RocksDbPersistenceProvider : IPersistenceProvider + { + const string NAME = "Rocksdb"; + + public string Name => NAME; + + public void AddRequiredServices(IServiceCollection services) where TFeature : IFullNodeFeature + { + Type type = typeof(TFeature); + + switch (type) + { + case Type _ when type == typeof(BaseFeature): + services.AddSingleton(); + services.AddSingleton(); + break; + + case Type _ when type == typeof(ConsensusFeature): + services.AddSingleton(); + services.AddSingleton(); + break; + + case Type _ when type == typeof(BlockStoreFeature): + services.AddSingleton(); + services.AddSingleton(); + break; + } + } + } +} diff --git a/src/Features/Blockcore.Features.Consensus/ProvenBlockHeaders/RocksdbProvenBlockHeaderRepository.cs b/src/Features/Blockcore.Features.Persistence.Rocksdb/RocksDbProvenBlockHeaderRepository.cs similarity index 95% rename from src/Features/Blockcore.Features.Consensus/ProvenBlockHeaders/RocksdbProvenBlockHeaderRepository.cs rename to src/Features/Blockcore.Features.Persistence.Rocksdb/RocksDbProvenBlockHeaderRepository.cs index 4a10f6a30..d73e5248e 100644 --- a/src/Features/Blockcore.Features.Consensus/ProvenBlockHeaders/RocksdbProvenBlockHeaderRepository.cs +++ b/src/Features/Blockcore.Features.Persistence.Rocksdb/RocksDbProvenBlockHeaderRepository.cs @@ -8,7 +8,6 @@ using Blockcore.Interfaces; using Blockcore.Networks; using Blockcore.Utilities; -using DBreeze.Utils; using Microsoft.Extensions.Logging; using NBitcoin; using RocksDbSharp; @@ -18,7 +17,7 @@ namespace Blockcore.Features.Consensus.ProvenBlockHeaders /// /// Persistent implementation of the DBreeze repository. /// - public class RocksdbProvenBlockHeaderRepository : IProvenBlockHeaderRepository + public class RocksDbProvenBlockHeaderRepository : IProvenBlockHeaderRepository { /// /// Instance logger. @@ -59,10 +58,10 @@ public class RocksdbProvenBlockHeaderRepository : IProvenBlockHeaderRepository /// Initializes a new instance of the object. /// /// Specification of the network the node runs on - RegTest/TestNet/MainNet. - /// folder path to the DBreeze database files. + /// folder path to the DBreeze database files. /// Factory to create a logger for this type. /// The serializer to use for objects. - public RocksdbProvenBlockHeaderRepository(Network network, DataFolder folder, ILoggerFactory loggerFactory, + public RocksDbProvenBlockHeaderRepository(Network network, DataFolder folder, ILoggerFactory loggerFactory, DataStoreSerializer dataStoreSerializer) : this(network, folder.ProvenBlockHeaderPath, loggerFactory, dataStoreSerializer) { @@ -72,10 +71,10 @@ public RocksdbProvenBlockHeaderRepository(Network network, DataFolder folder, IL /// Initializes a new instance of the object. /// /// Specification of the network the node runs on - RegTest/TestNet/MainNet. - /// folder path to the DBreeze database files. + /// folder path to the DBreeze database files. /// Factory to create a logger for this type. /// The serializer to use for objects. - public RocksdbProvenBlockHeaderRepository(Network network, string folder, ILoggerFactory loggerFactory, + public RocksDbProvenBlockHeaderRepository(Network network, string folder, ILoggerFactory loggerFactory, DataStoreSerializer dataStoreSerializer) { Guard.NotNull(network, nameof(network)); diff --git a/src/Features/Persistence/Blockcore.Features.Base.Persistence.LevelDb/Blockcore.Features.Base.Persistence.LevelDb.csproj b/src/Features/Persistence/Blockcore.Features.Base.Persistence.LevelDb/Blockcore.Features.Base.Persistence.LevelDb.csproj new file mode 100644 index 000000000..c962f5947 --- /dev/null +++ b/src/Features/Persistence/Blockcore.Features.Base.Persistence.LevelDb/Blockcore.Features.Base.Persistence.LevelDb.csproj @@ -0,0 +1,28 @@ + + + + LevelDb persistence for Blockcore Base feature + Blockcore.Features.Base.Persistence.LevelDb + Blockcore.Features.Base.Persistence.LevelDb + Blockcore.Features.Base.Persistence.LevelDb + False + Blockcore + true + + + + + + + + + + + + + + + 1701;1702;1705;IDE0008; + + + \ No newline at end of file diff --git a/src/Blockcore/Consensus/Chain/LeveldbChainStore.cs b/src/Features/Persistence/Blockcore.Features.Base.Persistence.LevelDb/LevelDbChainStore.cs similarity index 94% rename from src/Blockcore/Consensus/Chain/LeveldbChainStore.cs rename to src/Features/Persistence/Blockcore.Features.Base.Persistence.LevelDb/LevelDbChainStore.cs index 83f3f222d..19d1070a2 100644 --- a/src/Blockcore/Consensus/Chain/LeveldbChainStore.cs +++ b/src/Features/Persistence/Blockcore.Features.Base.Persistence.LevelDb/LevelDbChainStore.cs @@ -1,15 +1,17 @@ using System; using System.Collections.Generic; using Blockcore.Configuration; +using Blockcore.Consensus; using Blockcore.Consensus.BlockInfo; +using Blockcore.Consensus.Chain; using Blockcore.Networks; using Blockcore.Utilities; using LevelDB; using NBitcoin; -namespace Blockcore.Consensus.Chain +namespace Blockcore.Features.Base.Persistence.LevelDb { - public class LeveldbChainStore : IChainStore, IDisposable + public class LevelDbChainStore : IChainStore, IDisposable { private readonly Network network; @@ -30,7 +32,7 @@ public class LeveldbChainStore : IChainStore, IDisposable private object locker; - public LeveldbChainStore(Network network, DataFolder dataFolder, ChainIndexer chainIndexer) + public LevelDbChainStore(Network network, DataFolder dataFolder, ChainIndexer chainIndexer) { this.network = network; this.ChainIndexer = chainIndexer; diff --git a/src/Blockcore/Utilities/Store/LeveldbKeyValueRepository.cs b/src/Features/Persistence/Blockcore.Features.Base.Persistence.LevelDb/LevelDbKeyValueRepository.cs similarity index 89% rename from src/Blockcore/Utilities/Store/LeveldbKeyValueRepository.cs rename to src/Features/Persistence/Blockcore.Features.Base.Persistence.LevelDb/LevelDbKeyValueRepository.cs index bbdc820c1..8dc1037f5 100644 --- a/src/Blockcore/Utilities/Store/LeveldbKeyValueRepository.cs +++ b/src/Features/Persistence/Blockcore.Features.Base.Persistence.LevelDb/LevelDbKeyValueRepository.cs @@ -1,23 +1,25 @@ using System.IO; using System.Text; using Blockcore.Configuration; +using Blockcore.Utilities; using Blockcore.Utilities.JsonConverters; +using Blockcore.Utilities.Store; using LevelDB; -namespace Blockcore.Utilities.Store +namespace Blockcore.Features.Base.Persistence.LevelDb { - public class LeveldbKeyValueRepository : IKeyValueRepository + public class LevelDbKeyValueRepository : IKeyValueRepository { /// Access to database. private readonly DB leveldb; private readonly DataStoreSerializer dataStoreSerializer; - public LeveldbKeyValueRepository(DataFolder dataFolder, DataStoreSerializer dataStoreSerializer) : this(dataFolder.KeyValueRepositoryPath, dataStoreSerializer) + public LevelDbKeyValueRepository(DataFolder dataFolder, DataStoreSerializer dataStoreSerializer) : this(dataFolder.KeyValueRepositoryPath, dataStoreSerializer) { } - public LeveldbKeyValueRepository(string folder, DataStoreSerializer dataStoreSerializer) + public LevelDbKeyValueRepository(string folder, DataStoreSerializer dataStoreSerializer) { Directory.CreateDirectory(folder); this.dataStoreSerializer = dataStoreSerializer; diff --git a/src/Features/Persistence/Blockcore.Features.Base.Persistence.LevelDb/PersistenceProvider.cs b/src/Features/Persistence/Blockcore.Features.Base.Persistence.LevelDb/PersistenceProvider.cs new file mode 100644 index 000000000..a424250de --- /dev/null +++ b/src/Features/Persistence/Blockcore.Features.Base.Persistence.LevelDb/PersistenceProvider.cs @@ -0,0 +1,20 @@ +using Blockcore.Base; +using Blockcore.Consensus.Chain; +using Blockcore.Persistence; +using Blockcore.Persistence.LevelDb; +using Blockcore.Utilities.Store; +using Microsoft.Extensions.DependencyInjection; + +namespace Blockcore.Features.Base.Persistence.LevelDb +{ + public class PersistenceProvider : PersistenceProviderBase + { + public override string Tag => LevelDbPersistence.Name; + + public override void AddRequiredServices(IServiceCollection services) + { + services.AddSingleton(); + services.AddSingleton(); + } + } +} \ No newline at end of file diff --git a/src/Features/Persistence/Blockcore.Features.Base.Persistence.RocksDb/Blockcore.Features.Base.Persistence.RocksDb.csproj b/src/Features/Persistence/Blockcore.Features.Base.Persistence.RocksDb/Blockcore.Features.Base.Persistence.RocksDb.csproj new file mode 100644 index 000000000..a9563ab37 --- /dev/null +++ b/src/Features/Persistence/Blockcore.Features.Base.Persistence.RocksDb/Blockcore.Features.Base.Persistence.RocksDb.csproj @@ -0,0 +1,28 @@ + + + + RocksDb persistence for Blockcore Base feature + Blockcore.Features.Base.Persistence.RocksDb + Blockcore.Features.Base.Persistence.RocksDb + Blockcore.Features.Base.Persistence.RocksDb + False + Blockcore + true + + + + + + + + + + + + + + + 1701;1702;1705;IDE0008; + + + \ No newline at end of file diff --git a/src/Features/Persistence/Blockcore.Features.Base.Persistence.RocksDb/PersistenceProvider.cs b/src/Features/Persistence/Blockcore.Features.Base.Persistence.RocksDb/PersistenceProvider.cs new file mode 100644 index 000000000..e64c3cbf2 --- /dev/null +++ b/src/Features/Persistence/Blockcore.Features.Base.Persistence.RocksDb/PersistenceProvider.cs @@ -0,0 +1,20 @@ +using Blockcore.Base; +using Blockcore.Consensus.Chain; +using Blockcore.Persistence; +using Blockcore.Persistence.RocksDb; +using Blockcore.Utilities.Store; +using Microsoft.Extensions.DependencyInjection; + +namespace Blockcore.Features.Base.Persistence.RocksDb +{ + public class PersistenceProvider : PersistenceProviderBase + { + public override string Tag => RocksDbPersistence.Name; + + public override void AddRequiredServices(IServiceCollection services) + { + services.AddSingleton(); + services.AddSingleton(); + } + } +} \ No newline at end of file diff --git a/src/Blockcore/Consensus/Chain/RocksdbChainStore.cs b/src/Features/Persistence/Blockcore.Features.Base.Persistence.RocksDb/RocksDbChainStore.cs similarity index 87% rename from src/Blockcore/Consensus/Chain/RocksdbChainStore.cs rename to src/Features/Persistence/Blockcore.Features.Base.Persistence.RocksDb/RocksDbChainStore.cs index 08c9c8062..0593a5bf5 100644 --- a/src/Blockcore/Consensus/Chain/RocksdbChainStore.cs +++ b/src/Features/Persistence/Blockcore.Features.Base.Persistence.RocksDb/RocksDbChainStore.cs @@ -1,15 +1,23 @@ using System; using System.Collections.Generic; using Blockcore.Configuration; +using Blockcore.Consensus; using Blockcore.Consensus.BlockInfo; +using Blockcore.Consensus.Chain; using Blockcore.Networks; using Blockcore.Utilities; using NBitcoin; using RocksDbSharp; +using DB = RocksDbSharp.RocksDb; -namespace Blockcore.Consensus.Chain +namespace Blockcore.Features.Base.Persistence.RocksDb { - public class RocksdbChainStore : IChainStore, IDisposable + /// + /// Rocksdb implementation of the chain storage + /// + /// + /// + public class RocksDbChainStore : IChainStore, IDisposable { private readonly Network network; @@ -26,11 +34,11 @@ public class RocksdbChainStore : IChainStore, IDisposable /// private readonly MemoryCountCache recentHeaders; - private readonly RocksDb rocksdb; + private readonly DB rocksdb; private object locker; - public RocksdbChainStore(Network network, DataFolder dataFolder, ChainIndexer chainIndexer) + public RocksDbChainStore(Network network, DataFolder dataFolder, ChainIndexer chainIndexer) { this.network = network; this.ChainIndexer = chainIndexer; @@ -40,7 +48,7 @@ public RocksdbChainStore(Network network, DataFolder dataFolder, ChainIndexer ch // Open a connection to a new DB and create if not found var options = new DbOptions().SetCreateIfMissing(true); - this.rocksdb = RocksDb.Open(options, dataFolder.ChainPath); + this.rocksdb = DB.Open(options, dataFolder.ChainPath); } public ChainIndexer ChainIndexer { get; } diff --git a/src/Blockcore/Utilities/Store/RocksdbKeyValueRepository.cs b/src/Features/Persistence/Blockcore.Features.Base.Persistence.RocksDb/RocksDbKeyValueRepository.cs similarity index 84% rename from src/Blockcore/Utilities/Store/RocksdbKeyValueRepository.cs rename to src/Features/Persistence/Blockcore.Features.Base.Persistence.RocksDb/RocksDbKeyValueRepository.cs index ee1e63fa5..cfe2a462c 100644 --- a/src/Blockcore/Utilities/Store/RocksdbKeyValueRepository.cs +++ b/src/Features/Persistence/Blockcore.Features.Base.Persistence.RocksDb/RocksDbKeyValueRepository.cs @@ -1,30 +1,33 @@ using System.IO; using System.Text; using Blockcore.Configuration; +using Blockcore.Utilities; using Blockcore.Utilities.JsonConverters; +using Blockcore.Utilities.Store; using RocksDbSharp; +using DB = RocksDbSharp.RocksDb; -namespace Blockcore.Utilities.Store +namespace Blockcore.Features.Base.Persistence.RocksDb { - public class RocksdbKeyValueRepository : IKeyValueRepository + public class RocksDbKeyValueRepository : IKeyValueRepository { /// Access to database. - private readonly RocksDb rocksdb; + private readonly DB rocksdb; private readonly DataStoreSerializer dataStoreSerializer; - public RocksdbKeyValueRepository(DataFolder dataFolder, DataStoreSerializer dataStoreSerializer) : this(dataFolder.KeyValueRepositoryPath, dataStoreSerializer) + public RocksDbKeyValueRepository(DataFolder dataFolder, DataStoreSerializer dataStoreSerializer) : this(dataFolder.KeyValueRepositoryPath, dataStoreSerializer) { } - public RocksdbKeyValueRepository(string folder, DataStoreSerializer dataStoreSerializer) + public RocksDbKeyValueRepository(string folder, DataStoreSerializer dataStoreSerializer) { Directory.CreateDirectory(folder); this.dataStoreSerializer = dataStoreSerializer; // Open a connection to a new DB and create if not found var options = new DbOptions().SetCreateIfMissing(true); - this.rocksdb = RocksDb.Open(options, folder); + this.rocksdb = DB.Open(options, folder); } /// diff --git a/src/Features/Persistence/Blockcore.Features.BlockStore.Persistence.LevelDb/Blockcore.Features.BlockStore.Persistence.LevelDb.csproj b/src/Features/Persistence/Blockcore.Features.BlockStore.Persistence.LevelDb/Blockcore.Features.BlockStore.Persistence.LevelDb.csproj new file mode 100644 index 000000000..21d55e628 --- /dev/null +++ b/src/Features/Persistence/Blockcore.Features.BlockStore.Persistence.LevelDb/Blockcore.Features.BlockStore.Persistence.LevelDb.csproj @@ -0,0 +1,29 @@ + + + + LevelDb persistence for Blockcore BlockStore feature + Blockcore.Features.BlockStore.Persistence.LevelDb + Blockcore.Features.BlockStore.Persistence.LevelDb + Blockcore.Features.BlockStore.Persistence.LevelDb + False + Blockcore + true + + + + + + + + + + + + + + + + 1701;1702;1705;IDE0008; + + + \ No newline at end of file diff --git a/src/Features/Blockcore.Features.BlockStore/Repository/LeveldbBlockRepository.cs b/src/Features/Persistence/Blockcore.Features.BlockStore.Persistence.LevelDb/LevelDbBlockRepository.cs similarity index 97% rename from src/Features/Blockcore.Features.BlockStore/Repository/LeveldbBlockRepository.cs rename to src/Features/Persistence/Blockcore.Features.BlockStore.Persistence.LevelDb/LevelDbBlockRepository.cs index 683fe1360..9df96876d 100644 --- a/src/Features/Blockcore.Features.BlockStore/Repository/LeveldbBlockRepository.cs +++ b/src/Features/Persistence/Blockcore.Features.BlockStore.Persistence.LevelDb/LevelDbBlockRepository.cs @@ -8,6 +8,7 @@ using Blockcore.Consensus.BlockInfo; using Blockcore.Consensus.Chain; using Blockcore.Consensus.TransactionInfo; +using Blockcore.Features.BlockStore.Repository; using Blockcore.Networks; using Blockcore.Utilities; using DBreeze.Utils; @@ -15,13 +16,13 @@ using Microsoft.Extensions.Logging; using NBitcoin; -namespace Blockcore.Features.BlockStore.Repository +namespace Blockcore.Features.BlockStore.Persistence.LevelDb { - public class LeveldbBlockRepository : IBlockRepository + public class LevelDbBlockRepository : IBlockRepository { - internal static readonly byte BlockTableName = 1; - internal static readonly byte CommonTableName = 2; - internal static readonly byte TransactionTableName = 3; + public static readonly byte BlockTableName = 1; + public static readonly byte CommonTableName = 2; + public static readonly byte TransactionTableName = 3; private readonly DB leveldb; @@ -46,13 +47,13 @@ public class LeveldbBlockRepository : IBlockRepository private readonly DataStoreSerializer dataStoreSerializer; private readonly IReadOnlyDictionary genesisTransactions; - public LeveldbBlockRepository(Network network, DataFolder dataFolder, + public LevelDbBlockRepository(Network network, DataFolder dataFolder, ILoggerFactory loggerFactory, DataStoreSerializer dataStoreSerializer) : this(network, dataFolder.BlockPath, loggerFactory, dataStoreSerializer) { } - public LeveldbBlockRepository(Network network, string folder, ILoggerFactory loggerFactory, DataStoreSerializer dataStoreSerializer) + public LevelDbBlockRepository(Network network, string folder, ILoggerFactory loggerFactory, DataStoreSerializer dataStoreSerializer) { Guard.NotNull(network, nameof(network)); Guard.NotEmpty(folder, nameof(folder)); diff --git a/src/Features/Blockcore.Features.BlockStore/Pruning/RocksdbPrunedBlockRepository.cs b/src/Features/Persistence/Blockcore.Features.BlockStore.Persistence.LevelDb/LevelDbPrunedBlockRepository.cs similarity index 69% rename from src/Features/Blockcore.Features.BlockStore/Pruning/RocksdbPrunedBlockRepository.cs rename to src/Features/Persistence/Blockcore.Features.BlockStore.Persistence.LevelDb/LevelDbPrunedBlockRepository.cs index 05e8cd9b7..f685786a9 100644 --- a/src/Features/Blockcore.Features.BlockStore/Pruning/RocksdbPrunedBlockRepository.cs +++ b/src/Features/Persistence/Blockcore.Features.BlockStore.Persistence.LevelDb/LevelDbPrunedBlockRepository.cs @@ -1,23 +1,17 @@ -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Blockcore.Consensus.BlockInfo; +using Blockcore.Consensus.BlockInfo; using Blockcore.Consensus.Chain; +using Blockcore.Features.BlockStore.Pruning; using Blockcore.Features.BlockStore.Repository; using Blockcore.Networks; using Blockcore.Utilities; -using DBreeze.DataTypes; using LevelDB; using Microsoft.Extensions.Logging; -using NBitcoin; -using RocksDbSharp; - -namespace Blockcore.Features.BlockStore.Pruning +namespace Blockcore.Features.BlockStore.Persistence.LevelDb { /// - public class RocksdbPrunedBlockRepository : IPrunedBlockRepository + public class LevelDbPrunedBlockRepository : IPrunedBlockRepository { private readonly IBlockRepository blockRepository; @@ -30,7 +24,7 @@ public class RocksdbPrunedBlockRepository : IPrunedBlockRepository /// public HashHeightPair PrunedTip { get; private set; } - public RocksdbPrunedBlockRepository(IBlockRepository blockRepository, DataStoreSerializer dataStoreSerializer, ILoggerFactory loggerFactory, StoreSettings storeSettings, Network network) + public LevelDbPrunedBlockRepository(IBlockRepository blockRepository, DataStoreSerializer dataStoreSerializer, ILoggerFactory loggerFactory, StoreSettings storeSettings, Network network) { this.blockRepository = blockRepository; @@ -44,7 +38,7 @@ public RocksdbPrunedBlockRepository(IBlockRepository blockRepository, DataStoreS /// public void Initialize() { - this.LoadPrunedTip((RocksDb)this.blockRepository.DbInstance); + this.LoadPrunedTip((DB)this.blockRepository.DbInstance); } /// @@ -58,21 +52,21 @@ public void PrepareDatabase() lock (this.blockRepository.Locker) { - ((RocksDb)this.blockRepository.DbInstance).Put(DBH.Key(RocksdbBlockRepository.CommonTableName, prunedTipKey), this.dataStoreSerializer.Serialize(this.PrunedTip)); + ((DB)this.blockRepository.DbInstance).Put(DBH.Key(LevelDbBlockRepository.CommonTableName, prunedTipKey), this.dataStoreSerializer.Serialize(this.PrunedTip)); } } return; } - private void LoadPrunedTip(RocksDbSharp.RocksDb rocksdb) + private void LoadPrunedTip(DB db) { if (this.PrunedTip == null) { lock (this.blockRepository.Locker) { - byte[] row = rocksdb.Get(DBH.Key(RocksdbBlockRepository.CommonTableName, prunedTipKey)); + byte[] row = db.Get(DBH.Key(LevelDbBlockRepository.CommonTableName, prunedTipKey)); if (row != null) { this.PrunedTip = this.dataStoreSerializer.Deserialize(row); @@ -88,7 +82,7 @@ public void UpdatePrunedTip(ChainedHeader tip) lock (this.blockRepository.Locker) { - ((RocksDb)this.blockRepository.DbInstance).Put(DBH.Key(RocksdbBlockRepository.CommonTableName, prunedTipKey), this.dataStoreSerializer.Serialize(this.PrunedTip)); + ((DB)this.blockRepository.DbInstance).Put(DBH.Key(LevelDbBlockRepository.CommonTableName, prunedTipKey), this.dataStoreSerializer.Serialize(this.PrunedTip)); } } } diff --git a/src/Features/Persistence/Blockcore.Features.BlockStore.Persistence.LevelDb/PersistenceProvider.cs b/src/Features/Persistence/Blockcore.Features.BlockStore.Persistence.LevelDb/PersistenceProvider.cs new file mode 100644 index 000000000..c7fdc916c --- /dev/null +++ b/src/Features/Persistence/Blockcore.Features.BlockStore.Persistence.LevelDb/PersistenceProvider.cs @@ -0,0 +1,19 @@ +using Blockcore.Features.BlockStore.Pruning; +using Blockcore.Features.BlockStore.Repository; +using Blockcore.Persistence; +using Blockcore.Persistence.LevelDb; +using Microsoft.Extensions.DependencyInjection; + +namespace Blockcore.Features.BlockStore.Persistence.LevelDb +{ + public class PersistenceProvider : PersistenceProviderBase + { + public override string Tag => LevelDbPersistence.Name; + + public override void AddRequiredServices(IServiceCollection services) + { + services.AddSingleton(); + services.AddSingleton(); + } + } +} \ No newline at end of file diff --git a/src/Features/Persistence/Blockcore.Features.BlockStore.Persistence.RocksDb/Blockcore.Features.BlockStore.Persistence.RocksDb.csproj b/src/Features/Persistence/Blockcore.Features.BlockStore.Persistence.RocksDb/Blockcore.Features.BlockStore.Persistence.RocksDb.csproj new file mode 100644 index 000000000..3792e1ece --- /dev/null +++ b/src/Features/Persistence/Blockcore.Features.BlockStore.Persistence.RocksDb/Blockcore.Features.BlockStore.Persistence.RocksDb.csproj @@ -0,0 +1,29 @@ + + + + RocksDb persistence for Blockcore BlockStore feature + Blockcore.Features.BlockStore.Persistence.RocksDb + Blockcore.Features.BlockStore.Persistence.RocksDb + Blockcore.Features.BlockStore.Persistence.RocksDb + False + Blockcore + true + + + + + + + + + + + + + + + + 1701;1702;1705;IDE0008; + + + \ No newline at end of file diff --git a/src/Features/Persistence/Blockcore.Features.BlockStore.Persistence.RocksDb/PersistenceProvider.cs b/src/Features/Persistence/Blockcore.Features.BlockStore.Persistence.RocksDb/PersistenceProvider.cs new file mode 100644 index 000000000..2656eefe8 --- /dev/null +++ b/src/Features/Persistence/Blockcore.Features.BlockStore.Persistence.RocksDb/PersistenceProvider.cs @@ -0,0 +1,19 @@ +using Blockcore.Features.BlockStore.Pruning; +using Blockcore.Features.BlockStore.Repository; +using Blockcore.Persistence; +using Blockcore.Persistence.RocksDb; +using Microsoft.Extensions.DependencyInjection; + +namespace Blockcore.Features.BlockStore.Persistence.RocksDb +{ + public class PersistenceProvider : PersistenceProviderBase + { + public override string Tag => RocksDbPersistence.Name; + + public override void AddRequiredServices(IServiceCollection services) + { + services.AddSingleton(); + services.AddSingleton(); + } + } +} \ No newline at end of file diff --git a/src/Features/Blockcore.Features.BlockStore/Repository/RocksdbBlockRepository.cs b/src/Features/Persistence/Blockcore.Features.BlockStore.Persistence.RocksDb/RocksDbBlockRepository.cs similarity index 97% rename from src/Features/Blockcore.Features.BlockStore/Repository/RocksdbBlockRepository.cs rename to src/Features/Persistence/Blockcore.Features.BlockStore.Persistence.RocksDb/RocksDbBlockRepository.cs index 1632de5c7..f5cd50ca1 100644 --- a/src/Features/Blockcore.Features.BlockStore/Repository/RocksdbBlockRepository.cs +++ b/src/Features/Persistence/Blockcore.Features.BlockStore.Persistence.RocksDb/RocksDbBlockRepository.cs @@ -8,22 +8,24 @@ using Blockcore.Consensus.BlockInfo; using Blockcore.Consensus.Chain; using Blockcore.Consensus.TransactionInfo; +using Blockcore.Features.BlockStore.Repository; using Blockcore.Networks; using Blockcore.Utilities; using DBreeze.Utils; using Microsoft.Extensions.Logging; using NBitcoin; using RocksDbSharp; +using DB = RocksDbSharp.RocksDb; -namespace Blockcore.Features.BlockStore.Repository +namespace Blockcore.Features.BlockStore.Persistence.RocksDb { public class RocksdbBlockRepository : IBlockRepository { - internal static readonly byte BlockTableName = 1; - internal static readonly byte CommonTableName = 2; - internal static readonly byte TransactionTableName = 3; + public static readonly byte BlockTableName = 1; + public static readonly byte CommonTableName = 2; + public static readonly byte TransactionTableName = 3; - private readonly RocksDb rocksdb; + private readonly DB rocksdb; public object Locker { get; } @@ -59,7 +61,7 @@ public RocksdbBlockRepository(Network network, string folder, ILoggerFactory log Directory.CreateDirectory(folder); var options = new DbOptions().SetCreateIfMissing(true); - this.rocksdb = RocksDb.Open(options, folder); + this.rocksdb = DB.Open(options, folder); this.Locker = new object(); this.logger = loggerFactory.CreateLogger(this.GetType().FullName); diff --git a/src/Features/Blockcore.Features.BlockStore/Pruning/LeveldbPrunedBlockRepository.cs b/src/Features/Persistence/Blockcore.Features.BlockStore.Persistence.RocksDb/RocksDbPrunedBlockRepository.cs similarity index 82% rename from src/Features/Blockcore.Features.BlockStore/Pruning/LeveldbPrunedBlockRepository.cs rename to src/Features/Persistence/Blockcore.Features.BlockStore.Persistence.RocksDb/RocksDbPrunedBlockRepository.cs index d5a54e0ac..dda79dc13 100644 --- a/src/Features/Blockcore.Features.BlockStore/Pruning/LeveldbPrunedBlockRepository.cs +++ b/src/Features/Persistence/Blockcore.Features.BlockStore.Persistence.RocksDb/RocksDbPrunedBlockRepository.cs @@ -1,21 +1,17 @@ -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Blockcore.Consensus.BlockInfo; +using Blockcore.Consensus.BlockInfo; using Blockcore.Consensus.Chain; using Blockcore.Features.BlockStore.Repository; using Blockcore.Networks; using Blockcore.Utilities; -using DBreeze.DataTypes; -using LevelDB; using Microsoft.Extensions.Logging; -using NBitcoin; +using DB = RocksDbSharp.RocksDb; +using Blockcore.Features.BlockStore.Pruning; -namespace Blockcore.Features.BlockStore.Pruning +namespace Blockcore.Features.BlockStore.Persistence.RocksDb { /// - public class LeveldbPrunedBlockRepository : IPrunedBlockRepository + public class RocksDbPrunedBlockRepository : IPrunedBlockRepository { private readonly IBlockRepository blockRepository; @@ -28,7 +24,7 @@ public class LeveldbPrunedBlockRepository : IPrunedBlockRepository /// public HashHeightPair PrunedTip { get; private set; } - public LeveldbPrunedBlockRepository(IBlockRepository blockRepository, DataStoreSerializer dataStoreSerializer, ILoggerFactory loggerFactory, StoreSettings storeSettings, Network network) + public RocksDbPrunedBlockRepository(IBlockRepository blockRepository, DataStoreSerializer dataStoreSerializer, ILoggerFactory loggerFactory, StoreSettings storeSettings, Network network) { this.blockRepository = blockRepository; @@ -56,7 +52,7 @@ public void PrepareDatabase() lock (this.blockRepository.Locker) { - ((DB)this.blockRepository.DbInstance).Put(DBH.Key(LeveldbBlockRepository.CommonTableName, prunedTipKey), this.dataStoreSerializer.Serialize(this.PrunedTip)); + ((DB)this.blockRepository.DbInstance).Put(DBH.Key(RocksdbBlockRepository.CommonTableName, prunedTipKey), this.dataStoreSerializer.Serialize(this.PrunedTip)); } } @@ -70,7 +66,7 @@ private void LoadPrunedTip(DB rocksdb) lock (this.blockRepository.Locker) { - byte[] row = rocksdb.Get(DBH.Key(LeveldbBlockRepository.CommonTableName, prunedTipKey)); + byte[] row = rocksdb.Get(DBH.Key(RocksdbBlockRepository.CommonTableName, prunedTipKey)); if (row != null) { this.PrunedTip = this.dataStoreSerializer.Deserialize(row); @@ -86,7 +82,7 @@ public void UpdatePrunedTip(ChainedHeader tip) lock (this.blockRepository.Locker) { - ((DB)this.blockRepository.DbInstance).Put(DBH.Key(LeveldbBlockRepository.CommonTableName, prunedTipKey), this.dataStoreSerializer.Serialize(this.PrunedTip)); + ((DB)this.blockRepository.DbInstance).Put(DBH.Key(RocksdbBlockRepository.CommonTableName, prunedTipKey), this.dataStoreSerializer.Serialize(this.PrunedTip)); } } } diff --git a/src/Features/Persistence/Blockcore.Features.Consensus.Persistence.LevelDb/Blockcore.Features.Consensus.Persistence.LevelDb.csproj b/src/Features/Persistence/Blockcore.Features.Consensus.Persistence.LevelDb/Blockcore.Features.Consensus.Persistence.LevelDb.csproj new file mode 100644 index 000000000..c41283fab --- /dev/null +++ b/src/Features/Persistence/Blockcore.Features.Consensus.Persistence.LevelDb/Blockcore.Features.Consensus.Persistence.LevelDb.csproj @@ -0,0 +1,29 @@ + + + + LevelDb persistence for Blockcore Consensus feature + Blockcore.Features.Consensus.Persistence.LevelDb + Blockcore.Features.Consensus.Persistence.LevelDb + Blockcore.Features.Consensus.Persistence.LevelDb + False + Blockcore + true + + + + + + + + + + + + + + + + 1701;1702;1705;IDE0008; + + + \ No newline at end of file diff --git a/src/Features/Blockcore.Features.Consensus/CoinViews/Coindb/LeveldbCoindb.cs b/src/Features/Persistence/Blockcore.Features.Consensus.Persistence.LevelDb/LevelDbCoindb.cs similarity index 96% rename from src/Features/Blockcore.Features.Consensus/CoinViews/Coindb/LeveldbCoindb.cs rename to src/Features/Persistence/Blockcore.Features.Consensus.Persistence.LevelDb/LevelDbCoindb.cs index 9354ec3f7..840f9bdd6 100644 --- a/src/Features/Blockcore.Features.Consensus/CoinViews/Coindb/LeveldbCoindb.cs +++ b/src/Features/Persistence/Blockcore.Features.Consensus.Persistence.LevelDb/LevelDbCoindb.cs @@ -5,18 +5,20 @@ using Blockcore.Configuration; using Blockcore.Consensus.BlockInfo; using Blockcore.Consensus.TransactionInfo; +using Blockcore.Features.Consensus.CoinViews; +using Blockcore.Features.Consensus.CoinViews.Coindb; using Blockcore.Networks; using Blockcore.Utilities; using LevelDB; using Microsoft.Extensions.Logging; using NBitcoin; -namespace Blockcore.Features.Consensus.CoinViews.Coindb +namespace Blockcore.Features.Consensus.Persistence.LevelDb { /// /// Persistent implementation of coinview using dBreeze database. /// - public class LeveldbCoindb : ICoindb, IStakdb, IDisposable + public class LevelDbCoindb : ICoindb, IStakdb, IDisposable { /// Database key under which the block hash of the coin view's current tip is stored. private static readonly byte[] blockHashKey = new byte[0]; @@ -45,13 +47,13 @@ public class LeveldbCoindb : ICoindb, IStakdb, IDisposable private DataStoreSerializer dataStoreSerializer; - public LeveldbCoindb(Network network, DataFolder dataFolder, IDateTimeProvider dateTimeProvider, + public LevelDbCoindb(Network network, DataFolder dataFolder, IDateTimeProvider dateTimeProvider, ILoggerFactory loggerFactory, INodeStats nodeStats, DataStoreSerializer dataStoreSerializer) : this(network, dataFolder.CoindbPath, dateTimeProvider, loggerFactory, nodeStats, dataStoreSerializer) { } - public LeveldbCoindb(Network network, string folder, IDateTimeProvider dateTimeProvider, + public LevelDbCoindb(Network network, string folder, IDateTimeProvider dateTimeProvider, ILoggerFactory loggerFactory, INodeStats nodeStats, DataStoreSerializer dataStoreSerializer) { Guard.NotNull(network, nameof(network)); @@ -276,7 +278,7 @@ public void GetStake(IEnumerable blocklist) private void AddBenchStats(StringBuilder log) { - log.AppendLine("======Leveldb Bench======"); + log.AppendLine("======LevelDb Bench======"); BackendPerformanceSnapshot snapShot = this.performanceCounter.Snapshot(); diff --git a/src/Features/Blockcore.Features.Consensus/ProvenBlockHeaders/LeveldbProvenBlockHeaderRepository.cs b/src/Features/Persistence/Blockcore.Features.Consensus.Persistence.LevelDb/LevelDbProvenBlockHeaderRepository.cs similarity index 96% rename from src/Features/Blockcore.Features.Consensus/ProvenBlockHeaders/LeveldbProvenBlockHeaderRepository.cs rename to src/Features/Persistence/Blockcore.Features.Consensus.Persistence.LevelDb/LevelDbProvenBlockHeaderRepository.cs index 4ca36a8da..8711f7fdd 100644 --- a/src/Features/Blockcore.Features.Consensus/ProvenBlockHeaders/LeveldbProvenBlockHeaderRepository.cs +++ b/src/Features/Persistence/Blockcore.Features.Consensus.Persistence.LevelDb/LevelDbProvenBlockHeaderRepository.cs @@ -8,17 +8,16 @@ using Blockcore.Interfaces; using Blockcore.Networks; using Blockcore.Utilities; -using DBreeze.Utils; using LevelDB; using Microsoft.Extensions.Logging; using NBitcoin; -namespace Blockcore.Features.Consensus.ProvenBlockHeaders +namespace Blockcore.Features.Consensus.Persistence.LevelDb { /// /// Persistent implementation of the DBreeze repository. /// - public class LeveldbProvenBlockHeaderRepository : IProvenBlockHeaderRepository + public class LevelDbProvenBlockHeaderRepository : IProvenBlockHeaderRepository { /// /// Instance logger. @@ -62,7 +61,7 @@ public class LeveldbProvenBlockHeaderRepository : IProvenBlockHeaderRepository /// folder path to the DBreeze database files. /// Factory to create a logger for this type. /// The serializer to use for objects. - public LeveldbProvenBlockHeaderRepository(Network network, DataFolder folder, ILoggerFactory loggerFactory, + public LevelDbProvenBlockHeaderRepository(Network network, DataFolder folder, ILoggerFactory loggerFactory, DataStoreSerializer dataStoreSerializer) : this(network, folder.ProvenBlockHeaderPath, loggerFactory, dataStoreSerializer) { @@ -75,7 +74,7 @@ public LeveldbProvenBlockHeaderRepository(Network network, DataFolder folder, IL /// folder path to the DBreeze database files. /// Factory to create a logger for this type. /// The serializer to use for objects. - public LeveldbProvenBlockHeaderRepository(Network network, string folder, ILoggerFactory loggerFactory, + public LevelDbProvenBlockHeaderRepository(Network network, string folder, ILoggerFactory loggerFactory, DataStoreSerializer dataStoreSerializer) { Guard.NotNull(network, nameof(network)); diff --git a/src/Features/Persistence/Blockcore.Features.Consensus.Persistence.LevelDb/PersistenceProvider.cs b/src/Features/Persistence/Blockcore.Features.Consensus.Persistence.LevelDb/PersistenceProvider.cs new file mode 100644 index 000000000..bec452b5c --- /dev/null +++ b/src/Features/Persistence/Blockcore.Features.Consensus.Persistence.LevelDb/PersistenceProvider.cs @@ -0,0 +1,19 @@ +using Blockcore.Features.Consensus.CoinViews.Coindb; +using Blockcore.Interfaces; +using Blockcore.Persistence; +using Blockcore.Persistence.LevelDb; +using Microsoft.Extensions.DependencyInjection; + +namespace Blockcore.Features.Consensus.Persistence.LevelDb +{ + public class PersistenceProvider : PersistenceProviderBase + { + public override string Tag => LevelDbPersistence.Name; + + public override void AddRequiredServices(IServiceCollection services) + { + services.AddSingleton(); + services.AddSingleton(); + } + } +} \ No newline at end of file diff --git a/src/Features/Persistence/Blockcore.Features.Consensus.Persistence.RocksDb/Blockcore.Features.Consensus.Persistence.RocksDb.csproj b/src/Features/Persistence/Blockcore.Features.Consensus.Persistence.RocksDb/Blockcore.Features.Consensus.Persistence.RocksDb.csproj new file mode 100644 index 000000000..ad7055ec5 --- /dev/null +++ b/src/Features/Persistence/Blockcore.Features.Consensus.Persistence.RocksDb/Blockcore.Features.Consensus.Persistence.RocksDb.csproj @@ -0,0 +1,29 @@ + + + + RocksDb persistence for Blockcore Consensus feature + Blockcore.Features.Consensus.Persistence.RocksDb + Blockcore.Features.Consensus.Persistence.RocksDb + Blockcore.Features.Consensus.Persistence.RocksDb + False + Blockcore + true + + + + + + + + + + + + + + + + 1701;1702;1705;IDE0008; + + + \ No newline at end of file diff --git a/src/Features/Persistence/Blockcore.Features.Consensus.Persistence.RocksDb/PersistenceProvider.cs b/src/Features/Persistence/Blockcore.Features.Consensus.Persistence.RocksDb/PersistenceProvider.cs new file mode 100644 index 000000000..9118c0481 --- /dev/null +++ b/src/Features/Persistence/Blockcore.Features.Consensus.Persistence.RocksDb/PersistenceProvider.cs @@ -0,0 +1,19 @@ +using Blockcore.Features.Consensus.CoinViews.Coindb; +using Blockcore.Interfaces; +using Blockcore.Persistence; +using Blockcore.Persistence.RocksDb; +using Microsoft.Extensions.DependencyInjection; + +namespace Blockcore.Features.Consensus.Persistence.RocksDb +{ + public class PersistenceProvider : PersistenceProviderBase + { + public override string Tag => RocksDbPersistence.Name; + + public override void AddRequiredServices(IServiceCollection services) + { + services.AddSingleton(); + services.AddSingleton(); + } + } +} \ No newline at end of file diff --git a/src/Features/Persistence/Blockcore.Features.Consensus.Persistence.RocksDb/RocksDbCoindb .cs b/src/Features/Persistence/Blockcore.Features.Consensus.Persistence.RocksDb/RocksDbCoindb .cs new file mode 100644 index 000000000..e386f3c93 --- /dev/null +++ b/src/Features/Persistence/Blockcore.Features.Consensus.Persistence.RocksDb/RocksDbCoindb .cs @@ -0,0 +1,300 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Blockcore.Configuration; +using Blockcore.Consensus.BlockInfo; +using Blockcore.Consensus.TransactionInfo; +using Blockcore.Features.Consensus.CoinViews; +using Blockcore.Features.Consensus.CoinViews.Coindb; +using Blockcore.Networks; +using Blockcore.Utilities; +using Microsoft.Extensions.Logging; +using NBitcoin; +using RocksDbSharp; +using DB = RocksDbSharp.RocksDb; + +namespace Blockcore.Features.Consensus.Persistence.RocksDb +{ + /// + /// Persistent implementation of coinview using dBreeze database. + /// + public class RocksDbCoindb : ICoindb, IStakdb, IDisposable + { + /// Database key under which the block hash of the coin view's current tip is stored. + private static readonly byte[] blockHashKey = new byte[0]; + + private static readonly byte coinsTable = 1; + private static readonly byte blockTable = 2; + private static readonly byte rewindTable = 3; + private static readonly byte stakeTable = 4; + + /// Instance logger. + private readonly ILogger logger; + + /// Specification of the network the node runs on - regtest/testnet/mainnet. + private readonly Network network; + + /// Hash of the block which is currently the tip of the coinview. + private HashHeightPair blockHash; + + /// Performance counter to measure performance of the database insert and query operations. + private readonly BackendPerformanceCounter performanceCounter; + + private BackendPerformanceSnapshot latestPerformanceSnapShot; + + /// Access to rocksdb database. + private readonly DB rocksdb; + + private DataStoreSerializer dataStoreSerializer; + + public RocksDbCoindb(Network network, DataFolder dataFolder, IDateTimeProvider dateTimeProvider, + ILoggerFactory loggerFactory, INodeStats nodeStats, DataStoreSerializer dataStoreSerializer) + : this(network, dataFolder.CoindbPath, dateTimeProvider, loggerFactory, nodeStats, dataStoreSerializer) + { + } + + public RocksDbCoindb(Network network, string folder, IDateTimeProvider dateTimeProvider, + ILoggerFactory loggerFactory, INodeStats nodeStats, DataStoreSerializer dataStoreSerializer) + { + Guard.NotNull(network, nameof(network)); + Guard.NotEmpty(folder, nameof(folder)); + + this.dataStoreSerializer = dataStoreSerializer; + + this.logger = loggerFactory.CreateLogger(this.GetType().FullName); + + // Open a connection to a new DB and create if not found + var options = new DbOptions().SetCreateIfMissing(true); + this.rocksdb = DB.Open(options, folder); + + this.network = network; + this.performanceCounter = new BackendPerformanceCounter(dateTimeProvider); + + nodeStats.RegisterStats(this.AddBenchStats, StatsType.Benchmark, this.GetType().Name, 400); + } + + public void Initialize() + { + Block genesis = this.network.GetGenesis(); + + if (this.GetTipHash() == null) + { + this.SetBlockHash(new HashHeightPair(genesis.GetHash(), 0)); + } + } + + private void SetBlockHash(HashHeightPair nextBlockHash) + { + this.blockHash = nextBlockHash; + this.rocksdb.Put(new byte[] { blockTable }.Concat(blockHashKey).ToArray(), nextBlockHash.ToBytes()); + } + + public HashHeightPair GetTipHash() + { + if (this.blockHash == null) + { + var row = this.rocksdb.Get(new byte[] { blockTable }.Concat(blockHashKey).ToArray()); + if (row != null) + { + this.blockHash = new HashHeightPair(); + this.blockHash.FromBytes(row); + } + } + + return this.blockHash; + } + + public FetchCoinsResponse FetchCoins(OutPoint[] utxos) + { + FetchCoinsResponse res = new FetchCoinsResponse(); + + using (new StopwatchDisposable(o => this.performanceCounter.AddQueryTime(o))) + { + this.performanceCounter.AddQueriedEntities(utxos.Length); + + foreach (OutPoint outPoint in utxos) + { + byte[] row = this.rocksdb.Get(new byte[] { coinsTable }.Concat(outPoint.ToBytes()).ToArray()); + Coins outputs = row != null ? this.dataStoreSerializer.Deserialize(row) : null; + + this.logger.LogDebug("Outputs for '{0}' were {1}.", outPoint, outputs == null ? "NOT loaded" : "loaded"); + + res.UnspentOutputs.Add(outPoint, new UnspentOutput(outPoint, outputs)); + } + } + + return res; + } + + public void SaveChanges(IList unspentOutputs, HashHeightPair oldBlockHash, HashHeightPair nextBlockHash, List rewindDataList = null) + { + int insertedEntities = 0; + + using (var batch = new WriteBatch()) + { + using (new StopwatchDisposable(o => this.performanceCounter.AddInsertTime(o))) + { + HashHeightPair current = this.GetTipHash(); + if (current != oldBlockHash) + { + this.logger.LogTrace("(-)[BLOCKHASH_MISMATCH]"); + throw new InvalidOperationException("Invalid oldBlockHash"); + } + + // Here we'll add items to be inserted in a second pass. + List toInsert = new List(); + + foreach (var coin in unspentOutputs.OrderBy(utxo => utxo.OutPoint, new OutPointComparer())) + { + if (coin.Coins == null) + { + this.logger.LogDebug("Outputs of transaction ID '{0}' are prunable and will be removed from the database.", coin.OutPoint); + batch.Delete(new byte[] { coinsTable }.Concat(coin.OutPoint.ToBytes()).ToArray()); + } + else + { + // Add the item to another list that will be used in the second pass. + // This is for performance reasons: dBreeze is optimized to run the same kind of operations, sorted. + toInsert.Add(coin); + } + } + + for (int i = 0; i < toInsert.Count; i++) + { + var coin = toInsert[i]; + this.logger.LogDebug("Outputs of transaction ID '{0}' are NOT PRUNABLE and will be inserted into the database. {1}/{2}.", coin.OutPoint, i, toInsert.Count); + + batch.Put(new byte[] { coinsTable }.Concat(coin.OutPoint.ToBytes()).ToArray(), this.dataStoreSerializer.Serialize(coin.Coins)); + } + + if (rewindDataList != null) + { + foreach (RewindData rewindData in rewindDataList) + { + var nextRewindIndex = rewindData.PreviousBlockHash.Height + 1; + + this.logger.LogDebug("Rewind state #{0} created.", nextRewindIndex); + + batch.Put(new byte[] { rewindTable }.Concat(BitConverter.GetBytes(nextRewindIndex)).ToArray(), this.dataStoreSerializer.Serialize(rewindData)); + } + } + + insertedEntities += unspentOutputs.Count; + this.rocksdb.Write(batch); + + this.SetBlockHash(nextBlockHash); + } + } + + this.performanceCounter.AddInsertedEntities(insertedEntities); + } + + /// + public HashHeightPair Rewind() + { + HashHeightPair res = null; + using (var batch = new WriteBatch()) + { + HashHeightPair current = this.GetTipHash(); + + byte[] row = this.rocksdb.Get(new byte[] { rewindTable }.Concat(BitConverter.GetBytes(current.Height)).ToArray()); + + if (row == null) + { + throw new InvalidOperationException($"No rewind data found for block `{current}`"); + } + + batch.Delete(BitConverter.GetBytes(current.Height)); + + var rewindData = this.dataStoreSerializer.Deserialize(row); + + foreach (OutPoint outPoint in rewindData.OutputsToRemove) + { + this.logger.LogDebug("Outputs of outpoint '{0}' will be removed.", outPoint); + batch.Delete(new byte[] { coinsTable }.Concat(outPoint.ToBytes()).ToArray()); + } + + foreach (RewindDataOutput rewindDataOutput in rewindData.OutputsToRestore) + { + this.logger.LogDebug("Outputs of outpoint '{0}' will be restored.", rewindDataOutput.OutPoint); + batch.Put(new byte[] { coinsTable }.Concat(rewindDataOutput.OutPoint.ToBytes()).ToArray(), this.dataStoreSerializer.Serialize(rewindDataOutput.Coins)); + } + + res = rewindData.PreviousBlockHash; + + this.rocksdb.Write(batch); + + this.SetBlockHash(rewindData.PreviousBlockHash); + } + + return res; + } + + public RewindData GetRewindData(int height) + { + byte[] row = this.rocksdb.Get(new byte[] { rewindTable }.Concat(BitConverter.GetBytes(height)).ToArray()); + return row != null ? this.dataStoreSerializer.Deserialize(row) : null; + } + + /// + /// Persists unsaved POS blocks information to the database. + /// + /// List of POS block information to be examined and persists if unsaved. + public void PutStake(IEnumerable stakeEntries) + { + using (var batch = new WriteBatch()) + { + foreach (StakeItem stakeEntry in stakeEntries) + { + if (!stakeEntry.InStore) + { + batch.Put(new byte[] { stakeTable }.Concat(stakeEntry.BlockId.ToBytes(false)).ToArray(), this.dataStoreSerializer.Serialize(stakeEntry.BlockStake)); + stakeEntry.InStore = true; + } + } + + this.rocksdb.Write(batch); + } + } + + /// + /// Retrieves POS blocks information from the database. + /// + /// List of partially initialized POS block information that is to be fully initialized with the values from the database. + public void GetStake(IEnumerable blocklist) + { + foreach (StakeItem blockStake in blocklist) + { + this.logger.LogDebug("Loading POS block hash '{0}' from the database.", blockStake.BlockId); + byte[] stakeRow = this.rocksdb.Get(new byte[] { stakeTable }.Concat(blockStake.BlockId.ToBytes(false)).ToArray()); + + if (stakeRow != null) + { + blockStake.BlockStake = this.dataStoreSerializer.Deserialize(stakeRow); + blockStake.InStore = true; + } + } + } + + private void AddBenchStats(StringBuilder log) + { + log.AppendLine("======LevelDb Bench======"); + + BackendPerformanceSnapshot snapShot = this.performanceCounter.Snapshot(); + + if (this.latestPerformanceSnapShot == null) + log.AppendLine(snapShot.ToString()); + else + log.AppendLine((snapShot - this.latestPerformanceSnapShot).ToString()); + + this.latestPerformanceSnapShot = snapShot; + } + + /// + public void Dispose() + { + this.rocksdb.Dispose(); + } + } +} \ No newline at end of file diff --git a/src/Features/Persistence/Blockcore.Features.Consensus.Persistence.RocksDb/RocksDbProvenBlockHeaderRepository.cs b/src/Features/Persistence/Blockcore.Features.Consensus.Persistence.RocksDb/RocksDbProvenBlockHeaderRepository.cs new file mode 100644 index 000000000..99abc64cc --- /dev/null +++ b/src/Features/Persistence/Blockcore.Features.Consensus.Persistence.RocksDb/RocksDbProvenBlockHeaderRepository.cs @@ -0,0 +1,223 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using Blockcore.Configuration; +using Blockcore.Consensus.BlockInfo; +using Blockcore.Interfaces; +using Blockcore.Networks; +using Blockcore.Utilities; +using Microsoft.Extensions.Logging; +using NBitcoin; +using RocksDbSharp; +using DB = RocksDbSharp.RocksDb; + +namespace Blockcore.Features.Consensus.Persistence.RocksDb +{ + /// + /// Persistent implementation of the DBreeze repository. + /// + public class RocksDbProvenBlockHeaderRepository : IProvenBlockHeaderRepository + { + /// + /// Instance logger. + /// + private readonly ILogger logger; + + /// + /// Access to database. + /// + private readonly DB rocksdb; + + private object locker; + + /// + /// Specification of the network the node runs on - RegTest/TestNet/MainNet. + /// + private readonly Network network; + + /// + /// Database key under which the block hash and height of a tip is stored. + /// + private static readonly byte[] blockHashHeightKey = new byte[] { 1 }; + + private static readonly byte provenBlockHeaderTable = 1; + private static readonly byte blockHashHeightTable = 2; + + /// + /// Current tip. + /// + private ProvenBlockHeader provenBlockHeaderTip; + + private readonly DataStoreSerializer dataStoreSerializer; + + /// + public HashHeightPair TipHashHeight { get; private set; } + + /// + /// Initializes a new instance of the object. + /// + /// Specification of the network the node runs on - RegTest/TestNet/MainNet. + /// folder path to the DBreeze database files. + /// Factory to create a logger for this type. + /// The serializer to use for objects. + public RocksDbProvenBlockHeaderRepository(Network network, DataFolder folder, ILoggerFactory loggerFactory, + DataStoreSerializer dataStoreSerializer) + : this(network, folder.ProvenBlockHeaderPath, loggerFactory, dataStoreSerializer) + { + } + + /// + /// Initializes a new instance of the object. + /// + /// Specification of the network the node runs on - RegTest/TestNet/MainNet. + /// folder path to the DBreeze database files. + /// Factory to create a logger for this type. + /// The serializer to use for objects. + public RocksDbProvenBlockHeaderRepository(Network network, string folder, ILoggerFactory loggerFactory, + DataStoreSerializer dataStoreSerializer) + { + Guard.NotNull(network, nameof(network)); + Guard.NotNull(folder, nameof(folder)); + this.dataStoreSerializer = dataStoreSerializer; + + this.logger = loggerFactory.CreateLogger(this.GetType().FullName); + + Directory.CreateDirectory(folder); + + // Open a connection to a new DB and create if not found + var options = new DbOptions().SetCreateIfMissing(true); + this.rocksdb = DB.Open(options, folder); + + this.locker = new object(); + + this.network = network; + } + + /// + public Task InitializeAsync() + { + Task task = Task.Run(() => + { + this.TipHashHeight = this.GetTipHash(); + + if (this.TipHashHeight != null) + return; + + var hashHeight = new HashHeightPair(this.network.GetGenesis().GetHash(), 0); + + this.SetTip(hashHeight); + + this.TipHashHeight = hashHeight; + }); + + return task; + } + + /// + public Task GetAsync(int blockHeight) + { + var task = Task.Run((Func)(() => + { + byte[] row = null; + + lock (this.locker) + { + row = this.rocksdb.Get(DBH.Key(provenBlockHeaderTable, BitConverter.GetBytes(blockHeight))); + } + + if (row != null) + return this.dataStoreSerializer.Deserialize(row); + + return null; + })); + + return task; + } + + /// + public Task PutAsync(SortedDictionary headers, HashHeightPair newTip) + { + Guard.NotNull(headers, nameof(headers)); + Guard.NotNull(newTip, nameof(newTip)); + + Guard.Assert(newTip.Hash == headers.Values.Last().GetHash()); + + Task task = Task.Run(() => + { + this.logger.LogDebug("({0}.Count():{1})", nameof(headers), headers.Count()); + + this.InsertHeaders(headers); + + this.SetTip(newTip); + + this.TipHashHeight = newTip; + }); + + return task; + } + + /// + /// Set's the hash and height tip of the new . + /// + /// Open DBreeze transaction. + /// Hash height pair of the new block tip. + private void SetTip(HashHeightPair newTip) + { + Guard.NotNull(newTip, nameof(newTip)); + + lock (this.locker) + { + this.rocksdb.Put(DBH.Key(blockHashHeightTable, blockHashHeightKey), this.dataStoreSerializer.Serialize(newTip)); + } + } + + /// + /// Inserts items into to the database. + /// + /// List of items to save. + private void InsertHeaders(SortedDictionary headers) + { + using (var batch = new WriteBatch()) + { + foreach (KeyValuePair header in headers) + batch.Put(DBH.Key(provenBlockHeaderTable, BitConverter.GetBytes(header.Key)), this.dataStoreSerializer.Serialize(header.Value)); + + lock (this.locker) + { + this.rocksdb.Write(batch); + } + } + + // Store the latest ProvenBlockHeader in memory. + this.provenBlockHeaderTip = headers.Last().Value; + } + + /// + /// Retrieves the current tip from disk. + /// + /// Hash of blocks current tip. + private HashHeightPair GetTipHash() + { + HashHeightPair tipHash = null; + + byte[] row = null; + lock (this.locker) + { + row = this.rocksdb.Get(DBH.Key(blockHashHeightTable, blockHashHeightKey)); + } + + if (row != null) + tipHash = this.dataStoreSerializer.Deserialize(row); + + return tipHash; + } + + /// + public void Dispose() + { + this.rocksdb?.Dispose(); + } + } +} \ No newline at end of file diff --git a/src/Features/Persistence/Blockcore.Features.Persistence.LevelDb.CorePackage/Blockcore.Features.Persistence.LevelDb.CorePackage.csproj b/src/Features/Persistence/Blockcore.Features.Persistence.LevelDb.CorePackage/Blockcore.Features.Persistence.LevelDb.CorePackage.csproj new file mode 100644 index 000000000..75ab916e8 --- /dev/null +++ b/src/Features/Persistence/Blockcore.Features.Persistence.LevelDb.CorePackage/Blockcore.Features.Persistence.LevelDb.CorePackage.csproj @@ -0,0 +1,28 @@ + + + + LevelDb persistence package for core features + Blockcore.Features.Persistence.LevelDb.Package + Blockcore.Features.Persistence.LevelDb.Package + Blockcore.Features.Persistence.LevelDb.Package + False + Blockcore + true + + + + + + + + + + + + + + + 1701;1702;1705;IDE0008; + + + \ No newline at end of file diff --git a/src/Features/Persistence/Blockcore.Features.Persistence.Rocksdb.CorePackage/Blockcore.Features.Persistence.Rocksdb.CorePackage.csproj b/src/Features/Persistence/Blockcore.Features.Persistence.Rocksdb.CorePackage/Blockcore.Features.Persistence.Rocksdb.CorePackage.csproj new file mode 100644 index 000000000..b57874f19 --- /dev/null +++ b/src/Features/Persistence/Blockcore.Features.Persistence.Rocksdb.CorePackage/Blockcore.Features.Persistence.Rocksdb.CorePackage.csproj @@ -0,0 +1,28 @@ + + + + RocksDb persistence package for core features + Blockcore.Features.Persistence.Rocksdb.CorePackage + Blockcore.Features.Persistence.Rocksdb.CorePackage + Blockcore.Features.Persistence.Rocksdb.CorePackage + False + Blockcore + true + + + + + + + + + + + + + + + 1701;1702;1705;IDE0008; + + + \ No newline at end of file diff --git a/src/Features/Persistence/Blockcore.Persistence.LevelDb/Blockcore.Persistence.LevelDb.csproj b/src/Features/Persistence/Blockcore.Persistence.LevelDb/Blockcore.Persistence.LevelDb.csproj new file mode 100644 index 000000000..9bd6d0764 --- /dev/null +++ b/src/Features/Persistence/Blockcore.Persistence.LevelDb/Blockcore.Persistence.LevelDb.csproj @@ -0,0 +1,28 @@ + + + + LevelDb persistence common classes + Blockcore.Persistence.LevelDb + Blockcore.Persistence.LevelDb + Blockcore.Persistence.LevelDb + False + Blockcore + true + + + + + + + + + + + + + + + 1701;1702;1705;IDE0008; + + + \ No newline at end of file diff --git a/src/Features/Persistence/Blockcore.Persistence.LevelDb/Extensions/DictionaryExtensions.cs b/src/Features/Persistence/Blockcore.Persistence.LevelDb/Extensions/DictionaryExtensions.cs new file mode 100644 index 000000000..466454a12 --- /dev/null +++ b/src/Features/Persistence/Blockcore.Persistence.LevelDb/Extensions/DictionaryExtensions.cs @@ -0,0 +1,21 @@ +using LevelDB; + +namespace System.Collections.Generic +{ + public static class DictionaryExtensions + { + public static Dictionary SelectDictionary(this DB db, byte table) + { + var dict = new Dictionary(); + + var enumerator = db.GetEnumerator(); + while (enumerator.MoveNext()) + { + if (enumerator.Current.Key[0] == table) + dict.Add(enumerator.Current.Key.AsSpan().Slice(1).ToArray(), enumerator.Current.Value); + } + + return dict; + } + } +} diff --git a/src/Features/Persistence/Blockcore.Persistence.LevelDb/LevelDbPersistence.cs b/src/Features/Persistence/Blockcore.Persistence.LevelDb/LevelDbPersistence.cs new file mode 100644 index 000000000..128b7be5d --- /dev/null +++ b/src/Features/Persistence/Blockcore.Persistence.LevelDb/LevelDbPersistence.cs @@ -0,0 +1,13 @@ +namespace Blockcore.Persistence.LevelDb +{ + /// + /// Constants used to + /// + public static class LevelDbPersistence + { + /// + /// Gets the persistence implementation name. + /// + public static string Name => "LevelDB"; + } +} diff --git a/src/Features/Persistence/Blockcore.Persistence.RocksDb/Blockcore.Persistence.RocksDb.csproj b/src/Features/Persistence/Blockcore.Persistence.RocksDb/Blockcore.Persistence.RocksDb.csproj new file mode 100644 index 000000000..f0818ee30 --- /dev/null +++ b/src/Features/Persistence/Blockcore.Persistence.RocksDb/Blockcore.Persistence.RocksDb.csproj @@ -0,0 +1,29 @@ + + + + RocksDb persistence common classes + Blockcore.Persistence.RocksDb + Blockcore.Persistence.RocksDb + Blockcore.Persistence.RocksDb + False + Blockcore + true + + + + + + + + + + + + + + + + 1701;1702;1705;IDE0008; + + + \ No newline at end of file diff --git a/src/Features/Persistence/Blockcore.Persistence.RocksDb/Extensions/DictionaryExtensions.cs b/src/Features/Persistence/Blockcore.Persistence.RocksDb/Extensions/DictionaryExtensions.cs new file mode 100644 index 000000000..8341aa41c --- /dev/null +++ b/src/Features/Persistence/Blockcore.Persistence.RocksDb/Extensions/DictionaryExtensions.cs @@ -0,0 +1,21 @@ +using RocksDbSharp; + +namespace System.Collections.Generic +{ + public static class DictionaryExtensions + { + public static Dictionary SelectDictionary(this RocksDb db, byte table) + { + var dict = new Dictionary(); + + var enumerator = db.NewIterator(); + for (enumerator.SeekToFirst(); enumerator.Valid(); enumerator.Next()) + { + if (enumerator.Key()[0] == table) + dict.Add(enumerator.Key().AsSpan().Slice(1).ToArray(), enumerator.Value()); + } + + return dict; + } + } +} diff --git a/src/Features/Persistence/Blockcore.Persistence.RocksDb/RocksDbPersistence.cs b/src/Features/Persistence/Blockcore.Persistence.RocksDb/RocksDbPersistence.cs new file mode 100644 index 000000000..e0cf50707 --- /dev/null +++ b/src/Features/Persistence/Blockcore.Persistence.RocksDb/RocksDbPersistence.cs @@ -0,0 +1,13 @@ +namespace Blockcore.Persistence.RocksDb +{ + /// + /// Constants used to + /// + public static class RocksDbPersistence + { + /// + /// Gets the persistence implementation name. + /// + public static string Name => "RocksDB"; + } +} diff --git a/src/Networks/Bitcoin/Bitcoind/BitcoinD.csproj b/src/Networks/Bitcoin/Bitcoind/BitcoinD.csproj index 4c1acba0f..089e38a10 100644 --- a/src/Networks/Bitcoin/Bitcoind/BitcoinD.csproj +++ b/src/Networks/Bitcoin/Bitcoind/BitcoinD.csproj @@ -23,6 +23,8 @@ + + \ No newline at end of file diff --git a/src/Networks/Bitcoin/Bitcoind/Program.cs b/src/Networks/Bitcoin/Bitcoind/Program.cs index 60e1a3ff0..5d9eade9d 100644 --- a/src/Networks/Bitcoin/Bitcoind/Program.cs +++ b/src/Networks/Bitcoin/Bitcoind/Program.cs @@ -13,6 +13,7 @@ using Blockcore.Networks; using Blockcore.Networks.Bitcoin; using Blockcore.Utilities; +using Blockcore.Utilities.Store; namespace BitcoinD { diff --git a/src/Networks/City/City.Node/City.Node.csproj b/src/Networks/City/City.Node/City.Node.csproj index 5e55b48e8..c3da77b5b 100644 --- a/src/Networks/City/City.Node/City.Node.csproj +++ b/src/Networks/City/City.Node/City.Node.csproj @@ -20,6 +20,8 @@ + + diff --git a/src/Networks/City/City.Node/Program.cs b/src/Networks/City/City.Node/Program.cs index e3a643644..336775279 100644 --- a/src/Networks/City/City.Node/Program.cs +++ b/src/Networks/City/City.Node/Program.cs @@ -12,8 +12,6 @@ using Blockcore.Features.Miner; using Blockcore.Features.RPC; using Blockcore.Utilities; -using NBitcoin; -using NBitcoin.Protocol; namespace City.Daemon { diff --git a/src/Networks/OpenExo/OpenExo.Node/OpenExo.Node.csproj b/src/Networks/OpenExo/OpenExo.Node/OpenExo.Node.csproj index a5d2fae73..26dfae87e 100644 --- a/src/Networks/OpenExo/OpenExo.Node/OpenExo.Node.csproj +++ b/src/Networks/OpenExo/OpenExo.Node/OpenExo.Node.csproj @@ -21,6 +21,8 @@ + + diff --git a/src/Networks/OpenExo/OpenExo.Node/Program.cs b/src/Networks/OpenExo/OpenExo.Node/Program.cs index 129bf3d79..f9a6ce697 100644 --- a/src/Networks/OpenExo/OpenExo.Node/Program.cs +++ b/src/Networks/OpenExo/OpenExo.Node/Program.cs @@ -13,7 +13,6 @@ using Blockcore.Features.Miner; using Blockcore.Features.RPC; using Blockcore.Utilities; -using NBitcoin.Protocol; namespace OpenExo.Node { @@ -32,7 +31,7 @@ public static async Task Main(string[] args) .UseMempool() .AddPowPosMining() .UseColdStakingWallet() - .UseDiagnosticFeature() + .UseDiagnosticFeature() .UseNodeHost() .AddRPC(); diff --git a/src/Networks/Rutanio/Rutanio.Node/Program.cs b/src/Networks/Rutanio/Rutanio.Node/Program.cs index e396265a4..0641c0786 100644 --- a/src/Networks/Rutanio/Rutanio.Node/Program.cs +++ b/src/Networks/Rutanio/Rutanio.Node/Program.cs @@ -13,7 +13,6 @@ using Blockcore.Features.Miner; using Blockcore.Features.RPC; using Blockcore.Utilities; -using NBitcoin.Protocol; namespace Rutanio.Daemon { diff --git a/src/Networks/Rutanio/Rutanio.Node/Rutanio.Node.csproj b/src/Networks/Rutanio/Rutanio.Node/Rutanio.Node.csproj index d13eb693e..6b38cc441 100644 --- a/src/Networks/Rutanio/Rutanio.Node/Rutanio.Node.csproj +++ b/src/Networks/Rutanio/Rutanio.Node/Rutanio.Node.csproj @@ -1,29 +1,31 @@ - - Rutanio.Node - Exe - Blockcore - + + Rutanio.Node + Exe + Blockcore + - - latest - + + latest + - - - - - - - - - - - - + + + + + + + + + + + + + + - - - + + + \ No newline at end of file diff --git a/src/Networks/Stratis/StratisDns/Program.cs b/src/Networks/Stratis/StratisDns/Program.cs index 321f4d7aa..b1e611b5d 100644 --- a/src/Networks/Stratis/StratisDns/Program.cs +++ b/src/Networks/Stratis/StratisDns/Program.cs @@ -11,10 +11,8 @@ using Blockcore.Features.Miner; using Blockcore.Features.RPC; using Blockcore.Features.Wallet; -using Blockcore.Networks; using Blockcore.Networks.Stratis; using Blockcore.Utilities; -using NBitcoin.Protocol; namespace StratisDnsD { @@ -33,7 +31,6 @@ public static async Task Main(string[] args) try { var nodeSettings = new NodeSettings(networksSelector: Networks.Stratis, args: args); - var dnsSettings = new DnsSettings(nodeSettings); if (string.IsNullOrWhiteSpace(dnsSettings.DnsHostName) || string.IsNullOrWhiteSpace(dnsSettings.DnsNameServer) || string.IsNullOrWhiteSpace(dnsSettings.DnsMailBox)) diff --git a/src/Networks/Stratis/StratisDns/StratisDnsD.csproj b/src/Networks/Stratis/StratisDns/StratisDnsD.csproj index a4bb72b0f..8c124f8f2 100644 --- a/src/Networks/Stratis/StratisDns/StratisDnsD.csproj +++ b/src/Networks/Stratis/StratisDns/StratisDnsD.csproj @@ -25,5 +25,7 @@ + + \ No newline at end of file diff --git a/src/Networks/Stratis/Stratisd/Program.cs b/src/Networks/Stratis/Stratisd/Program.cs index 20f6d6e76..a0722b5b5 100644 --- a/src/Networks/Stratis/Stratisd/Program.cs +++ b/src/Networks/Stratis/Stratisd/Program.cs @@ -11,10 +11,8 @@ using Blockcore.Features.MemoryPool; using Blockcore.Features.Miner; using Blockcore.Features.RPC; -using Blockcore.Networks; using Blockcore.Networks.Stratis; using Blockcore.Utilities; -using NBitcoin.Protocol; namespace StratisD { diff --git a/src/Networks/Stratis/Stratisd/StratisD.csproj b/src/Networks/Stratis/Stratisd/StratisD.csproj index 62b1f9a32..c9d32b854 100644 --- a/src/Networks/Stratis/Stratisd/StratisD.csproj +++ b/src/Networks/Stratis/Stratisd/StratisD.csproj @@ -26,5 +26,7 @@ + + \ No newline at end of file diff --git a/src/Networks/Xds/Xdsd/Program.cs b/src/Networks/Xds/Xdsd/Program.cs index 04366b1a9..c782b136b 100644 --- a/src/Networks/Xds/Xdsd/Program.cs +++ b/src/Networks/Xds/Xdsd/Program.cs @@ -12,7 +12,6 @@ using Blockcore.Features.RPC; using Blockcore.Networks.Xds; using Blockcore.Utilities; -using NBitcoin.Protocol; namespace StratisD { @@ -27,7 +26,7 @@ public static async Task Main(string[] args) { var nodeSettings = new NodeSettings(networksSelector: Networks.Xds, args: args); - IFullNodeBuilder nodeBuilder = new FullNodeBuilder() + IFullNodeBuilder nodeBuilder = new FullNodeBuilder() .UseNodeSettings(nodeSettings) .UseBlockStore() .UsePosConsensus() diff --git a/src/Networks/Xds/Xdsd/Properties/launchSettings.json b/src/Networks/Xds/Xdsd/Properties/launchSettings.json index 550fd70ff..5c2e6015b 100644 --- a/src/Networks/Xds/Xdsd/Properties/launchSettings.json +++ b/src/Networks/Xds/Xdsd/Properties/launchSettings.json @@ -2,7 +2,15 @@ "profiles": { "Xds": { "commandName": "Project", - "commandLineArgs": "-addnode=159.65.148.135" + "commandLineArgs": "-addnode=178.62.62.160 -datadir=C:\\testtttt -apiport=48339" + }, + "RocksDb": { + "commandName": "Project", + "commandLineArgs": "-addnode=178.62.62.160 -datadir=C:\\testtttt\\rocksdb -dbtype=rocksdb -apiport=48339" + }, + "LevelDb": { + "commandName": "Project", + "commandLineArgs": "-addnode=178.62.62.160 -datadir=C:\\testtttt\\leveldb -dbtype=leveldb -apiport=48339" } } } \ No newline at end of file diff --git a/src/Networks/Xds/Xdsd/XdsD.csproj b/src/Networks/Xds/Xdsd/XdsD.csproj index e3c1c99cc..a3918379d 100644 --- a/src/Networks/Xds/Xdsd/XdsD.csproj +++ b/src/Networks/Xds/Xdsd/XdsD.csproj @@ -26,5 +26,7 @@ + + \ No newline at end of file diff --git a/src/Networks/x42/x42.Node/x42.Node.csproj b/src/Networks/x42/x42.Node/x42.Node.csproj index 3ef743d3d..850b9a5e1 100644 --- a/src/Networks/x42/x42.Node/x42.Node.csproj +++ b/src/Networks/x42/x42.Node/x42.Node.csproj @@ -22,6 +22,8 @@ + + \ No newline at end of file diff --git a/src/Node/Blockcore.Node/Blockcore.Node.csproj b/src/Node/Blockcore.Node/Blockcore.Node.csproj index 2271030b4..a3a052133 100644 --- a/src/Node/Blockcore.Node/Blockcore.Node.csproj +++ b/src/Node/Blockcore.Node/Blockcore.Node.csproj @@ -18,7 +18,7 @@ - + @@ -26,6 +26,8 @@ + + diff --git a/src/Node/Blockcore.Node/NodeBuilder.cs b/src/Node/Blockcore.Node/NodeBuilder.cs index 6e729a69b..a86609266 100644 --- a/src/Node/Blockcore.Node/NodeBuilder.cs +++ b/src/Node/Blockcore.Node/NodeBuilder.cs @@ -10,11 +10,14 @@ using Blockcore.Features.Wallet; using Blockcore.Features.NodeHost; using Blockcore.Features.Dns; +using Blockcore.Persistence; namespace Blockcore.Node { public static class NodeBuilder { + public static PersistenceProviderManager persistenceProviderManager; + public static IFullNodeBuilder Create(string chain, NodeSettings settings) { chain = chain.ToUpperInvariant(); @@ -64,6 +67,6 @@ static void UseDnsFullNode(IFullNodeBuilder nodeBuilder, NodeSettings nodeSettin nodeBuilder.UseDns(); } - } + } } } diff --git a/src/Tests/Blockcore.Features.BlockStore.Tests/BlockRepositoryTests.cs b/src/Tests/Blockcore.Features.BlockStore.Tests/BlockRepositoryTests.cs index d1ab5ba6c..9cab31acf 100644 --- a/src/Tests/Blockcore.Features.BlockStore.Tests/BlockRepositoryTests.cs +++ b/src/Tests/Blockcore.Features.BlockStore.Tests/BlockRepositoryTests.cs @@ -3,6 +3,7 @@ using System.Linq; using Blockcore.Consensus.BlockInfo; using Blockcore.Consensus.TransactionInfo; +using Blockcore.Features.BlockStore.Persistence.RocksDb; using Blockcore.Features.BlockStore.Repository; using Blockcore.Networks; using Blockcore.Tests.Common.Logging; diff --git a/src/Tests/Blockcore.Features.BlockStore.Tests/Blockcore.Features.BlockStore.Tests.csproj b/src/Tests/Blockcore.Features.BlockStore.Tests/Blockcore.Features.BlockStore.Tests.csproj index f423c7f4b..d81618d16 100644 --- a/src/Tests/Blockcore.Features.BlockStore.Tests/Blockcore.Features.BlockStore.Tests.csproj +++ b/src/Tests/Blockcore.Features.BlockStore.Tests/Blockcore.Features.BlockStore.Tests.csproj @@ -18,6 +18,8 @@ + + all runtime; build; native; contentfiles; analyzers @@ -25,6 +27,7 @@ + diff --git a/src/Tests/Blockcore.Features.Consensus.Tests/CoinViews/CoinviewTests.cs b/src/Tests/Blockcore.Features.Consensus.Tests/CoinViews/CoinviewTests.cs index 1c01e5df4..36e761a9c 100644 --- a/src/Tests/Blockcore.Features.Consensus.Tests/CoinViews/CoinviewTests.cs +++ b/src/Tests/Blockcore.Features.Consensus.Tests/CoinViews/CoinviewTests.cs @@ -12,6 +12,7 @@ using Blockcore.Consensus.TransactionInfo; using Blockcore.Features.Consensus.CoinViews; using Blockcore.Features.Consensus.CoinViews.Coindb; +using Blockcore.Features.Consensus.Persistence.LevelDb; using Blockcore.Features.Consensus.ProvenBlockHeaders; using Blockcore.Networks; using Blockcore.Networks.Stratis; @@ -49,7 +50,7 @@ public CoinviewTests() //this.coindb = new DBreezeCoindb(this.network, this.dataFolder, this.dateTimeProvider, this.loggerFactory, this.nodeStats, new DataStoreSerializer(this.network.Consensus.ConsensusFactory)); //this.coindb = new FasterCoindb(this.network, this.dataFolder, this.dateTimeProvider, this.loggerFactory, this.nodeStats, new DataStoreSerializer(this.network.Consensus.ConsensusFactory)); - this.coindb = new LeveldbCoindb(this.network, this.dataFolder, this.dateTimeProvider, this.loggerFactory, this.nodeStats, new DataStoreSerializer(this.network.Consensus.ConsensusFactory)); + this.coindb = new LevelDbCoindb(this.network, this.dataFolder, this.dateTimeProvider, this.loggerFactory, this.nodeStats, new DataStoreSerializer(this.network.Consensus.ConsensusFactory)); this.coindb.Initialize(); this.chainIndexer = new ChainIndexer(this.network); diff --git a/src/Tests/Blockcore.Features.Consensus.Tests/ProvenBlockHeaders/ProvenBlockHeaderRepositoryTests.cs b/src/Tests/Blockcore.Features.Consensus.Tests/ProvenBlockHeaders/ProvenBlockHeaderRepositoryTests.cs index ebee70467..98e898426 100644 --- a/src/Tests/Blockcore.Features.Consensus.Tests/ProvenBlockHeaders/ProvenBlockHeaderRepositoryTests.cs +++ b/src/Tests/Blockcore.Features.Consensus.Tests/ProvenBlockHeaders/ProvenBlockHeaderRepositoryTests.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Threading.Tasks; using Blockcore.Consensus.BlockInfo; +using Blockcore.Features.Consensus.Persistence.LevelDb; using Blockcore.Features.Consensus.ProvenBlockHeaders; using Blockcore.Interfaces; using Blockcore.Networks; @@ -122,7 +123,7 @@ public async Task GetAsync_ReadsProvenBlockHeaderAsync() } // Query the repository for the item that was inserted in the above code. - using (LeveldbProvenBlockHeaderRepository repo = this.SetupRepository(this.Network, folder)) + using (LevelDbProvenBlockHeaderRepository repo = this.SetupRepository(this.Network, folder)) { var headerOut = await repo.GetAsync(blockHeight).ConfigureAwait(false); @@ -142,7 +143,7 @@ public async Task GetAsync_WithWrongBlockHeightReturnsNullAsync() engine.Put(DBH.Key(BlockHashHeightTable, new byte[0]), this.DataStoreSerializer.Serialize(new HashHeightPair(new uint256(), 1))); } - using (LeveldbProvenBlockHeaderRepository repo = this.SetupRepository(this.Network, folder)) + using (LevelDbProvenBlockHeaderRepository repo = this.SetupRepository(this.Network, folder)) { // Select a different block height. ProvenBlockHeader outHeader = await repo.GetAsync(2).ConfigureAwait(false); @@ -180,9 +181,9 @@ public async Task PutAsyncsDisposeOnInitialiseShouldBeAtLastSavedTipAsync() } } - private LeveldbProvenBlockHeaderRepository SetupRepository(Network network, string folder) + private LevelDbProvenBlockHeaderRepository SetupRepository(Network network, string folder) { - var repo = new LeveldbProvenBlockHeaderRepository(network, folder, this.LoggerFactory.Object, this.dataStoreSerializer); + var repo = new LevelDbProvenBlockHeaderRepository(network, folder, this.LoggerFactory.Object, this.dataStoreSerializer); Task task = repo.InitializeAsync(); diff --git a/src/Tests/Blockcore.Features.Consensus.Tests/ProvenBlockHeaders/ProvenBlockHeaderStoreTests.cs b/src/Tests/Blockcore.Features.Consensus.Tests/ProvenBlockHeaders/ProvenBlockHeaderStoreTests.cs index f75118737..eb8a2ce26 100644 --- a/src/Tests/Blockcore.Features.Consensus.Tests/ProvenBlockHeaders/ProvenBlockHeaderStoreTests.cs +++ b/src/Tests/Blockcore.Features.Consensus.Tests/ProvenBlockHeaders/ProvenBlockHeaderStoreTests.cs @@ -6,6 +6,7 @@ using System.Threading.Tasks; using Blockcore.Consensus.BlockInfo; using Blockcore.Consensus.Chain; +using Blockcore.Features.Consensus.Persistence.LevelDb; using Blockcore.Features.Consensus.ProvenBlockHeaders; using Blockcore.Interfaces; using Blockcore.Networks; @@ -39,7 +40,7 @@ public ProvenBlockHeaderStoreTests() : base(new StratisTest()) var ibdMock = new Mock(); ibdMock.Setup(s => s.IsInitialBlockDownload()).Returns(false); - this.provenBlockHeaderRepository = new LeveldbProvenBlockHeaderRepository(this.Network, CreateTestDir(this), this.LoggerFactory.Object, dBreezeSerializer); + this.provenBlockHeaderRepository = new LevelDbProvenBlockHeaderRepository(this.Network, CreateTestDir(this), this.LoggerFactory.Object, dBreezeSerializer); this.provenBlockHeaderStore = new ProvenBlockHeaderStore(DateTimeProvider.Default, this.LoggerFactory.Object, this.provenBlockHeaderRepository, nodeStats, ibdMock.Object); } diff --git a/src/Tests/Blockcore.Features.Consensus.Tests/TestChainFactory.cs b/src/Tests/Blockcore.Features.Consensus.Tests/TestChainFactory.cs index f22e683ab..9d09cead2 100644 --- a/src/Tests/Blockcore.Features.Consensus.Tests/TestChainFactory.cs +++ b/src/Tests/Blockcore.Features.Consensus.Tests/TestChainFactory.cs @@ -16,6 +16,7 @@ using Blockcore.Consensus.TransactionInfo; using Blockcore.Consensus.Validators; using Blockcore.Features.BlockStore; +using Blockcore.Features.BlockStore.Persistence.LevelDb; using Blockcore.Features.BlockStore.Repository; using Blockcore.Features.Consensus.CoinViews; using Blockcore.Features.Consensus.Rules; @@ -156,7 +157,7 @@ public static async Task CreateAsync(Network network, string d var dBreezeSerializer = new DataStoreSerializer(network.Consensus.ConsensusFactory); - var blockRepository = new LeveldbBlockRepository(testChainContext.Network, dataFolder, testChainContext.LoggerFactory, dBreezeSerializer); + var blockRepository = new LevelDbBlockRepository(testChainContext.Network, dataFolder, testChainContext.LoggerFactory, dBreezeSerializer); var blockStoreFlushCondition = new BlockStoreQueueFlushCondition(testChainContext.ChainState, testChainContext.InitialBlockDownloadState); diff --git a/src/Tests/Blockcore.Features.MemoryPool.Tests/FullNodeBuilderTest.cs b/src/Tests/Blockcore.Features.MemoryPool.Tests/FullNodeBuilderTest.cs index 5ff204c3c..05a52f7b7 100644 --- a/src/Tests/Blockcore.Features.MemoryPool.Tests/FullNodeBuilderTest.cs +++ b/src/Tests/Blockcore.Features.MemoryPool.Tests/FullNodeBuilderTest.cs @@ -9,6 +9,7 @@ using Blockcore.Features.Consensus; using Blockcore.Networks; using Blockcore.Tests.Common; +using Blockcore.Utilities.Store; using Microsoft.Extensions.DependencyInjection; using NBitcoin; @@ -27,7 +28,9 @@ public void CanHaveAllFullnodeServicesTest() var nodeSettings = new NodeSettings(KnownNetworks.TestNet, args: new string[] { $"-datadir=Blockcore.Features.MemoryPool.Tests/TestData/FullNodeBuilderTest/CanHaveAllServicesTest" }); - var fullNodeBuilder = new FullNodeBuilder(nodeSettings); + var persistenceManager = new TestPersistenceProviderManager(nodeSettings); + + var fullNodeBuilder = new FullNodeBuilder(nodeSettings, persistenceManager); IFullNode fullNode = fullNodeBuilder .UseBlockStore() .UsePowConsensus() diff --git a/src/Tests/Blockcore.Features.NodeHost.Tests/ApiSettingsTest.cs b/src/Tests/Blockcore.Features.NodeHost.Tests/ApiSettingsTest.cs index f7803546d..46b6a13c1 100644 --- a/src/Tests/Blockcore.Features.NodeHost.Tests/ApiSettingsTest.cs +++ b/src/Tests/Blockcore.Features.NodeHost.Tests/ApiSettingsTest.cs @@ -268,6 +268,7 @@ public void GivenUseHttpsAndNoCertificateFilePath_ThenShouldThrowConfigurationEx private static NodeHostSettings FullNodeSetup(NodeSettings nodeSettings) { return new FullNodeBuilder() + .UsePersistenceProviderMananger(new TestPersistenceProviderManager(nodeSettings)) .UseNodeSettings(nodeSettings) .UseNodeHost() .UsePowConsensus() diff --git a/src/Tests/Blockcore.Features.PoA.Tests/PoATestsBase.cs b/src/Tests/Blockcore.Features.PoA.Tests/PoATestsBase.cs index 20ca92623..54835ca7e 100644 --- a/src/Tests/Blockcore.Features.PoA.Tests/PoATestsBase.cs +++ b/src/Tests/Blockcore.Features.PoA.Tests/PoATestsBase.cs @@ -11,6 +11,7 @@ using Blockcore.Consensus.Chain; using Blockcore.Consensus.Checkpoints; using Blockcore.Consensus.Rules; +using Blockcore.Features.Base.Persistence.LevelDb; using Blockcore.Features.Consensus.CoinViews; using Blockcore.Features.PoA.Voting; using Blockcore.Networks; @@ -68,7 +69,7 @@ public PoATestsBase(TestPoANetwork network = null) this.asyncProvider = new AsyncProvider(this.loggerFactory, this.signals, new Mock().Object); var dataFolder = new DataFolder(TestBase.CreateTestDir(this)); - var finalizedBlockRepo = new FinalizedBlockInfoRepository(new LeveldbKeyValueRepository(dataFolder, this.DataStoreSerializer), this.loggerFactory, this.asyncProvider); + var finalizedBlockRepo = new FinalizedBlockInfoRepository(new LevelDbKeyValueRepository(dataFolder, this.DataStoreSerializer), this.loggerFactory, this.asyncProvider); finalizedBlockRepo.LoadFinalizedBlockInfoAsync(this.network).GetAwaiter().GetResult(); this.resultExecutorMock = new Mock(); @@ -92,7 +93,7 @@ public PoATestsBase(TestPoANetwork network = null) public static IFederationManager CreateFederationManager(object caller, Network network, LoggerFactory loggerFactory, ISignals signals) { string dir = TestBase.CreateTestDir(caller); - var keyValueRepo = new LeveldbKeyValueRepository(dir, new DataStoreSerializer(network.Consensus.ConsensusFactory)); + var keyValueRepo = new LevelDbKeyValueRepository(dir, new DataStoreSerializer(network.Consensus.ConsensusFactory)); var settings = new NodeSettings(network, args: new string[] { $"-datadir={dir}" }); var federationManager = new FederationManager(settings, network, loggerFactory, keyValueRepo, signals); diff --git a/src/Tests/Blockcore.IntegrationTests.Common/Runners/CustomRunner.cs b/src/Tests/Blockcore.IntegrationTests.Common/Runners/CustomRunner.cs index 5a9e98589..485946d39 100644 --- a/src/Tests/Blockcore.IntegrationTests.Common/Runners/CustomRunner.cs +++ b/src/Tests/Blockcore.IntegrationTests.Common/Runners/CustomRunner.cs @@ -6,6 +6,7 @@ using Blockcore.IntegrationTests.Common.Extensions; using Blockcore.Networks; using Blockcore.P2P; +using Blockcore.Tests.Common; using NBitcoin; using NBitcoin.Protocol; @@ -41,7 +42,11 @@ public override void BuildNode() else settings = new NodeSettings(this.Network, agent: this.Agent, args: argsAsStringArray) { MinProtocolVersion = this.minProtocolVersion }; - IFullNodeBuilder builder = new FullNodeBuilder().UseNodeSettings(settings); + var persistenceProviderManager = new TestPersistenceProviderManager(settings); + + IFullNodeBuilder builder = new FullNodeBuilder() + .UsePersistenceProviderMananger(persistenceProviderManager) + .UseNodeSettings(settings); this.callback(builder); diff --git a/src/Tests/Blockcore.IntegrationTests.Common/Runners/StratisBitcoinPosRunner.cs b/src/Tests/Blockcore.IntegrationTests.Common/Runners/StratisBitcoinPosRunner.cs index 66fa5ce4b..65523aee5 100644 --- a/src/Tests/Blockcore.IntegrationTests.Common/Runners/StratisBitcoinPosRunner.cs +++ b/src/Tests/Blockcore.IntegrationTests.Common/Runners/StratisBitcoinPosRunner.cs @@ -14,6 +14,8 @@ using Blockcore.P2P; using NBitcoin; using NBitcoin.Protocol; +using Blockcore.Utilities.Store; +using Blockcore.Tests.Common; namespace Blockcore.IntegrationTests.Common.Runners { @@ -31,11 +33,13 @@ public StratisBitcoinPosRunner(string dataDir, Network network, string agent = " public override void BuildNode() { var settings = new NodeSettings(this.Network, this.Agent, args: new string[] { "-conf=stratis.conf", "-datadir=" + this.DataFolder }); + var persistenceProviderManager = new TestPersistenceProviderManager(settings); // For stratisX tests we need the minimum protocol version to be 70000. settings.MinProtocolVersion = ProtocolVersion.POS_PROTOCOL_VERSION; var builder = new FullNodeBuilder() + .UsePersistenceProviderMananger(persistenceProviderManager) .UseNodeSettings(settings) .UseBlockStore() .UsePosConsensus() @@ -70,7 +74,9 @@ public override void BuildNode() public static IFullNode BuildStakingNode(string dataDir, bool staking = true) { var nodeSettings = new NodeSettings(networksSelector: Networks.Stratis.Networks.Stratis, args: new string[] { $"-datadir={dataDir}", $"-stake={(staking ? 1 : 0)}", "-walletname=dummy", "-walletpassword=dummy" }); - var fullNodeBuilder = new FullNodeBuilder(nodeSettings); + var persistenceProviderManager = new TestPersistenceProviderManager(nodeSettings); + + var fullNodeBuilder = new FullNodeBuilder(nodeSettings, persistenceProviderManager); IFullNode fullNode = fullNodeBuilder .UseBlockStore() .UsePosConsensus() diff --git a/src/Tests/Blockcore.IntegrationTests.Common/Runners/StratisBitcoinPowRunner.cs b/src/Tests/Blockcore.IntegrationTests.Common/Runners/StratisBitcoinPowRunner.cs index 4663b81a3..77b975946 100644 --- a/src/Tests/Blockcore.IntegrationTests.Common/Runners/StratisBitcoinPowRunner.cs +++ b/src/Tests/Blockcore.IntegrationTests.Common/Runners/StratisBitcoinPowRunner.cs @@ -14,6 +14,7 @@ using Blockcore.Networks; using Blockcore.P2P; using NBitcoin; +using Blockcore.Tests.Common; namespace Blockcore.IntegrationTests.Common.Runners { @@ -34,7 +35,11 @@ public override void BuildNode() else settings = new NodeSettings(this.Network, agent: this.Agent, args: new string[] { "-conf=bitcoin.conf", "-datadir=" + this.DataFolder }); + var persistenceProviderManager = new TestPersistenceProviderManager(settings); + + var builder = new FullNodeBuilder() + .UsePersistenceProviderMananger(persistenceProviderManager) .UseNodeSettings(settings) .UseBlockStore() .UsePowConsensus() diff --git a/src/Tests/Blockcore.IntegrationTests/BlockStore/BlockStoreTests.cs b/src/Tests/Blockcore.IntegrationTests/BlockStore/BlockStoreTests.cs index d99a526d5..4e1139f72 100644 --- a/src/Tests/Blockcore.IntegrationTests/BlockStore/BlockStoreTests.cs +++ b/src/Tests/Blockcore.IntegrationTests/BlockStore/BlockStoreTests.cs @@ -4,6 +4,7 @@ using Blockcore.Consensus.ScriptInfo; using Blockcore.Consensus.TransactionInfo; using Blockcore.Features.BlockStore; +using Blockcore.Features.BlockStore.Persistence.LevelDb; using Blockcore.Features.BlockStore.Repository; using Blockcore.IntegrationTests.Common; using Blockcore.IntegrationTests.Common.EnvironmentMockUpHelpers; @@ -36,7 +37,7 @@ public BlockStoreTests() [Fact] public void BlockRepositoryPutBatch() { - using (var blockRepository = new LeveldbBlockRepository(this.network, TestBase.CreateDataFolder(this), this.loggerFactory, this.dataStoreSerializer)) + using (var blockRepository = new LevelDbBlockRepository(this.network, TestBase.CreateDataFolder(this), this.loggerFactory, this.dataStoreSerializer)) { blockRepository.SetTxIndex(true); diff --git a/src/Tests/Blockcore.IntegrationTests/Blockcore.IntegrationTests.csproj b/src/Tests/Blockcore.IntegrationTests/Blockcore.IntegrationTests.csproj index 45a4e752d..1284f7105 100644 --- a/src/Tests/Blockcore.IntegrationTests/Blockcore.IntegrationTests.csproj +++ b/src/Tests/Blockcore.IntegrationTests/Blockcore.IntegrationTests.csproj @@ -32,6 +32,9 @@ + + + diff --git a/src/Tests/Blockcore.IntegrationTests/CoinViewTests.cs b/src/Tests/Blockcore.IntegrationTests/CoinViewTests.cs index 0e5fe5c75..40388fe8f 100644 --- a/src/Tests/Blockcore.IntegrationTests/CoinViewTests.cs +++ b/src/Tests/Blockcore.IntegrationTests/CoinViewTests.cs @@ -9,6 +9,7 @@ using Blockcore.Consensus.Chain; using Blockcore.Consensus.Checkpoints; using Blockcore.Consensus.TransactionInfo; +using Blockcore.Features.Base.Persistence.LevelDb; using Blockcore.Features.Consensus; using Blockcore.Features.Consensus.CoinViews; using Blockcore.IntegrationTests.Common; @@ -287,7 +288,7 @@ public void CanSaveChainIncrementally() var chain = new ChainIndexer(this.regTest); var data = new DataFolder(TestBase.CreateTestDir(this)); - using (var repo = new ChainRepository(this.loggerFactory, new LeveldbChainStore(this.network, data, chain), this.network)) + using (var repo = new ChainRepository(this.loggerFactory, new LevelDbChainStore(this.network, data, chain), this.network)) { chain.SetTip(repo.LoadAsync(chain.Genesis).GetAwaiter().GetResult()); Assert.True(chain.Tip == chain.Genesis); diff --git a/src/Tests/Blockcore.IntegrationTests/NodeContext.cs b/src/Tests/Blockcore.IntegrationTests/NodeContext.cs index efbe0ace3..ea4328e10 100644 --- a/src/Tests/Blockcore.IntegrationTests/NodeContext.cs +++ b/src/Tests/Blockcore.IntegrationTests/NodeContext.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Runtime.CompilerServices; using Blockcore.Features.Consensus.CoinViews.Coindb; +using Blockcore.Features.Consensus.Persistence.LevelDb; using Blockcore.Networks; using Blockcore.Tests.Common; using Blockcore.Utilities; @@ -27,7 +28,7 @@ public NodeContext(object caller, string name, Network network, bool clean) var serializer = new DataStoreSerializer(this.Network.Consensus.ConsensusFactory); //this.Coindb = new DBreezeCoindb(network, this.FolderName, dateTimeProvider, this.loggerFactory, new NodeStats(dateTimeProvider, this.loggerFactory), serializer); //this.Coindb = new FasterCoindb(network, this.FolderName, dateTimeProvider, this.loggerFactory, new NodeStats(dateTimeProvider, this.loggerFactory), serializer); - this.Coindb = new LeveldbCoindb(network, this.FolderName, dateTimeProvider, this.loggerFactory, new NodeStats(dateTimeProvider, this.loggerFactory), serializer); + this.Coindb = new LevelDbCoindb(network, this.FolderName, dateTimeProvider, this.loggerFactory, new NodeStats(dateTimeProvider, this.loggerFactory), serializer); this.Coindb.Initialize(); this.cleanList = new List { (IDisposable)this.Coindb }; } @@ -67,7 +68,7 @@ public void ReloadPersistentCoinView() var serializer = new DataStoreSerializer(this.Network.Consensus.ConsensusFactory); //this.Coindb = new DBreezeCoindb(this.Network, this.FolderName, dateTimeProvider, this.loggerFactory, new NodeStats(dateTimeProvider, this.loggerFactory), serializer); //this.Coindb = new FasterCoindb(this.Network, this.FolderName, dateTimeProvider, this.loggerFactory, new NodeStats(dateTimeProvider, this.loggerFactory), serializer); - this.Coindb = new LeveldbCoindb(this.Network, this.FolderName, dateTimeProvider, this.loggerFactory, new NodeStats(dateTimeProvider, this.loggerFactory), serializer); + this.Coindb = new LevelDbCoindb(this.Network, this.FolderName, dateTimeProvider, this.loggerFactory, new NodeStats(dateTimeProvider, this.loggerFactory), serializer); this.Coindb.Initialize(); this.cleanList.Add((IDisposable)this.Coindb); diff --git a/src/Tests/Blockcore.IntegrationTests/RPC/BaseRPCControllerTest.cs b/src/Tests/Blockcore.IntegrationTests/RPC/BaseRPCControllerTest.cs index ed6ed85d6..1d20c9b0c 100644 --- a/src/Tests/Blockcore.IntegrationTests/RPC/BaseRPCControllerTest.cs +++ b/src/Tests/Blockcore.IntegrationTests/RPC/BaseRPCControllerTest.cs @@ -27,7 +27,9 @@ protected BaseRPCControllerTest() : base(new BitcoinRegTest()) public IFullNode BuildServicedNode(string dir) { var nodeSettings = new NodeSettings(this.Network, args: new string[] { $"-datadir={dir}" }); - var fullNodeBuilder = new FullNodeBuilder(nodeSettings); + var persistenceProviderManager = new TestPersistenceProviderManager(nodeSettings); + + var fullNodeBuilder = new FullNodeBuilder(nodeSettings, persistenceProviderManager); IFullNode fullNode = fullNodeBuilder .UseBlockStore() .UsePowConsensus() diff --git a/src/Tests/Blockcore.IntegrationTests/RPC/RPCSettingsTest.cs b/src/Tests/Blockcore.IntegrationTests/RPC/RPCSettingsTest.cs index f2d3f242d..f638abd24 100644 --- a/src/Tests/Blockcore.IntegrationTests/RPC/RPCSettingsTest.cs +++ b/src/Tests/Blockcore.IntegrationTests/RPC/RPCSettingsTest.cs @@ -22,6 +22,7 @@ public void CanSpecifyRPCSettings() var nodeSettings = new NodeSettings(this.Network, args: new string[] { $"-datadir={dir}", "-rpcuser=abc", "-rpcpassword=def", "-rpcport=91", "-server=1" }); IFullNode node = new FullNodeBuilder() + .UsePersistenceProviderMananger(new TestPersistenceProviderManager(nodeSettings)) .UseNodeSettings(nodeSettings) .UsePowConsensus() .AddRPC() diff --git a/src/Tests/Blockcore.Tests.Common/Blockcore.Tests.Common.csproj b/src/Tests/Blockcore.Tests.Common/Blockcore.Tests.Common.csproj index f88e34ad8..b73697536 100644 --- a/src/Tests/Blockcore.Tests.Common/Blockcore.Tests.Common.csproj +++ b/src/Tests/Blockcore.Tests.Common/Blockcore.Tests.Common.csproj @@ -20,6 +20,9 @@ + + + diff --git a/src/Tests/Blockcore.Tests.Common/TestPersistenceProviderManager.cs b/src/Tests/Blockcore.Tests.Common/TestPersistenceProviderManager.cs new file mode 100644 index 000000000..83531cded --- /dev/null +++ b/src/Tests/Blockcore.Tests.Common/TestPersistenceProviderManager.cs @@ -0,0 +1,28 @@ +using Blockcore.Configuration; +using Blockcore.Persistence; + +namespace Blockcore.Tests.Common +{ + /// + /// To be used when no test has to use persistence. + /// Doesn't register anything. + /// + /// + public class TestPersistenceProviderManager : PersistenceProviderManager + { + public TestPersistenceProviderManager(NodeSettings nodeSettings) : base(nodeSettings) + { + } + + public override void Initialize() + { + // manually register LevelDb implementation + this.persistenceProviders["LevelDb".ToLowerInvariant()] = new System.Collections.Generic.List + { + new Features.Base.Persistence.LevelDb.PersistenceProvider(), + new Features.Consensus.Persistence.LevelDb.PersistenceProvider(), + new Features.BlockStore.Persistence.LevelDb.PersistenceProvider(), + }; + } + } +} diff --git a/src/Tests/Blockcore.Tests/Base/ChainRepositoryTest.cs b/src/Tests/Blockcore.Tests/Base/ChainRepositoryTest.cs index bc6ba5029..683ad15cc 100644 --- a/src/Tests/Blockcore.Tests/Base/ChainRepositoryTest.cs +++ b/src/Tests/Blockcore.Tests/Base/ChainRepositoryTest.cs @@ -1,17 +1,14 @@ using System; using System.Collections.Generic; using System.Linq; -using Blockcore.Base; using Blockcore.Configuration; using Blockcore.Consensus.BlockInfo; using Blockcore.Consensus.Chain; +using Blockcore.Features.Base.Persistence.LevelDb; using Blockcore.Tests.Common; using Blockcore.Utilities; -using DBreeze; -using DBreeze.DataTypes; using LevelDB; using Microsoft.Extensions.Logging; -using Moq; using NBitcoin; using Xunit; @@ -33,7 +30,7 @@ public void SaveChainToDisk() var chain = new ChainIndexer(KnownNetworks.StratisRegTest); this.AppendBlock(chain); - using (var repo = new ChainRepository(new LoggerFactory(), new LeveldbChainStore(chain.Network, new DataFolder(dir), chain), chain.Network)) + using (var repo = new ChainRepository(new LoggerFactory(), new LevelDbChainStore(chain.Network, new DataFolder(dir), chain), chain.Network)) { repo.SaveAsync(chain).GetAwaiter().GetResult(); } @@ -88,7 +85,7 @@ public void LoadChainFromDisk() engine.Write(batch); } } - using (var repo = new ChainRepository(new LoggerFactory(), new LeveldbChainStore(chain.Network, new DataFolder(dir), chain), chain.Network)) + using (var repo = new ChainRepository(new LoggerFactory(), new LevelDbChainStore(chain.Network, new DataFolder(dir), chain), chain.Network)) { var testChain = new ChainIndexer(KnownNetworks.StratisRegTest); testChain.SetTip(repo.LoadAsync(testChain.Genesis).GetAwaiter().GetResult()); diff --git a/src/Tests/Blockcore.Tests/Base/TipsManagerTests.cs b/src/Tests/Blockcore.Tests/Base/TipsManagerTests.cs index 1b5c1976d..27d2fd1bf 100644 --- a/src/Tests/Blockcore.Tests/Base/TipsManagerTests.cs +++ b/src/Tests/Blockcore.Tests/Base/TipsManagerTests.cs @@ -3,6 +3,7 @@ using System.Threading.Tasks; using Blockcore.Base; using Blockcore.Consensus.Chain; +using Blockcore.Features.Base.Persistence.LevelDb; using Blockcore.Tests.Common; using Blockcore.Utilities; using Blockcore.Utilities.Store; @@ -15,7 +16,7 @@ namespace Blockcore.Tests.Base public class TipsManagerTests : TestBase { private readonly LoggerFactory loggerFactory; - private readonly LeveldbKeyValueRepository keyValueRepo; + private readonly LevelDbKeyValueRepository keyValueRepo; private readonly ITipsManager tipsManager; private readonly List mainChainHeaders; @@ -24,7 +25,7 @@ public TipsManagerTests() : base(KnownNetworks.StratisMain) { this.loggerFactory = new LoggerFactory(); string dir = CreateTestDir(this); - this.keyValueRepo = new LeveldbKeyValueRepository(dir, new DataStoreSerializer(this.Network.Consensus.ConsensusFactory)); + this.keyValueRepo = new LevelDbKeyValueRepository(dir, new DataStoreSerializer(this.Network.Consensus.ConsensusFactory)); this.tipsManager = new TipsManager(this.keyValueRepo, this.loggerFactory); diff --git a/src/Tests/Blockcore.Tests/Builder/Feature/FeaturesDependencyCheckingTest.cs b/src/Tests/Blockcore.Tests/Builder/Feature/FeaturesDependencyCheckingTest.cs index 7a454d47f..2b7c8bb08 100644 --- a/src/Tests/Blockcore.Tests/Builder/Feature/FeaturesDependencyCheckingTest.cs +++ b/src/Tests/Blockcore.Tests/Builder/Feature/FeaturesDependencyCheckingTest.cs @@ -5,6 +5,7 @@ using Blockcore.Configuration; using Blockcore.Features.Consensus; using Blockcore.Tests.Common; +using Blockcore.Utilities.Store; using Xunit; namespace Blockcore.Tests.Builder.Feature @@ -74,7 +75,11 @@ private class FeatureA : FeatureBase [Fact] public void DependencyCheckWithValidDependencies() { - IFullNodeBuilder builder = new FullNodeBuilder().UseNodeSettings(NodeSettings.Default(KnownNetworks.StratisRegTest)); + var settings = NodeSettings.Default(KnownNetworks.StratisRegTest); + + IFullNodeBuilder builder = new FullNodeBuilder() + .UsePersistenceProviderMananger(new TestPersistenceProviderManager(settings)) + .UseNodeSettings(settings); builder.ConfigureFeature(features => { @@ -98,7 +103,12 @@ public void DependencyCheckWithValidDependencies() [Fact] public void DependencyCheckWithInvalidDependenciesThrowsException() { - IFullNodeBuilder builder = new FullNodeBuilder().UseNodeSettings(NodeSettings.Default(KnownNetworks.StratisRegTest)); + var nodeSettings = NodeSettings.Default(KnownNetworks.StratisRegTest); + + IFullNodeBuilder builder = new FullNodeBuilder() + .UsePersistenceProviderMananger(new TestPersistenceProviderManager(nodeSettings)) + .UseNodeSettings(nodeSettings); + builder.ConfigureFeature(features => { features diff --git a/src/Tests/Blockcore.Tests/Builder/FullNodeBuilderExtensionsTest.cs b/src/Tests/Blockcore.Tests/Builder/FullNodeBuilderExtensionsTest.cs index 9ca638ed0..37dcd46ac 100644 --- a/src/Tests/Blockcore.Tests/Builder/FullNodeBuilderExtensionsTest.cs +++ b/src/Tests/Blockcore.Tests/Builder/FullNodeBuilderExtensionsTest.cs @@ -24,7 +24,7 @@ public FullNodeBuilderExtensionsTest() this.featureCollectionDelegates = new List>(); this.featureCollection = new FeatureCollection(); - this.fullNodeBuilder = new FullNodeBuilder(this.serviceCollectionDelegates, this.serviceProviderDelegates, this.featureCollectionDelegates, this.featureCollection); + this.fullNodeBuilder = new FullNodeBuilder(this.serviceCollectionDelegates, this.serviceProviderDelegates, this.featureCollectionDelegates, this.featureCollection, new TestPersistenceProviderManager(null)); this.fullNodeBuilder.Network = KnownNetworks.TestNet; } @@ -60,7 +60,7 @@ public void UseDefaultNodeSettingsConfiguresNodeBuilderWithDefaultSettings() [Fact] public void UseNodeSettingsUsingTestNetConfiguresNodeBuilderWithTestnetSettings() { - var nodeSettings = new NodeSettings(KnownNetworks.TestNet, args:new string[] { + var nodeSettings = new NodeSettings(KnownNetworks.TestNet, args: new string[] { "-datadir=TestData/FullNodeBuilder/UseNodeSettings" }); FullNodeBuilderNodeSettingsExtension.UseNodeSettings(this.fullNodeBuilder, nodeSettings); @@ -76,7 +76,7 @@ public void UseNodeSettingsUsingTestNetConfiguresNodeBuilderWithTestnetSettings( [Fact] public void UseNodeSettingsUsingRegTestNetConfiguresNodeBuilderWithRegTestNet() { - var nodeSettings = new NodeSettings(KnownNetworks.RegTest, args:new string[] { + var nodeSettings = new NodeSettings(KnownNetworks.RegTest, args: new string[] { "-datadir=TestData/FullNodeBuilder/UseNodeSettings" }); FullNodeBuilderNodeSettingsExtension.UseNodeSettings(this.fullNodeBuilder, nodeSettings); diff --git a/src/Tests/Blockcore.Tests/Builder/FullNodeBuilderTest.cs b/src/Tests/Blockcore.Tests/Builder/FullNodeBuilderTest.cs index b3d08f0eb..fe17212b8 100644 --- a/src/Tests/Blockcore.Tests/Builder/FullNodeBuilderTest.cs +++ b/src/Tests/Blockcore.Tests/Builder/FullNodeBuilderTest.cs @@ -8,6 +8,7 @@ using Blockcore.Networks; using Blockcore.Tests.Common; using Blockcore.Utilities; +using Blockcore.Utilities.Store; using Microsoft.Extensions.DependencyInjection; using NBitcoin; @@ -39,7 +40,7 @@ public FullNodeBuilderTest() this.featureCollectionDelegates = new List>(); this.featureCollection = new FeatureCollection(); - this.fullNodeBuilder = new FullNodeBuilder(this.serviceCollectionDelegates, this.serviceProviderDelegates, this.featureCollectionDelegates, this.featureCollection); + this.fullNodeBuilder = new FullNodeBuilder(this.serviceCollectionDelegates, this.serviceProviderDelegates, this.featureCollectionDelegates, this.featureCollection, new TestPersistenceProviderManager(null)); this.fullNodeBuilder.Network = KnownNetworks.RegTest; } @@ -47,7 +48,7 @@ public FullNodeBuilderTest() [Fact] public void ConstructorWithoutNodeSettingsDoesNotSetupBaseServices() { - this.fullNodeBuilder = new FullNodeBuilder(this.serviceCollectionDelegates, this.serviceProviderDelegates, this.featureCollectionDelegates, this.featureCollection); + this.fullNodeBuilder = new FullNodeBuilder(this.serviceCollectionDelegates, this.serviceProviderDelegates, this.featureCollectionDelegates, this.featureCollection, new TestPersistenceProviderManager(null)); Assert.Empty(this.featureCollection.FeatureRegistrations); Assert.Empty(this.featureCollectionDelegates); @@ -62,7 +63,7 @@ public void ConstructorWithNodeSettingsSetupBaseServices() { var settings = new NodeSettings(KnownNetworks.RegTest); - this.fullNodeBuilder = new FullNodeBuilder(settings, this.serviceCollectionDelegates, this.serviceProviderDelegates, this.featureCollectionDelegates, this.featureCollection); + this.fullNodeBuilder = new FullNodeBuilder(settings, this.serviceCollectionDelegates, this.serviceProviderDelegates, this.featureCollectionDelegates, this.featureCollection, new TestPersistenceProviderManager(settings)); Assert.Empty(this.featureCollection.FeatureRegistrations); Assert.Single(this.featureCollectionDelegates); @@ -114,7 +115,7 @@ public void BuildWithInitialServicesSetupConfiguresFullNodeUsingConfiguration() string dataDir = "TestData/FullNodeBuilder/BuildWithInitialServicesSetup"; var nodeSettings = new NodeSettings(KnownNetworks.StratisRegTest, args: new string[] { $"-datadir={dataDir}" }); - this.fullNodeBuilder = new FullNodeBuilder(nodeSettings, this.serviceCollectionDelegates, this.serviceProviderDelegates, this.featureCollectionDelegates, this.featureCollection); + this.fullNodeBuilder = new FullNodeBuilder(nodeSettings, this.serviceCollectionDelegates, this.serviceProviderDelegates, this.featureCollectionDelegates, this.featureCollection, new TestPersistenceProviderManager(nodeSettings)); this.fullNodeBuilder.ConfigureServices(e => { diff --git a/src/Tests/Blockcore.Tests/Consensus/FinalizedBlockInfoRepositoryTest.cs b/src/Tests/Blockcore.Tests/Consensus/FinalizedBlockInfoRepositoryTest.cs index 615ce5ecd..5973270cd 100644 --- a/src/Tests/Blockcore.Tests/Consensus/FinalizedBlockInfoRepositoryTest.cs +++ b/src/Tests/Blockcore.Tests/Consensus/FinalizedBlockInfoRepositoryTest.cs @@ -1,6 +1,7 @@ using System.Threading.Tasks; using Blockcore.AsyncWork; using Blockcore.Consensus; +using Blockcore.Features.Base.Persistence.LevelDb; using Blockcore.Tests.Common; using Blockcore.Utilities; using Blockcore.Utilities.Store; @@ -24,7 +25,7 @@ public FinalizedBlockInfoRepositoryTest() : base(KnownNetworks.StratisRegTest) public async Task FinalizedHeightSavedOnDiskAsync() { string dir = CreateTestDir(this); - var kvRepo = new LeveldbKeyValueRepository(dir, new DataStoreSerializer(this.Network.Consensus.ConsensusFactory)); + var kvRepo = new LevelDbKeyValueRepository(dir, new DataStoreSerializer(this.Network.Consensus.ConsensusFactory)); var asyncMock = new Mock(); asyncMock.Setup(a => a.RegisterTask(It.IsAny(), It.IsAny())); @@ -44,7 +45,7 @@ public async Task FinalizedHeightSavedOnDiskAsync() public async Task FinalizedHeightCantBeDecreasedAsync() { string dir = CreateTestDir(this); - var kvRepo = new LeveldbKeyValueRepository(dir, new DataStoreSerializer(this.Network.Consensus.ConsensusFactory)); + var kvRepo = new LevelDbKeyValueRepository(dir, new DataStoreSerializer(this.Network.Consensus.ConsensusFactory)); var asyncMock = new Mock(); asyncMock.Setup(a => a.RegisterTask(It.IsAny(), It.IsAny()));