diff --git a/neo.sln b/neo.sln index b0de1c27b1..92ba03c635 100644 --- a/neo.sln +++ b/neo.sln @@ -78,6 +78,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TokensTracker", "src\Plugin EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RpcClient", "src\Plugins\RpcClient\RpcClient.csproj", "{185ADAFC-BFC6-413D-BC2E-97F9FB0A8AF0}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.Hosting.App", "src\Neo.Hosting.App\Neo.Hosting.App.csproj", "{C2095AD3-2ACA-46F3-89EC-BE52F98DA59B}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -216,6 +218,10 @@ Global {185ADAFC-BFC6-413D-BC2E-97F9FB0A8AF0}.Debug|Any CPU.Build.0 = Debug|Any CPU {185ADAFC-BFC6-413D-BC2E-97F9FB0A8AF0}.Release|Any CPU.ActiveCfg = Release|Any CPU {185ADAFC-BFC6-413D-BC2E-97F9FB0A8AF0}.Release|Any CPU.Build.0 = Release|Any CPU + {C2095AD3-2ACA-46F3-89EC-BE52F98DA59B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C2095AD3-2ACA-46F3-89EC-BE52F98DA59B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C2095AD3-2ACA-46F3-89EC-BE52F98DA59B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C2095AD3-2ACA-46F3-89EC-BE52F98DA59B}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -255,6 +261,7 @@ Global {FF76D8A4-356B-461A-8471-BC1B83E57BBC} = {C2DC830A-327A-42A7-807D-295216D30DBB} {5E4947F3-05D3-4806-B0F3-30DAC71B5986} = {C2DC830A-327A-42A7-807D-295216D30DBB} {185ADAFC-BFC6-413D-BC2E-97F9FB0A8AF0} = {C2DC830A-327A-42A7-807D-295216D30DBB} + {C2095AD3-2ACA-46F3-89EC-BE52F98DA59B} = {B5339DF7-5D1D-43BA-B332-74B825E1770E} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {BCBA19D9-F868-4C6D-8061-A2B91E06E3EC} diff --git a/src/Neo.Extensions/AssemblyUtility.cs b/src/Neo.Extensions/AssemblyUtility.cs new file mode 100644 index 0000000000..f7cc10678b --- /dev/null +++ b/src/Neo.Extensions/AssemblyUtility.cs @@ -0,0 +1,25 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// AssemblyUtility.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using System.Reflection; + +namespace Neo.Extensions +{ + public static class AssemblyUtility + { + public static int GetVersionNumber() + { + var version = Assembly.GetCallingAssembly().GetName().Version; + if (version is null) return 0; + return version.Major * 1000 + version.Minor * 100 + version.Build * 10 + version.Revision; + } + } +} diff --git a/src/Neo.Hosting.App/CommandLine/DefaultRootCommand.cs b/src/Neo.Hosting.App/CommandLine/DefaultRootCommand.cs new file mode 100644 index 0000000000..825e73ae0a --- /dev/null +++ b/src/Neo.Hosting.App/CommandLine/DefaultRootCommand.cs @@ -0,0 +1,40 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// DefaultRootCommand.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using System; +using System.CommandLine; +using System.IO; + +namespace Neo.Hosting.App.CommandLine +{ + internal sealed class DefaultRootCommand : Command + { + private static string? s_executablePath; + private static string? s_executableName; + + public DefaultRootCommand() : base(ExecutableName, "NEO Blockchain CommandLine Tool") + { + //var exportCommand = new ExportCommand(); + //var runCommand = new RunCommand(); + //var connectCommand = new ConnectCommand(); + + //AddCommand(exportCommand); + //AddCommand(runCommand); + //AddCommand(connectCommand); + } + + public static string ExecutableName => + s_executableName ??= Path.GetFileNameWithoutExtension(ExecutablePath).Replace(" ", ""); + + public static string ExecutablePath => + s_executablePath ??= Environment.GetCommandLineArgs()[0]; + } +} diff --git a/src/Neo.Hosting.App/Configuration/NeoConfigurationSource.cs b/src/Neo.Hosting.App/Configuration/NeoConfigurationSource.cs new file mode 100644 index 0000000000..d80f17174e --- /dev/null +++ b/src/Neo.Hosting.App/Configuration/NeoConfigurationSource.cs @@ -0,0 +1,23 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// NeoConfigurationSource.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using Microsoft.Extensions.Configuration; +using Neo.Hosting.App.Providers; + +namespace Neo.Hosting.App.Configuration +{ + internal class NeoConfigurationSource + (IConfigurationSection? configurationSection = null) : IConfigurationSource + { + public IConfigurationProvider Build(IConfigurationBuilder builder) => + new NeoConfigurationProvider(configurationSection); + } +} diff --git a/src/Neo.Hosting.App/Configuration/NeoOptions.cs b/src/Neo.Hosting.App/Configuration/NeoOptions.cs new file mode 100644 index 0000000000..0cda4dc1bb --- /dev/null +++ b/src/Neo.Hosting.App/Configuration/NeoOptions.cs @@ -0,0 +1,110 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// NeoOptions.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using Neo.Hosting.App.Helpers; +using Neo.Hosting.App.Host; +using Neo.Network.P2P; +using System; +using System.Collections.Generic; +using System.IO; +using System.Security; + +namespace Neo.Hosting.App.Configuration +{ + internal sealed class NeoOptions + { + public StorageOptions Storage { get; set; } = new(); + public P2POptions P2P { get; set; } = new(); + public ContractOptions Contract { get; set; } = new("0x50ac1c37690cc2cfc594472833cf57505d5f46de"); + public PluginOptions Plugin { get; set; } = new(); + public NamedPipeOptions NamedPipe { get; set; } = new(); + public List Wallets { get; set; } = []; + } + + internal sealed class StorageOptions + { + public class ArchiveSettings + { + public string Path { get; set; } = AppContext.BaseDirectory; + public string FileName { get; set; } = "chain.0.acc"; + } + + public string Engine { get; set; } = NeoDefaults.StoreProviderName; + public string Path { get; set; } = "Data_LevelDB_{0:X2}"; + public bool Verify { get; set; } = true; + public ArchiveSettings Archive { get; set; } = new(); + } + + internal sealed class P2POptions + { + public string Listen { get; set; } = "0.0.0.0"; + public ushort Port { get; set; } = 10333; + public int MinDesiredConnections { get; set; } = Peer.DefaultMinDesiredConnections; + public int MaxConnections { get; set; } = Peer.DefaultMaxConnections; + public int MaxConnectionsPerAddress { get; set; } = 3; + } + + internal sealed class ContractOptions + (string neoNameService) + { + private static readonly string s_defualtNameServiceString = "0x50ac1c37690cc2cfc594472833cf57505d5f46de"; + private static readonly UInt160 s_defaultNameServiceScriptHash = UInt160.Parse(s_defualtNameServiceString); + + private UInt160 _neoNameService = s_defaultNameServiceScriptHash; + + public UInt160 NeoNameService + { + get => _neoNameService; + set => _neoNameService = ParseUtility.TryParseUInt160(neoNameService) ?? s_defaultNameServiceScriptHash; + } + } + + internal sealed class PluginOptions + { + public string DownloadUrl { get; set; } = "https://api.github.com/repos/neo-project/neo/releases"; + public bool Prerelease { get; set; } = false; + public Version Version { get; set; } = new(0, 0); + } + + internal sealed class NamedPipeOptions + { + public string Name { get; set; } = default!; + } + + internal sealed class WalletOptions + (string name, string path, string password, bool isActive) + { + public string Name { get; set; } = name; + public FileInfo Path { get; set; } = new(path); + public bool IsActive { get; set; } = isActive; + + public required SecureString Password + { + get => _encryptedPassword; + set + { + var passwordOptionValue = password; + + unsafe + { + fixed (char* passwordChars = passwordOptionValue) + { + var securePasswordString = new SecureString(passwordChars, passwordOptionValue.Length); + securePasswordString.MakeReadOnly(); + _encryptedPassword = value = securePasswordString; + } + } + } + } + + private SecureString _encryptedPassword = new(); + } +} diff --git a/src/Neo.Hosting.App/Extensions/CommandLineBuilderExtensions.cs b/src/Neo.Hosting.App/Extensions/CommandLineBuilderExtensions.cs new file mode 100644 index 0000000000..ad247e00d2 --- /dev/null +++ b/src/Neo.Hosting.App/Extensions/CommandLineBuilderExtensions.cs @@ -0,0 +1,61 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// CommandLineBuilderExtensions.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using System; +using System.CommandLine.Builder; +using System.CommandLine.Hosting; +using System.CommandLine.Invocation; +using System.Linq; + +namespace Neo.Hosting.App.Extensions +{ + internal static class CommandLineBuilderExtensions + { + private const string ConfigurationDirectiveName = "config"; + + internal static CommandLineBuilder UseInternalHost(this CommandLineBuilder builder, + Func hostBuilderFactory, + Action? configureHost = null) => + builder.AddMiddleware(async (invocation, next) => + { + var argsRemaining = invocation.ParseResult.UnparsedTokens.ToArray(); + var hostBuilder = hostBuilderFactory?.Invoke(argsRemaining) + ?? new HostBuilder(); + + hostBuilder.Properties[typeof(InvocationContext)] = invocation; + + hostBuilder.ConfigureHostConfiguration(config => + { + config.AddCommandLineDirectives(invocation.ParseResult, ConfigurationDirectiveName); + }); + + hostBuilder.ConfigureServices(services => + { + services.AddSingleton(invocation); + services.AddSingleton(invocation.BindingContext); + services.AddSingleton(invocation.Console); + services.AddTransient(_ => invocation.InvocationResult!); + services.AddTransient(_ => invocation.ParseResult); + }); + + hostBuilder.UseInvocationLifetime(invocation); + configureHost?.Invoke(hostBuilder); + + using var host = hostBuilder.Build(); + + invocation.BindingContext.AddService(typeof(IHost), _ => host); + + await next(invocation); + }); + } +} diff --git a/src/Neo.Hosting.App/Extensions/HostBuilderExtensions.cs b/src/Neo.Hosting.App/Extensions/HostBuilderExtensions.cs new file mode 100644 index 0000000000..d58d2bae07 --- /dev/null +++ b/src/Neo.Hosting.App/Extensions/HostBuilderExtensions.cs @@ -0,0 +1,129 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// HostBuilderExtensions.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using Neo.Hosting.App.Configuration; +using Neo.Hosting.App.Host; +using Neo.Plugins; +using System; +using System.CommandLine.Hosting; +using System.IO; + +namespace Neo.Hosting.App.Extensions +{ + internal static class HostBuilderExtensions + { + public static IHostBuilder UseNeoSystem(this IHostBuilder hostBuilder) + { + hostBuilder.ConfigureServices((context, services) => + { + var protocolSettingsSection = context.Configuration.GetSection("ProtocolConfiguration"); + var protocolSettings = NeoProtocolSettingsDefaults.MainNet; + + if (protocolSettingsSection.Exists() == false) + services.AddSingleton(protocolSettings); + else + { + protocolSettings = ProtocolSettings.Load(protocolSettingsSection); + services.AddSingleton(protocolSettings); + + } + + Plugin.LoadPlugins(); + + var storageOptions = context.Configuration.Get(); + + string? storagePath = null; + if (string.IsNullOrEmpty(storageOptions?.Path) == false) + { + storagePath = string.Format(storageOptions.Path, protocolSettings.Network); + if (Directory.Exists(storagePath) == false) + { + if (Path.IsPathFullyQualified(storagePath) == false) + storagePath = Path.Combine(AppContext.BaseDirectory, storagePath); + } + } + + services.AddSingleton(new NeoSystem(protocolSettings, storageOptions?.Engine ?? NeoDefaults.StoreProviderName, storagePath)); + }); + + return hostBuilder; + } + + public static IHostBuilder UseNeoServices(this IHostBuilder hostBuilder, Action? configure = null) + { + hostBuilder.ConfigureServices((context, services) => + { + services.Configure(config => config.SuppressStatusMessages = true); + services.Configure(context.Configuration); + + //services.AddSingleton(); + //services.AddSingleton(); + //services.AddSingleton(); + //services.AddSingleton(); + //services.AddSingleton(); + + configure?.Invoke(context, services); + }); + + return hostBuilder; + } + + public static IHostBuilder UseNeoHostConfiguration(this IHostBuilder hostBuilder, Action? configure = null) + { + hostBuilder.ConfigureHostConfiguration(config => + { + config.AddNeoHostConfiguration(); + + configure?.Invoke(config); + }); + + return hostBuilder; + } + + public static IHostBuilder UseNeoAppConfiguration(this IHostBuilder hostBuilder, Action? configure = null) + { + hostBuilder.ConfigureAppConfiguration((context, config) => + { + config.AddNeoAppConfiguration(); + + var environmentName = context.HostingEnvironment.EnvironmentName; + var jsonConfigFileName = $"config.{environmentName}.json"; + + try + { + var manager = new ConfigurationManager(); + manager.AddJsonFile(jsonConfigFileName, optional: false); + + IConfigurationBuilder builder = manager; + var appConfigSection = manager.GetSection(NeoJsonSectionNameDefaults.Application); + + builder.Add(new NeoConfigurationSource(appConfigSection.Exists() ? appConfigSection : null)); + + config.AddConfiguration(manager); + } + catch (FileNotFoundException) + { + throw; + } + + + + configure?.Invoke(context, config); + }); + + return hostBuilder; + } + } +} diff --git a/src/Neo.Hosting.App/Extensions/IConfigurationBuilderExtensions.cs b/src/Neo.Hosting.App/Extensions/IConfigurationBuilderExtensions.cs new file mode 100644 index 0000000000..7067401063 --- /dev/null +++ b/src/Neo.Hosting.App/Extensions/IConfigurationBuilderExtensions.cs @@ -0,0 +1,52 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// IConfigurationBuilderExtensions.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Hosting; +using Neo.Hosting.App.Helpers; +using Neo.Hosting.App.Host; +using System; + +namespace Neo.Hosting.App.Extensions +{ + internal static class IConfigurationBuilderExtensions + { + public static IConfigurationBuilder AddNeoHostConfiguration(this IConfigurationBuilder configBuilder) + { + _ = EnvironmentUtility.TryGetHostingEnvironment(out var hostEnvironment); + + configBuilder.AddInMemoryCollection( + [ + new(HostDefaults.EnvironmentKey, hostEnvironment ?? NeoHostingEnvironments.MainNet), + new(HostDefaults.ContentRootKey, Environment.CurrentDirectory), + ]); + + configBuilder.SetBasePath(AppContext.BaseDirectory); + + return configBuilder; + } + + public static IConfigurationBuilder AddNeoAppConfiguration(this IConfigurationBuilder configBuilder) + { + _ = EnvironmentUtility.TryGetHostingEnvironment(out var hostEnvironment); + + configBuilder.AddInMemoryCollection( + [ + new(HostDefaults.EnvironmentKey, hostEnvironment ?? NeoHostingEnvironments.MainNet), + new(HostDefaults.ContentRootKey, Environment.CurrentDirectory), + ]); + + configBuilder.SetBasePath(AppContext.BaseDirectory); + + return configBuilder; + } + } +} diff --git a/src/Neo.Hosting.App/Extensions/IHostEnvironmentExtensions.cs b/src/Neo.Hosting.App/Extensions/IHostEnvironmentExtensions.cs new file mode 100644 index 0000000000..860e08a576 --- /dev/null +++ b/src/Neo.Hosting.App/Extensions/IHostEnvironmentExtensions.cs @@ -0,0 +1,44 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// IHostEnvironmentExtensions.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using Microsoft.Extensions.Hosting; +using Neo.Hosting.App.Host; +using System; + +namespace Neo.Hosting.App.Extensions +{ + internal static class IHostEnvironmentExtensions + { + public static bool IsNeoLocalNet(this IHostEnvironment hostEnvironment) + { + ArgumentNullException.ThrowIfNull(hostEnvironment, nameof(hostEnvironment)); + return hostEnvironment.IsEnvironment(NeoHostingEnvironments.LocalNet); + } + + public static bool IsNeoTestNet(this IHostEnvironment hostEnvironment) + { + ArgumentNullException.ThrowIfNull(hostEnvironment, nameof(hostEnvironment)); + return hostEnvironment.IsEnvironment(NeoHostingEnvironments.TestNet); + } + + public static bool IsNeoMainNet(this IHostEnvironment hostEnvironment) + { + ArgumentNullException.ThrowIfNull(hostEnvironment, nameof(hostEnvironment)); + return hostEnvironment.IsEnvironment(NeoHostingEnvironments.MainNet); + } + + public static bool IsNeoPrivateNet(this IHostEnvironment hostEnvironment) + { + ArgumentNullException.ThrowIfNull(hostEnvironment, nameof(hostEnvironment)); + return hostEnvironment.IsEnvironment(NeoHostingEnvironments.PrivateNet); + } + } +} diff --git a/src/Neo.Hosting.App/Handlers/DummyHandler.cs b/src/Neo.Hosting.App/Handlers/DummyHandler.cs new file mode 100644 index 0000000000..a69a9be12e --- /dev/null +++ b/src/Neo.Hosting.App/Handlers/DummyHandler.cs @@ -0,0 +1,29 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// DummyHandler.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using System.CommandLine.Invocation; +using System.Threading.Tasks; + +namespace Neo.Hosting.App.Handlers +{ + public sealed class EmptyHandler : ICommandHandler + { + public int Invoke(InvocationContext context) + { + return 0; + } + + public Task InvokeAsync(InvocationContext context) + { + return Task.FromResult(0); + } + } +} diff --git a/src/Neo.Hosting.App/Handlers/NullExceptionFilter.cs b/src/Neo.Hosting.App/Handlers/NullExceptionFilter.cs new file mode 100644 index 0000000000..ef830a16aa --- /dev/null +++ b/src/Neo.Hosting.App/Handlers/NullExceptionFilter.cs @@ -0,0 +1,32 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// NullExceptionFilter.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using System; +using System.CommandLine.Invocation; + +namespace Neo.Hosting.App.Handlers +{ + internal static class NullExceptionFilter + { + internal static void Handler(Exception exception, InvocationContext context) + { +#if DEBUG + if (exception is not OperationCanceledException) + { + //context.Console.WriteLine(string.Empty); + //context.Console.ErrorMessage(exception); + } +#endif + + context.ExitCode = exception.HResult; + } + } +} diff --git a/src/Neo.Hosting.App/Helpers/EnvironmentUtility.cs b/src/Neo.Hosting.App/Helpers/EnvironmentUtility.cs new file mode 100644 index 0000000000..c5a10ccdb6 --- /dev/null +++ b/src/Neo.Hosting.App/Helpers/EnvironmentUtility.cs @@ -0,0 +1,86 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// EnvironmentUtility.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using Neo.Hosting.App.Host; +using System; +using System.Diagnostics.CodeAnalysis; +using System.IO; +using System.Linq; + +namespace Neo.Hosting.App.Helpers +{ + internal static class EnvironmentUtility + { + private static readonly char[] s_invalidPipeNameChars = Path.GetInvalidFileNameChars(); + + public static bool TryGetServicePipeName([NotNullWhen(true)] out string? pipeName) + { + pipeName = Environment.GetEnvironmentVariable(NeoEnvironmentVariableDefaults.PipeName, EnvironmentVariableTarget.User) + ?? Environment.GetEnvironmentVariable(NeoEnvironmentVariableDefaults.PipeName, EnvironmentVariableTarget.Process); + + if ((string.IsNullOrEmpty(pipeName) && + string.IsNullOrWhiteSpace(pipeName)) || + pipeName.Any(static a => s_invalidPipeNameChars.Contains(a))) + { + pipeName = null; // Clear invalid any pipe name + return false; + } + + return true; + } + + public static bool TrySetServicePipeName(string pipeName) + { + if (string.IsNullOrEmpty(pipeName) && + string.IsNullOrWhiteSpace(pipeName)) + return false; + + if (pipeName.Any(static a => s_invalidPipeNameChars.Contains(a)) == false) + return false; + + Environment.SetEnvironmentVariable(NeoEnvironmentVariableDefaults.PipeName, pipeName, EnvironmentVariableTarget.User); + + return true; + } + + public static void DeleteServicePipeName() => + Environment.SetEnvironmentVariable(NeoEnvironmentVariableDefaults.PipeName, null, EnvironmentVariableTarget.User); + + public static bool TryGetHostingEnvironment([MaybeNullWhen(true)] out string? environment) + { + environment = Environment.GetEnvironmentVariable(NeoEnvironmentVariableDefaults.Environment, EnvironmentVariableTarget.User) + ?? Environment.GetEnvironmentVariable(NeoEnvironmentVariableDefaults.Environment, EnvironmentVariableTarget.Process); + + if (string.IsNullOrEmpty(environment) && + string.IsNullOrWhiteSpace(environment)) + { + environment = null; + return false; + } + + return true; + } + + //public static NamedPipeEndPoint AddOrGetServicePipeName() + //{ + // if (TryGetServicePipeName(out var pipeName)) + // return new(pipeName); + // else + // { + // var endPoint = new NamedPipeEndPoint(Path.GetRandomFileName()); + + // Environment.SetEnvironmentVariable(NeoEnvironmentVariableDefaults.PipeName, endPoint.PipeName, EnvironmentVariableTarget.User); + + // return endPoint; + // } + //} + } +} diff --git a/src/Neo.Hosting.App/Helpers/ParseUtility.cs b/src/Neo.Hosting.App/Helpers/ParseUtility.cs new file mode 100644 index 0000000000..a250a4f370 --- /dev/null +++ b/src/Neo.Hosting.App/Helpers/ParseUtility.cs @@ -0,0 +1,24 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// ParseUtility.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +namespace Neo.Hosting.App.Helpers +{ + internal static class ParseUtility + { + public static UInt160? TryParseUInt160(string? value) + { + if (string.IsNullOrEmpty(value)) return default; + if (UInt160.TryParse(value, out var result)) + return result; + return UInt160.Zero; + } + } +} diff --git a/src/Neo.Hosting.App/Host/NeoDefaults.cs b/src/Neo.Hosting.App/Host/NeoDefaults.cs new file mode 100644 index 0000000000..6da3601936 --- /dev/null +++ b/src/Neo.Hosting.App/Host/NeoDefaults.cs @@ -0,0 +1,18 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// NeoDefaults.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +namespace Neo.Hosting.App.Host +{ + internal static class NeoDefaults + { + public static readonly string StoreProviderName = "MemoryStore"; + } +} diff --git a/src/Neo.Hosting.App/Host/NeoEnvironmentVariableDefaults.cs b/src/Neo.Hosting.App/Host/NeoEnvironmentVariableDefaults.cs new file mode 100644 index 0000000000..1cbc16478d --- /dev/null +++ b/src/Neo.Hosting.App/Host/NeoEnvironmentVariableDefaults.cs @@ -0,0 +1,20 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// NeoEnvironmentVariableDefaults.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +namespace Neo.Hosting.App.Host +{ + internal static class NeoEnvironmentVariableDefaults + { + public const string PREFIX = "NEO_"; + public static readonly string PipeName = $"{PREFIX}_NAMEDPIPE__NAME"; + public static readonly string Environment = $"{PREFIX}ENVIRONMENT"; + } +} diff --git a/src/Neo.Hosting.App/Host/NeoHostingEnvironments.cs b/src/Neo.Hosting.App/Host/NeoHostingEnvironments.cs new file mode 100644 index 0000000000..4fc25ea874 --- /dev/null +++ b/src/Neo.Hosting.App/Host/NeoHostingEnvironments.cs @@ -0,0 +1,25 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// NeoHostingEnvironments.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +namespace Neo.Hosting.App.Host +{ + internal static class NeoHostingEnvironments + { + public static readonly string LocalNet = "localnet"; + + public static readonly string TestNet = "testnet"; + + public static readonly string MainNet = "mainnet"; + + public static readonly string PrivateNet = "privatenet"; + + } +} diff --git a/src/Neo.Hosting.App/Host/NeoJsonSectionNameDefaults.cs b/src/Neo.Hosting.App/Host/NeoJsonSectionNameDefaults.cs new file mode 100644 index 0000000000..14e291a9ae --- /dev/null +++ b/src/Neo.Hosting.App/Host/NeoJsonSectionNameDefaults.cs @@ -0,0 +1,25 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// NeoJsonSectionNameDefaults.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +namespace Neo.Hosting.App.Host +{ + internal class NeoJsonSectionNameDefaults + { + public static readonly string Application = "ApplicationConfiguration"; + public static readonly string Archive = "Archive"; + public static readonly string Contract = "Contract"; + public static readonly string NamedPipeTransport = "NamedPipeTransport"; + public static readonly string PeerToPeer = "P2P"; + public static readonly string Plugin = "Plugin"; + public static readonly string Remote = "Remote"; + public static readonly string Storage = "Storage"; + } +} diff --git a/src/Neo.Hosting.App/Host/NeoProtocolSettingsDefaults.cs b/src/Neo.Hosting.App/Host/NeoProtocolSettingsDefaults.cs new file mode 100644 index 0000000000..81246732be --- /dev/null +++ b/src/Neo.Hosting.App/Host/NeoProtocolSettingsDefaults.cs @@ -0,0 +1,120 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// NeoProtocolSettingsDefaults.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using Neo.Cryptography.ECC; +using System.Collections.Generic; +using System.Collections.Immutable; + +namespace Neo.Hosting.App.Host +{ + internal class NeoProtocolSettingsDefaults + { + public static ProtocolSettings MainNet = new() + { + Network = 860833102u, + AddressVersion = 53, + MillisecondsPerBlock = 15_000u, + MaxTransactionsPerBlock = 512u, + MemoryPoolMaxTransactions = 50_000, + MaxTraceableBlocks = 2_102_400u, + InitialGasDistribution = 5_200_000_000_000_000ul, + ValidatorsCount = 7, + StandbyCommittee = [ + // Validators + ECPoint.Parse("03b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c", ECCurve.Secp256r1), + ECPoint.Parse("02df48f60e8f3e01c48ff40b9b7f1310d7a8b2a193188befe1c2e3df740e895093", ECCurve.Secp256r1), + ECPoint.Parse("03b8d9d5771d8f513aa0869b9cc8d50986403b78c6da36890638c3d46a5adce04a", ECCurve.Secp256r1), + ECPoint.Parse("02ca0e27697b9c248f6f16e085fd0061e26f44da85b58ee835c110caa5ec3ba554", ECCurve.Secp256r1), + ECPoint.Parse("024c7b7fb6c310fccf1ba33b082519d82964ea93868d676662d4a59ad548df0e7d", ECCurve.Secp256r1), + ECPoint.Parse("02aaec38470f6aad0042c6e877cfd8087d2676b0f516fddd362801b9bd3936399e", ECCurve.Secp256r1), + ECPoint.Parse("02486fd15702c4490a26703112a5cc1d0923fd697a33406bd5a1c00e0013b09a70", ECCurve.Secp256r1), + // Other Members + ECPoint.Parse("023a36c72844610b4d34d1968662424011bf783ca9d984efa19a20babf5582f3fe", ECCurve.Secp256r1), + ECPoint.Parse("03708b860c1de5d87f5b151a12c2a99feebd2e8b315ee8e7cf8aa19692a9e18379", ECCurve.Secp256r1), + ECPoint.Parse("03c6aa6e12638b36e88adc1ccdceac4db9929575c3e03576c617c49cce7114a050", ECCurve.Secp256r1), + ECPoint.Parse("03204223f8c86b8cd5c89ef12e4f0dbb314172e9241e30c9ef2293790793537cf0", ECCurve.Secp256r1), + ECPoint.Parse("02a62c915cf19c7f19a50ec217e79fac2439bbaad658493de0c7d8ffa92ab0aa62", ECCurve.Secp256r1), + ECPoint.Parse("03409f31f0d66bdc2f70a9730b66fe186658f84a8018204db01c106edc36553cd0", ECCurve.Secp256r1), + ECPoint.Parse("0288342b141c30dc8ffcde0204929bb46aed5756b41ef4a56778d15ada8f0c6654", ECCurve.Secp256r1), + ECPoint.Parse("020f2887f41474cfeb11fd262e982051c1541418137c02a0f4961af911045de639", ECCurve.Secp256r1), + ECPoint.Parse("0222038884bbd1d8ff109ed3bdef3542e768eef76c1247aea8bc8171f532928c30", ECCurve.Secp256r1), + ECPoint.Parse("03d281b42002647f0113f36c7b8efb30db66078dfaaa9ab3ff76d043a98d512fde", ECCurve.Secp256r1), + ECPoint.Parse("02504acbc1f4b3bdad1d86d6e1a08603771db135a73e61c9d565ae06a1938cd2ad", ECCurve.Secp256r1), + ECPoint.Parse("0226933336f1b75baa42d42b71d9091508b638046d19abd67f4e119bf64a7cfb4d", ECCurve.Secp256r1), + ECPoint.Parse("03cdcea66032b82f5c30450e381e5295cae85c5e6943af716cc6b646352a6067dc", ECCurve.Secp256r1), + ECPoint.Parse("02cd5a5547119e24feaa7c2a0f37b8c9366216bab7054de0065c9be42084003c8a", ECCurve.Secp256r1) + ], + SeedList = [ + "seed1.neo.org:10333", + "seed2.neo.org:10333", + "seed3.neo.org:10333", + "seed4.neo.org:10333", + "seed5.neo.org:10333" + ], + Hardforks = new Dictionary() + { + [Hardfork.HF_Aspidochelone] = 1_730_000u, + [Hardfork.HF_Basilisk] = 4_120_000u, + [Hardfork.HF_Cockatrice] = 5_450_000u, + }.ToImmutableDictionary(), + }; + + public static ProtocolSettings TestNet = new() + { + Network = 894710606u, + AddressVersion = 53, + MillisecondsPerBlock = 15_000u, + MaxTransactionsPerBlock = 5_000u, + MemoryPoolMaxTransactions = 50_000, + MaxTraceableBlocks = 2_102_400u, + InitialGasDistribution = 5_200_000_000_000_000ul, + ValidatorsCount = 7, + StandbyCommittee = [ + // Validators + ECPoint.Parse("023e9b32ea89b94d066e649b124fd50e396ee91369e8e2a6ae1b11c170d022256d", ECCurve.Secp256r1), + ECPoint.Parse("03009b7540e10f2562e5fd8fac9eaec25166a58b26e412348ff5a86927bfac22a2", ECCurve.Secp256r1), + ECPoint.Parse("02ba2c70f5996f357a43198705859fae2cfea13e1172962800772b3d588a9d4abd", ECCurve.Secp256r1), + ECPoint.Parse("03408dcd416396f64783ac587ea1e1593c57d9fea880c8a6a1920e92a259477806", ECCurve.Secp256r1), + ECPoint.Parse("02a7834be9b32e2981d157cb5bbd3acb42cfd11ea5c3b10224d7a44e98c5910f1b", ECCurve.Secp256r1), + ECPoint.Parse("0214baf0ceea3a66f17e7e1e839ea25fd8bed6cd82e6bb6e68250189065f44ff01", ECCurve.Secp256r1), + ECPoint.Parse("030205e9cefaea5a1dfc580af20c8d5aa2468bb0148f1a5e4605fc622c80e604ba", ECCurve.Secp256r1), + // Other Members + ECPoint.Parse("025831cee3708e87d78211bec0d1bfee9f4c85ae784762f042e7f31c0d40c329b8", ECCurve.Secp256r1), + ECPoint.Parse("02cf9dc6e85d581480d91e88e8cbeaa0c153a046e89ded08b4cefd851e1d7325b5", ECCurve.Secp256r1), + ECPoint.Parse("03840415b0a0fcf066bcc3dc92d8349ebd33a6ab1402ef649bae00e5d9f5840828", ECCurve.Secp256r1), + ECPoint.Parse("026328aae34f149853430f526ecaa9cf9c8d78a4ea82d08bdf63dd03c4d0693be6", ECCurve.Secp256r1), + ECPoint.Parse("02c69a8d084ee7319cfecf5161ff257aa2d1f53e79bf6c6f164cff5d94675c38b3", ECCurve.Secp256r1), + ECPoint.Parse("0207da870cedb777fceff948641021714ec815110ca111ccc7a54c168e065bda70", ECCurve.Secp256r1), + ECPoint.Parse("035056669864feea401d8c31e447fb82dd29f342a9476cfd449584ce2a6165e4d7", ECCurve.Secp256r1), + ECPoint.Parse("0370c75c54445565df62cfe2e76fbec4ba00d1298867972213530cae6d418da636", ECCurve.Secp256r1), + ECPoint.Parse("03957af9e77282ae3263544b7b2458903624adc3f5dee303957cb6570524a5f254", ECCurve.Secp256r1), + ECPoint.Parse("03d84d22b8753cf225d263a3a782a4e16ca72ef323cfde04977c74f14873ab1e4c", ECCurve.Secp256r1), + ECPoint.Parse("02147c1b1d5728e1954958daff2f88ee2fa50a06890a8a9db3fa9e972b66ae559f", ECCurve.Secp256r1), + ECPoint.Parse("03c609bea5a4825908027e4ab217e7efc06e311f19ecad9d417089f14927a173d5", ECCurve.Secp256r1), + ECPoint.Parse("0231edee3978d46c335e851c76059166eb8878516f459e085c0dd092f0f1d51c21", ECCurve.Secp256r1), + ECPoint.Parse("03184b018d6b2bc093e535519732b3fd3f7551c8cffaf4621dd5a0b89482ca66c9", ECCurve.Secp256r1) + ], + SeedList = [ + "seed1t5.neo.org:20333", + "seed2t5.neo.org:20333", + "seed3t5.neo.org:20333", + "seed4t5.neo.org:20333", + "seed5t5.neo.org:20333" + ], + Hardforks = new Dictionary() + { + [Hardfork.HF_Aspidochelone] = 210_000u, + [Hardfork.HF_Basilisk] = 2_680_000u, + [Hardfork.HF_Cockatrice] = 3_967_000u, + }.ToImmutableDictionary(), + }; + } +} diff --git a/src/Neo.Hosting.App/Neo.Hosting.App.csproj b/src/Neo.Hosting.App/Neo.Hosting.App.csproj new file mode 100644 index 0000000000..fb26b0f814 --- /dev/null +++ b/src/Neo.Hosting.App/Neo.Hosting.App.csproj @@ -0,0 +1,41 @@ + + + + Exe + net8.0 + Neo.Hosting.App + neo-cmd + enable + true + ../../bin/$(AssemblyTitle) + + + + + + + + + Always + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Neo.Hosting.App/Program.Configurations.cs b/src/Neo.Hosting.App/Program.Configurations.cs new file mode 100644 index 0000000000..9dfd116b25 --- /dev/null +++ b/src/Neo.Hosting.App/Program.Configurations.cs @@ -0,0 +1,86 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// Program.Configurations.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Diagnostics.Metrics; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Console; +using Microsoft.Extensions.Logging.Debug; +using Microsoft.Extensions.Logging.EventLog; +using Neo.Hosting.App.Extensions; +using System; + +namespace Neo.Hosting.App +{ + public partial class Program + { + internal static IHostBuilder DefaultNeoHostBuilderFactory(string[] args) => + new HostBuilder() + .UseNeoHostConfiguration() + .UseNeoAppConfiguration() + .ConfigureServices(AddDefaultServices) + .UseServiceProviderFactory((context) => new DefaultServiceProviderFactory(CreateDefaultNeoServiceProviderOptions(context))); + + static ServiceProviderOptions CreateDefaultNeoServiceProviderOptions(HostBuilderContext context) + { + var flag = context.HostingEnvironment.IsNeoLocalNet(); + return new ServiceProviderOptions + { + ValidateScopes = flag, + ValidateOnBuild = flag + }; + } + + static void AddDefaultServices(HostBuilderContext hostingContext, IServiceCollection services) + { + services.AddLogging(logging => + { + logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging")); + + var isWindows = OperatingSystem.IsWindows(); + if (isWindows && hostingContext.HostingEnvironment.IsNeoLocalNet() == false) + logging.AddFilter(level => level >= Microsoft.Extensions.Logging.LogLevel.Warning); + +#if DEBUG + logging.AddFilter(level => level >= Microsoft.Extensions.Logging.LogLevel.Trace); + logging.AddDebug(); +#endif + logging.AddEventSourceLogger(); + + //if (IsRunningAsService == false) + // logging.AddCommandLineLogger(); // Neo CommandLine Logger + //else + //{ + logging.AddSimpleConsole(config => + { + config.ColorBehavior = LoggerColorBehavior.Enabled; + config.SingleLine = true; + config.TimestampFormat = "[yyyy-MM-dd HH:mm:ss.fff] "; + config.UseUtcTimestamp = false; + }); + //} + + if (isWindows) + logging.AddEventLog(); + + logging.Configure(options => + { + options.ActivityTrackingOptions = + ActivityTrackingOptions.SpanId | + ActivityTrackingOptions.TraceId | + ActivityTrackingOptions.ParentId; + }); + }); + } + } +} diff --git a/src/Neo.Hosting.App/Program.cs b/src/Neo.Hosting.App/Program.cs new file mode 100644 index 0000000000..31af2791d6 --- /dev/null +++ b/src/Neo.Hosting.App/Program.cs @@ -0,0 +1,68 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// Program.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Hosting.Systemd; +using Microsoft.Extensions.Hosting.WindowsServices; +using Neo.Extensions; +using Neo.Hosting.App.CommandLine; +using Neo.Hosting.App.Extensions; +using Neo.Hosting.App.Handlers; +using System; +using System.CommandLine; +using System.CommandLine.Builder; +using System.CommandLine.Hosting; +using System.CommandLine.Parsing; +using System.Reflection; +using System.Threading.Tasks; + +namespace Neo.Hosting.App +{ + public sealed partial class Program + { + internal const string DEFAULT_VERSION_STRING = "0.0.0"; + + internal static int ApplicationVersionNumber => + AssemblyUtility.GetVersionNumber(); + + internal static Version ApplicationVersion => + Assembly.GetExecutingAssembly().GetName().Version ?? new Version("0.0.0"); + + internal static bool IsRunningAsService => + (SystemdHelpers.IsSystemdService() || WindowsServiceHelpers.IsWindowsService()) || Environment.UserInteractive == false; + + static async Task Main(string[] args) + { + Console.BackgroundColor = ConsoleColor.Black; + Console.Clear(); + + var rootCommand = new DefaultRootCommand(); + var parser = new CommandLineBuilder(rootCommand) + .UseInternalHost(DefaultNeoHostBuilderFactory, builder => + { + builder.UseNeoServices(); + builder.UseNeoSystem(); + builder.UseCommandHandler(); + //builder.UseCommandHandler(); + //builder.UseCommandHandler(); + //builder.UseCommandHandler(); + //builder.UseCommandHandler(); + builder.UseSystemd(); + builder.UseWindowsService(); + }) + .UseDefaults() + .UseExceptionHandler(NullExceptionFilter.Handler) + .Build(); + + return await parser.InvokeAsync(args); + } + } +} diff --git a/src/Neo.Hosting.App/Providers/NeoConfigurationProvider.cs b/src/Neo.Hosting.App/Providers/NeoConfigurationProvider.cs new file mode 100644 index 0000000000..59005a3664 --- /dev/null +++ b/src/Neo.Hosting.App/Providers/NeoConfigurationProvider.cs @@ -0,0 +1,120 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// NeoConfigurationProvider.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using Akka.Util.Internal; +using Microsoft.Extensions.Configuration; +using Neo.Hosting.App.Host; +using Neo.Network.P2P; +using System; +using System.Collections; +using System.Collections.Generic; + +namespace Neo.Hosting.App.Providers +{ + internal class NeoConfigurationProvider + (IConfigurationSection? configurationSection = null) : ConfigurationProvider + { + public override void Load() + { + Data = CreateDefaultKeys(); + Load(Environment.GetEnvironmentVariables(EnvironmentVariableTarget.User)); + Load(Environment.GetEnvironmentVariables(EnvironmentVariableTarget.Process)); + + if (configurationSection is not null) + Load(configurationSection); + } + + internal void Load(IDictionary envVariables) + { + var e = envVariables.GetEnumerator(); + + try + { + while (e.MoveNext()) + { + var key = (string)e.Entry.Key; + var value = (string?)e.Entry.Value; + + AddIfNormalizedKeyMatchesPrefix(Data, Normalize(key), value); + } + } + finally + { + (e as IDisposable)?.Dispose(); + } + } + + internal void Load(IConfigurationSection section) + { + var e = section.AsEnumerable().GetEnumerator(); + var prefix = $"{section.Key}:"; + + try + { + while (e.MoveNext()) + { + var key = e.Current.Key; + var value = e.Current.Value; + + if (key.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)) + Data.AddOrSet(key[prefix.Length..], value); + } + } + finally + { + (e as IDisposable)?.Dispose(); + } + } + + private static Dictionary CreateDefaultKeys() => + new(StringComparer.OrdinalIgnoreCase) + { + // Storage + ["STORAGE:PATH"] = "Data_LevelDB_{0:X2}", + ["STORAGE:ENGINE"] = NeoDefaults.StoreProviderName, + ["STORAGE:VERIFY"] = bool.TrueString, + ["STORAGE:ARCHIVE:PATH"] = AppContext.BaseDirectory, + ["STORAGE:ARCHIVE:FILENAME"] = "chain.{0}.acc", + + // P2P + ["P2P:LISTEN"] = "0.0.0.0", + ["P2P:PORT"] = "10333", + ["P2P:MINDESIREDCONNECTIONS"] = $"{Peer.DefaultMinDesiredConnections}", + ["P2P:MAXCONNECTIONS"] = $"{Peer.DefaultMaxConnections}", + ["P2P:MAXCONNECTIONSPERADDRESS"] = "3", + + // Contracts + ["CONTRACT:NEONAMESERVICE"] = "0x50ac1c37690cc2cfc594472833cf57505d5f46de", + + // Plugin + ["PLUGIN:DOWNLOADURL"] = "https://api.github.com/repos/neo-project/neo/releases", + ["PLUGIN:PRERELEASE"] = bool.FalseString, + ["PLUGIN:VERSION"] = $"{Program.ApplicationVersion.ToString(3)}", + + // Remote + ["NAMEDPIPE:NAME"] = $"NEO_SERVICE", + }; + + private static void AddIfNormalizedKeyMatchesPrefix(IDictionary data, string normalizedKey, string? value) + { + var normalizedPrefix1 = NeoEnvironmentVariableDefaults.PREFIX; + var normalizedPrefix2 = $"NEO:"; + + if (normalizedKey.StartsWith(normalizedPrefix1, StringComparison.OrdinalIgnoreCase)) + data[normalizedKey[normalizedPrefix1.Length..]] = value; + else if (normalizedKey.StartsWith(normalizedPrefix2, StringComparison.OrdinalIgnoreCase)) + data[normalizedKey[normalizedPrefix2.Length..]] = value; + } + + private static string Normalize(string key) => + key.Replace("__", ConfigurationPath.KeyDelimiter); + } +} diff --git a/src/Neo.Hosting.App/config.localnet.json b/src/Neo.Hosting.App/config.localnet.json new file mode 100644 index 0000000000..ec91c176bb --- /dev/null +++ b/src/Neo.Hosting.App/config.localnet.json @@ -0,0 +1,83 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information" + }, + "NeoError": { + "LogLevel": { + "Default": "Error" + } + } + }, + "ApplicationConfiguration": { + "Storage": { + "Engine": "MemoryStore", + "Verify": false, + "Archive": { + "FileName": "chain.{0}.acc" + } + }, + "P2P": { + "Listen": "127.0.0.1", + "Port": 226 + }, + "Contract": { + "NeoNameService": "0x50ac1c37690cc2cfc594472833cf57505d5f46de" + }, + "NamedPipe": { + "Name": "HelloPipe" + }, + "Wallets": [ + { + "Name": "MyTestWallet", + "Path": "./wallets/hello.json", + "Password": "hello", + "IsActive": true + } + ] + }, + "ProtocolConfiguration": { + "Network": 860833102, + "AddressVersion": 53, + "MillisecondsPerBlock": 15000, + "MaxTransactionsPerBlock": 512, + "MemoryPoolMaxTransactions": 50000, + "MaxTraceableBlocks": 2102400, + "Hardforks": { + "HF_Aspidochelone": 1730000, + "HF_Basilisk": 4120000 + }, + "InitialGasDistribution": 5200000000000000, + "ValidatorsCount": 7, + "StandbyCommittee": [ + "03b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c", + "02df48f60e8f3e01c48ff40b9b7f1310d7a8b2a193188befe1c2e3df740e895093", + "03b8d9d5771d8f513aa0869b9cc8d50986403b78c6da36890638c3d46a5adce04a", + "02ca0e27697b9c248f6f16e085fd0061e26f44da85b58ee835c110caa5ec3ba554", + "024c7b7fb6c310fccf1ba33b082519d82964ea93868d676662d4a59ad548df0e7d", + "02aaec38470f6aad0042c6e877cfd8087d2676b0f516fddd362801b9bd3936399e", + "02486fd15702c4490a26703112a5cc1d0923fd697a33406bd5a1c00e0013b09a70", + "023a36c72844610b4d34d1968662424011bf783ca9d984efa19a20babf5582f3fe", + "03708b860c1de5d87f5b151a12c2a99feebd2e8b315ee8e7cf8aa19692a9e18379", + "03c6aa6e12638b36e88adc1ccdceac4db9929575c3e03576c617c49cce7114a050", + "03204223f8c86b8cd5c89ef12e4f0dbb314172e9241e30c9ef2293790793537cf0", + "02a62c915cf19c7f19a50ec217e79fac2439bbaad658493de0c7d8ffa92ab0aa62", + "03409f31f0d66bdc2f70a9730b66fe186658f84a8018204db01c106edc36553cd0", + "0288342b141c30dc8ffcde0204929bb46aed5756b41ef4a56778d15ada8f0c6654", + "020f2887f41474cfeb11fd262e982051c1541418137c02a0f4961af911045de639", + "0222038884bbd1d8ff109ed3bdef3542e768eef76c1247aea8bc8171f532928c30", + "03d281b42002647f0113f36c7b8efb30db66078dfaaa9ab3ff76d043a98d512fde", + "02504acbc1f4b3bdad1d86d6e1a08603771db135a73e61c9d565ae06a1938cd2ad", + "0226933336f1b75baa42d42b71d9091508b638046d19abd67f4e119bf64a7cfb4d", + "03cdcea66032b82f5c30450e381e5295cae85c5e6943af716cc6b646352a6067dc", + "02cd5a5547119e24feaa7c2a0f37b8c9366216bab7054de0065c9be42084003c8a" + ], + "SeedList": [ + "seed1.neo.org:10333", + "seed2.neo.org:10333", + "seed3.neo.org:10333", + "seed4.neo.org:10333", + "seed5.neo.org:10333" + ] + } +} diff --git a/src/Neo/Cryptography/Crc32.cs b/src/Neo/Cryptography/Crc32.cs new file mode 100644 index 0000000000..15af3bad88 --- /dev/null +++ b/src/Neo/Cryptography/Crc32.cs @@ -0,0 +1,116 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// Crc32.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using System; +using System.Collections.Generic; +using System.Security.Cryptography; + +namespace Neo.Cryptography +{ + public sealed class Crc32 : HashAlgorithm + { + public static readonly uint DefaultPolynomial = 0xedb88320u; + public static readonly uint DefaultSeed = 0xffffffffu; + + private static uint[] s_defaultTable; + + public override int HashSize => 32; + + private readonly uint _seed; + private readonly uint[] _table; + private uint _hash; + + public Crc32() : this(DefaultPolynomial, DefaultSeed) + { + + } + + public Crc32( + uint polynomial, + uint seed) + { + if (BitConverter.IsLittleEndian) + throw new PlatformNotSupportedException("Not supported on Big Endian processors"); + + _table = InitializeTable(polynomial); + _seed = seed; + } + + public override void Initialize() + { + _hash = _seed; + } + + protected override void HashCore(byte[] array, int ibStart, int cbSize) + { + _hash = CalculateHash(_table, _hash, array, ibStart, cbSize); + } + + protected override byte[] HashFinal() + { + var hashBuffer = Crc32.UInt32ToBigEndianBytes(~_hash); + HashValue = hashBuffer; + return hashBuffer; + } + + public static uint Compute(byte[] buffer) => + Compute(DefaultSeed, buffer); + + public static uint Compute(uint seed, byte[] buffer) => + Compute(DefaultPolynomial, seed, buffer); + + public static uint Compute(uint polynomial, uint seed, byte[] buffer) => + ~CalculateHash(InitializeTable(polynomial), seed, buffer, 0, buffer.Length); + + private static uint[] InitializeTable(uint polynomial) + { + if (polynomial == DefaultPolynomial && s_defaultTable != null) + return s_defaultTable; + + var createTable = new uint[256]; + for (var i = 0u; i < 256u; i++) + { + var entry = i; + for (var j = 0; j < 8; j++) + { + if ((entry & 1) == 1) + entry = (entry >> 1) ^ polynomial; + else + entry >>= 1; + } + createTable[i] = entry; + } + + if (polynomial == DefaultPolynomial) + s_defaultTable = createTable; + + return createTable; + } + + private static uint CalculateHash(uint[] table, uint seed, IList buffer, int start, int size) + { + var hash = seed; + for (var i = start; i < start + size; i++) + hash = (hash >> 8) ^ table[buffer[i] ^ hash & 0xff]; + return hash; + } + + private static byte[] UInt32ToBigEndianBytes(uint value) + { + var result = BitConverter.GetBytes(value); + + if (BitConverter.IsLittleEndian) + Array.Reverse(result); + + return result; + } + } +} diff --git a/src/Neo/Neo.csproj b/src/Neo/Neo.csproj index 835224eddd..f71ce1a433 100644 --- a/src/Neo/Neo.csproj +++ b/src/Neo/Neo.csproj @@ -30,6 +30,7 @@ +