Example #1
0
        public static async Task <CoreNode> CreateAsync(CoreNodeParams coreNodeParams, CancellationToken cancel)
        {
            Guard.NotNull(nameof(coreNodeParams), coreNodeParams);
            using (BenchmarkLogger.Measure())
            {
                var coreNode = new CoreNode();
                coreNode.DataDir        = coreNodeParams.DataDir;
                coreNode.Network        = coreNodeParams.Network;
                coreNode.MempoolService = coreNodeParams.MempoolService;

                var configPath = Path.Combine(coreNode.DataDir, "bitcoin.conf");
                coreNode.Config = new CoreConfig();
                if (File.Exists(configPath))
                {
                    var configString = await File.ReadAllTextAsync(configPath).ConfigureAwait(false);

                    coreNode.Config.TryAdd(configString);
                }

                var      configDic         = coreNode.Config.ToDictionary();
                string   rpcUser           = null;
                string   rpcPassword       = null;
                EndPoint whitebind         = null;
                string   rpcHost           = null;
                int?     rpcPort           = null;
                string   rpcCookieFilePath = null;
                foreach (var networkPrefixWithDot in NetworkTranslator.GetConfigPrefixesWithDots(coreNode.Network))
                {
                    var rpcc = configDic.TryGet($"{networkPrefixWithDot}rpccookiefile");
                    var ru   = configDic.TryGet($"{networkPrefixWithDot}rpcuser");
                    var rp   = configDic.TryGet($"{networkPrefixWithDot}rpcpassword");
                    var wbs  = configDic.TryGet($"{networkPrefixWithDot}whitebind");
                    var rpst = configDic.TryGet($"{networkPrefixWithDot}rpchost");
                    var rpts = configDic.TryGet($"{networkPrefixWithDot}rpcport");

                    if (rpcc != null)
                    {
                        rpcCookieFilePath = rpcc;
                    }
                    if (ru != null)
                    {
                        rpcUser = ru;
                    }
                    if (rp != null)
                    {
                        rpcPassword = rp;
                    }
                    if (wbs != null && EndPointParser.TryParse(wbs, coreNode.Network.DefaultPort, out EndPoint wb))
                    {
                        whitebind = wb;
                    }
                    if (rpst != null)
                    {
                        rpcHost = rpst;
                    }
                    if (rpts != null && int.TryParse(rpts, out int rpt))
                    {
                        rpcPort = rpt;
                    }
                }

                string authString;
                bool   cookieAuth = rpcCookieFilePath != null;
                if (cookieAuth)
                {
                    authString = $"cookiefile={rpcCookieFilePath}";
                }
                else
                {
                    rpcUser ??= Encoders.Hex.EncodeData(RandomUtils.GetBytes(21));
                    rpcPassword ??= Encoders.Hex.EncodeData(RandomUtils.GetBytes(21));
                    authString = $"{rpcUser}:{rpcPassword}";
                }

                coreNode.P2pEndPoint = whitebind ?? coreNodeParams.P2pEndPointStrategy.EndPoint;
                rpcHost ??= coreNodeParams.RpcEndPointStrategy.EndPoint.GetHostOrDefault();
                rpcPort ??= coreNodeParams.RpcEndPointStrategy.EndPoint.GetPortOrDefault();
                EndPointParser.TryParse($"{rpcHost}:{rpcPort}", coreNode.Network.RPCPort, out EndPoint rpce);
                coreNode.RpcEndPoint = rpce;

                coreNode.RpcClient = new RPCClient($"{authString}", coreNode.RpcEndPoint.ToString(coreNode.Network.DefaultPort), coreNode.Network);

                if (coreNodeParams.TryRestart)
                {
                    await coreNode.TryStopAsync(false).ConfigureAwait(false);
                }

                if (coreNodeParams.TryDeleteDataDir)
                {
                    await IoHelpers.DeleteRecursivelyWithMagicDustAsync(coreNode.DataDir).ConfigureAwait(false);
                }

                IoHelpers.EnsureDirectoryExists(coreNode.DataDir);

                var configPrefix       = NetworkTranslator.GetConfigPrefix(coreNode.Network);
                var desiredConfigLines = new List <string>()
                {
                    $"{configPrefix}.server			= 1",
                    $"{configPrefix}.listen			= 1",
                    $"{configPrefix}.whitebind		= {coreNode.P2pEndPoint.ToString(coreNode.Network.DefaultPort)}",
                    $"{configPrefix}.rpchost		= {coreNode.RpcEndPoint.GetHostOrDefault()}",
                    $"{configPrefix}.rpcport		= {coreNode.RpcEndPoint.GetPortOrDefault()}"
                };

                if (!cookieAuth)
                {
                    desiredConfigLines.Add($"{configPrefix}.rpcuser		= {coreNode.RpcClient.CredentialString.UserPassword.UserName}");
                    desiredConfigLines.Add($"{configPrefix}.rpcpassword	= {coreNode.RpcClient.CredentialString.UserPassword.Password}");
                }

                if (coreNodeParams.TxIndex != null)
                {
                    desiredConfigLines.Add($"{configPrefix}.txindex = {coreNodeParams.TxIndex}");
                }

                if (coreNodeParams.Prune != null)
                {
                    desiredConfigLines.Add($"{configPrefix}.prune = {coreNodeParams.Prune}");
                }

                var sectionComment = $"# The following configuration options were added or modified by Wasabi Wallet.";
                // If the comment is not already present.
                // And there would be new config entries added.
                var throwAwayConfig = new CoreConfig(coreNode.Config);
                throwAwayConfig.AddOrUpdate(string.Join(Environment.NewLine, desiredConfigLines));
                if (!coreNode.Config.ToString().Contains(sectionComment, StringComparison.Ordinal) &&
                    throwAwayConfig.Count != coreNode.Config.Count)
                {
                    desiredConfigLines.Insert(0, sectionComment);
                }

                if (coreNode.Config.AddOrUpdate(string.Join(Environment.NewLine, desiredConfigLines)) ||
                    !File.Exists(configPath))
                {
                    IoHelpers.EnsureContainingDirectoryExists(configPath);
                    await File.WriteAllTextAsync(configPath, coreNode.Config.ToString());
                }

                // If it isn't already running, then we run it.
                if (await coreNode.RpcClient.TestAsync().ConfigureAwait(false) is null)
                {
                    Logger.LogInfo("Bitcoin Core is already running.");
                }
        public static async Task <CoreNode> CreateAsync(CoreNodeParams coreNodeParams, CancellationToken cancel)
        {
            Guard.NotNull(nameof(coreNodeParams), coreNodeParams);
            using (BenchmarkLogger.Measure())
            {
                var coreNode = new CoreNode();
                coreNode.HostedServices = coreNodeParams.HostedServices;
                coreNode.DataDir        = coreNodeParams.DataDir;
                coreNode.Network        = coreNodeParams.Network;
                coreNode.MempoolService = coreNodeParams.MempoolService;

                var configPath = Path.Combine(coreNode.DataDir, "bitcoin.conf");
                coreNode.Config = new CoreConfig();
                if (File.Exists(configPath))
                {
                    var configString = await File.ReadAllTextAsync(configPath).ConfigureAwait(false);

                    coreNode.Config.AddOrUpdate(configString);                     // Bitcoin Core considers the last entry to be valid.
                }
                cancel.ThrowIfCancellationRequested();

                var configTranslator = new CoreConfigTranslator(coreNode.Config, coreNode.Network);

                string    rpcUser           = configTranslator.TryGetRpcUser();
                string    rpcPassword       = configTranslator.TryGetRpcPassword();
                string    rpcCookieFilePath = configTranslator.TryGetRpcCookieFile();
                string    rpcHost           = configTranslator.TryGetRpcBind();
                int?      rpcPort           = configTranslator.TryGetRpcPort();
                WhiteBind whiteBind         = configTranslator.TryGetWhiteBind();

                string authString;
                bool   cookieAuth = rpcCookieFilePath is { };
                if (cookieAuth)
                {
                    authString = $"cookiefile={rpcCookieFilePath}";
                }
                else
                {
                    rpcUser ??= Encoders.Hex.EncodeData(RandomUtils.GetBytes(21));
                    rpcPassword ??= Encoders.Hex.EncodeData(RandomUtils.GetBytes(21));
                    authString = $"{rpcUser}:{rpcPassword}";
                }

                coreNode.P2pEndPoint = whiteBind?.EndPoint ?? coreNodeParams.P2pEndPointStrategy.EndPoint;
                rpcHost ??= coreNodeParams.RpcEndPointStrategy.EndPoint.GetHostOrDefault();
                rpcPort ??= coreNodeParams.RpcEndPointStrategy.EndPoint.GetPortOrDefault();
                EndPointParser.TryParse($"{rpcHost}:{rpcPort}", coreNode.Network.RPCPort, out EndPoint rpce);
                coreNode.RpcEndPoint = rpce;

                var rpcClient = new RPCClient(
                    $"{authString}",
                    coreNode.RpcEndPoint.ToString(coreNode.Network.DefaultPort),
                    coreNode.Network);
                coreNode.RpcClient = new CachedRpcClient(rpcClient, coreNodeParams.Cache);

                if (coreNodeParams.TryRestart)
                {
                    await coreNode.TryStopAsync(false).ConfigureAwait(false);
                }
                cancel.ThrowIfCancellationRequested();

                if (coreNodeParams.TryDeleteDataDir)
                {
                    await IoHelpers.DeleteRecursivelyWithMagicDustAsync(coreNode.DataDir).ConfigureAwait(false);
                }
                cancel.ThrowIfCancellationRequested();

                IoHelpers.EnsureDirectoryExists(coreNode.DataDir);

                var configPrefix             = NetworkTranslator.GetConfigPrefix(coreNode.Network);
                var whiteBindPermissionsPart = !string.IsNullOrWhiteSpace(whiteBind?.Permissions) ? $"{whiteBind?.Permissions}@" : "";
                var desiredConfigLines       = new List <string>()
                {
                    $"{configPrefix}.server			= 1",
                    $"{configPrefix}.listen			= 1",
                    $"{configPrefix}.whitebind		= {whiteBindPermissionsPart}{coreNode.P2pEndPoint.ToString(coreNode.Network.DefaultPort)}",
                    $"{configPrefix}.rpcbind		= {coreNode.RpcEndPoint.GetHostOrDefault()}",
                    $"{configPrefix}.rpcallowip		= {IPAddress.Loopback}",
                    $"{configPrefix}.rpcport		= {coreNode.RpcEndPoint.GetPortOrDefault()}"
                };

                if (!cookieAuth)
                {
                    desiredConfigLines.Add($"{configPrefix}.rpcuser		= {coreNode.RpcClient.CredentialString.UserPassword.UserName}");
                    desiredConfigLines.Add($"{configPrefix}.rpcpassword	= {coreNode.RpcClient.CredentialString.UserPassword.Password}");
                }

                if (coreNodeParams.TxIndex is { })