public FullNodeTumblerClientConfiguration(TumblingState tumblingState, bool onlyMonitor, bool connectionTest = false, bool useProxy = true)
        {
            this.tumblingState = tumblingState ?? throw new ArgumentNullException(nameof(tumblingState));
            Network            = tumblingState.TumblerNetwork ?? throw new ArgumentNullException(nameof(tumblingState.TumblerNetwork));

            Logs.LogDir = this.tumblingState.NodeSettings.DataDir;

            if (!onlyMonitor || connectionTest)
            {
                TorPath = "tor";

                Cooperative   = true;
                AllowInsecure = true;

                if (tumblingState.TumblerUri != null)
                {
                    TumblerServer = new TumblerUrlBuilder(this.tumblingState.TumblerUri);
                    if (TumblerServer == null)
                    {
                        throw new ConfigException("Tumbler server is not configured");
                    }
                }

                if (useProxy)
                {
                    AliceConnectionSettings = new SocksConnectionSettings()
                    {
                        Proxy = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 9050)
                    };

                    BobConnectionSettings = new SocksConnectionSettings()
                    {
                        Proxy = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 9050)
                    };
                }
                else
                {
                    // This mode is only for unit/integration tests, as it allows testing with latency introduced by Tor
                    AliceConnectionSettings = new ConnectionSettingsBase();
                    BobConnectionSettings   = new ConnectionSettingsBase();
                }

                if (connectionTest)
                {
                    return;
                }
            }

            OnlyMonitor = onlyMonitor;
            Logs.Configuration.LogInformation("Network: " + Network);
            DataDir = GetTumbleBitDataDir(this.tumblingState.NodeSettings.DataDir);
            Logs.Configuration.LogInformation("Data directory set to " + DataDir);

            DBreezeRepository = new DBreezeRepository(Path.Combine(DataDir, "db2"));
            Tracker           = new Tracker(DBreezeRepository, Network);

            // Need to use our own ExternalServices implementations to remove RPC dependency
            Services = ExternalServices.CreateFromFullNode(DBreezeRepository, Tracker, this.tumblingState);
        }
        public FullNodeTumblerClientConfiguration(TumblingState tumblingState, bool onlyMonitor, bool connectionTest = false)
        {
            this.tumblingState = tumblingState ?? throw new ArgumentNullException(nameof(tumblingState));
            Network            = tumblingState.TumblerNetwork ?? throw new ArgumentNullException(nameof(tumblingState.TumblerNetwork));

            if (!onlyMonitor || connectionTest)
            {
                TorPath = "tor";

                Cooperative   = true;
                AllowInsecure = true;

                if (tumblingState.TumblerUri != null)
                {
                    TumblerServer = new TumblerUrlBuilder(this.tumblingState.TumblerUri);
                    if (TumblerServer == null)
                    {
                        throw new ConfigException("Tumbler server is not configured");
                    }
                }

                AliceConnectionSettings = new SocksConnectionSettings()
                {
                    Proxy = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 9050)
                };

                // TODO: Need to check what recommended configuration is to prevent Alice/Bob linkage
                BobConnectionSettings = new SocksConnectionSettings()
                {
                    Proxy = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 9050)
                };

                if (connectionTest)
                {
                    return;
                }
            }

            OnlyMonitor = onlyMonitor;
            Logs.Configuration.LogInformation("Network: " + Network);
            DataDir = Path.Combine(this.tumblingState.NodeSettings.DataDir, "TumbleBit");
            Logs.Configuration.LogInformation("Data directory set to " + DataDir);

            DBreezeRepository = new DBreezeRepository(Path.Combine(DataDir, "db2"));
            Tracker           = new Tracker(DBreezeRepository, Network);

            // Need to use our own ExternalServices implementations to remove RPC dependency
            Services = ExternalServices.CreateFromFullNode(DBreezeRepository, Tracker, this.tumblingState);
        }
        public TumblerConfiguration LoadArgs(String[] args)
        {
            ConfigurationFile = args.Where(a => a.StartsWith("-conf=", StringComparison.Ordinal)).Select(a => a.Substring("-conf=".Length).Replace("\"", "")).FirstOrDefault();
            DataDir           = args.Where(a => a.StartsWith("-datadir=", StringComparison.Ordinal)).Select(a => a.Substring("-datadir=".Length).Replace("\"", "")).FirstOrDefault();
            if (DataDir != null && ConfigurationFile != null)
            {
                var isRelativePath = Path.GetFullPath(ConfigurationFile).Length > ConfigurationFile.Length;
                if (isRelativePath)
                {
                    ConfigurationFile = Path.Combine(DataDir, ConfigurationFile);
                }
            }

            Network = args.Contains("-testnet", StringComparer.OrdinalIgnoreCase) ? Network.TestNet :
                      args.Contains("-regtest", StringComparer.OrdinalIgnoreCase) ? Network.RegTest :
                      Network.Main;

            if (ConfigurationFile != null)
            {
                AssetConfigFileExists();
                var configTemp = TextFileConfiguration.Parse(File.ReadAllText(ConfigurationFile));

                Network = configTemp.GetOrDefault <bool>("testnet", false) ? Network.TestNet :
                          configTemp.GetOrDefault <bool>("regtest", false) ? Network.RegTest :
                          Network.Main;
            }
            if (DataDir == null)
            {
                DataDir = DefaultDataDirectory.GetDefaultDirectory("NTumbleBitServer", Network);
            }

            if (ConfigurationFile == null)
            {
                ConfigurationFile = GetDefaultConfigurationFile(Network);
            }
            Logs.Configuration.LogInformation("Network: " + Network);

            Logs.Configuration.LogInformation("Data directory set to " + DataDir);
            Logs.Configuration.LogInformation("Configuration file set to " + ConfigurationFile);

            if (!Directory.Exists(DataDir))
            {
                throw new ConfigurationException("Data directory does not exists");
            }

            var consoleConfig = new TextFileConfiguration(args);
            var config        = TextFileConfiguration.Parse(File.ReadAllText(ConfigurationFile));

            consoleConfig.MergeInto(config, true);

            if (config.Contains("help"))
            {
                Console.WriteLine("Details on the wiki page :  https://github.com/NTumbleBit/NTumbleBit/wiki/Server-Config");
                OpenBrowser("https://github.com/NTumbleBit/NTumbleBit/wiki/Server-Config");
                Environment.Exit(0);
            }

            var standardCycles = new StandardCycles(Network);
            var cycleName      = "kotori";        //config.GetOrDefault<string>("cycle", standardCycles.Debug ? "shorty2x" : "shorty2x");

            Logs.Configuration.LogInformation($"Using cycle {cycleName}");

            var standardCycle = standardCycles.GetStandardCycle(cycleName);

            if (standardCycle == null)
            {
                throw new ConfigException($"Invalid cycle name, choose among {String.Join(",", standardCycles.ToEnumerable().Select(c => c.FriendlyName).ToArray())}");
            }

            ClassicTumblerParameters.CycleGenerator = standardCycle.Generator;
            ClassicTumblerParameters.Denomination   = standardCycle.Denomination;
            var torEnabled = config.GetOrDefault <bool>("tor.enabled", true);

            if (torEnabled)
            {
                TorSettings = TorConnectionSettings.ParseConnectionSettings("tor", config);
            }

            Cooperative = config.GetOrDefault <bool>("cooperative", true);

            var defaultPort = config.GetOrDefault <int>("port", 37123);

            OnlyMonitor = config.GetOrDefault <bool>("onlymonitor", false);
            string listenAddress = config.GetOrDefault <string>("listen", Utils.GetInternetConnectedAddress().ToString());

            Listen = new IPEndPoint(IPAddress.Parse(listenAddress), defaultPort);

            RPC               = RPCArgs.Parse(config, Network);
            TorPath           = config.GetOrDefault <string>("torpath", "tor");
            DBreezeRepository = new DBreezeRepository(Path.Combine(DataDir, "db2"));
            Tracker           = new Tracker(DBreezeRepository, Network);

            // The worst case scenario is tumbler posting Puzzle which than fails and the tumbler has to get a refund.
            // This it(`T[Puzzle]`) 447B + (`T[Refund]` for (`T[Puzzle]`)) 651B = 1098B
            // Assuming the average transaction fee @ 50 sat / B we get: 1098B * 50 sat / B = 0.00054900 BTC just the network fees
            // For the denomination 0.1 BTC the 1 % fee would be 0.001 BTC
            // Combining the network fees with 1 % fees for 0.1 BTC denomination gives us 0.00054900 BTC + 0.001 BTC = 0.00154900 BTC ≈ 0.00155 BTC
            // The overall tumbler fee will work out to be 1.55 % of the denomination
            var defaultFee = new Money(0.00155m, MoneyUnit.BTC);

            ClassicTumblerParameters.Fee = config.GetOrDefault <Money>("tumbler.fee", defaultFee);

            TumblerProtocol = config.GetOrDefault <TumblerProtocolType>("tumbler.protocol", TumblerProtocolType.Tcp);

            RPCClient rpc = null;

            try
            {
                rpc = RPC.ConfigureRPCClient(Network);
            }
            catch
            {
                throw new ConfigException("Please, fix rpc settings in " + ConfigurationFile);
            }

            Services = ExternalServices.CreateFromRPCClient(rpc, DBreezeRepository, Tracker, true);
            return(this);
        }
Пример #4
0
        public TumblerConfiguration LoadArgs(String[] args)
        {
            ConfigurationFile = args.Where(a => a.StartsWith("-conf=", StringComparison.Ordinal)).Select(a => a.Substring("-conf=".Length).Replace("\"", "")).FirstOrDefault();
            DataDir           = args.Where(a => a.StartsWith("-datadir=", StringComparison.Ordinal)).Select(a => a.Substring("-datadir=".Length).Replace("\"", "")).FirstOrDefault();
            if (DataDir != null && ConfigurationFile != null)
            {
                var isRelativePath = Path.GetFullPath(ConfigurationFile).Length > ConfigurationFile.Length;
                if (isRelativePath)
                {
                    ConfigurationFile = Path.Combine(DataDir, ConfigurationFile);
                }
            }

            Network = args.Contains("-testnet", StringComparer.OrdinalIgnoreCase) ? Network.TestNet :
                      args.Contains("-regtest", StringComparer.OrdinalIgnoreCase) ? Network.RegTest :
                      Network.Main;

            if (ConfigurationFile != null)
            {
                AssetConfigFileExists();
                var configTemp = TextFileConfiguration.Parse(File.ReadAllText(ConfigurationFile));
                Network = configTemp.GetOrDefault <bool>("testnet", false) ? Network.TestNet :
                          configTemp.GetOrDefault <bool>("regtest", false) ? Network.RegTest :
                          Network.Main;
            }
            if (DataDir == null)
            {
                DataDir = DefaultDataDirectory.GetDefaultDirectory("NTumbleBitServer", Network);
            }

            if (ConfigurationFile == null)
            {
                ConfigurationFile = GetDefaultConfigurationFile();
            }
            Logs.Configuration.LogInformation("Network: " + Network);

            Logs.Configuration.LogInformation("Data directory set to " + DataDir);
            Logs.Configuration.LogInformation("Configuration file set to " + ConfigurationFile);

            if (!Directory.Exists(DataDir))
            {
                throw new ConfigurationException("Data directory does not exists");
            }

            var consoleConfig = new TextFileConfiguration(args);
            var config        = TextFileConfiguration.Parse(File.ReadAllText(ConfigurationFile));

            consoleConfig.MergeInto(config, true);

            if (config.Contains("help"))
            {
                Console.WriteLine("Details on the wiki page :  https://github.com/NTumbleBit/NTumbleBit/wiki/Server-Config");
                OpenBrowser("https://github.com/NTumbleBit/NTumbleBit/wiki/Server-Config");
                Environment.Exit(0);
            }

            var standardCycles = new StandardCycles(Network);
            var cycleName      = config.GetOrDefault <string>("cycle", standardCycles.Debug ? "shorty" : "kotori");

            Logs.Configuration.LogInformation($"Using cycle {cycleName}");
            ClassicTumblerParameters.CycleGenerator = standardCycles.GetStandardCycle(cycleName)?.Generator;
            if (ClassicTumblerParameters.CycleGenerator == null)
            {
                throw new ConfigException($"Invalid cycle name, choose among {String.Join(",", standardCycles.ToEnumerable().Select(c => c.FriendlyName).ToArray())}");
            }

            var torEnabled = config.GetOrDefault <bool>("tor.enabled", true);

            if (torEnabled)
            {
                TorSettings = TorConnectionSettings.ParseConnectionSettings("tor", config);
            }

            Cooperative = config.GetOrDefault <bool>("cooperative", true);

            var defaultPort = config.GetOrDefault <int>("port", 37123);

            OnlyMonitor = config.GetOrDefault <bool>("onlymonitor", false);
            Listen      = new IPEndPoint(IPAddress.Parse("127.0.0.1"), defaultPort);

            RPC               = RPCArgs.Parse(config, Network);
            TorPath           = config.GetOrDefault <string>("torpath", "tor");
            DBreezeRepository = new DBreezeRepository(Path.Combine(DataDir, "db2"));
            Tracker           = new Tracker(DBreezeRepository, Network);

            RPCClient rpc = null;

            try
            {
                rpc = RPC.ConfigureRPCClient(Network);
            }
            catch
            {
                throw new ConfigException("Please, fix rpc settings in " + ConfigurationFile);
            }

            Services = ExternalServices.CreateFromRPCClient(rpc, DBreezeRepository, Tracker);
            return(this);
        }
Пример #5
0
        async Task ConfigureAsyncCore(TumblerConfiguration conf, ClientInteraction interaction)
        {
            Cooperative = conf.Cooperative;
            ClassicTumblerParameters = conf.ClassicTumblerParameters.Clone();
            Network       = conf.Network;
            LocalEndpoint = conf.Listen;
            RPCClient rpcClient = null;

            try
            {
                rpcClient = conf.RPC.ConfigureRPCClient(conf.Network);
            }
            catch
            {
                throw new ConfigException("Please, fix rpc settings in " + conf.ConfigurationFile);
            }

            bool torConfigured = false;

            if (conf.TorSettings != null)
            {
                Exception error = null;
                try
                {
                    _Resources.Add(await conf.TorSettings.SetupAsync(interaction, conf.TorPath).ConfigureAwait(false));
                    Logs.Configuration.LogInformation("Successfully authenticated to Tor");
                    var torRSA = Path.Combine(conf.DataDir, "Tor.rsa");


                    TorPrivateKey = null;
                    if (File.Exists(torRSA))
                    {
                        TorPrivateKey = File.ReadAllText(torRSA, Encoding.UTF8);
                    }

                    TorConnection = conf.TorSettings.CreateTorClient2();
                    _Resources.Add(TorConnection);

                    await TorConnection.ConnectAsync().ConfigureAwait(false);

                    await TorConnection.AuthenticateAsync().ConfigureAwait(false);

                    var result = await TorConnection.RegisterHiddenServiceAsync(conf.Listen, conf.TorSettings.VirtualPort, TorPrivateKey).ConfigureAwait(false);

                    if (TorPrivateKey == null)
                    {
                        File.WriteAllText(torRSA, result.PrivateKey, Encoding.UTF8);
                        Logs.Configuration.LogWarning($"Tor RSA private key generated to {torRSA}");
                    }

                    var tumblerUri = new TumblerUrlBuilder
                    {
                        Port = result.HiddenServiceUri.Port,
                        Host = result.HiddenServiceUri.Host
                    };
                    TumblerUris.Add(tumblerUri);
                    TorUri = tumblerUri.GetRoutableUri(false);
                    ClassicTumblerParameters.ExpectedAddress = TorUri.AbsoluteUri;
                    Logs.Configuration.LogInformation($"Tor configured on {result.HiddenServiceUri}");
                    torConfigured = true;
                }
                catch (ConfigException ex)
                {
                    error = ex;
                }
                catch (TorException ex)
                {
                    error = ex;
                }
                catch (ClientInteractionException)
                {
                }
                if (error != null)
                {
                    Logs.Configuration.LogWarning("Error while configuring Tor hidden service: " + error.Message);
                }
            }

            if (!torConfigured)
            {
                Logs.Configuration.LogWarning("The tumbler is not configured as a Tor Hidden service");
            }


            var tumlerKeyData  = LoadRSAKeyData(conf.DataDir, "Tumbler.pem", conf.NoRSAProof);
            var voucherKeyData = LoadRSAKeyData(conf.DataDir, "Voucher.pem", conf.NoRSAProof);

            ClassicTumblerParameters.ServerKey  = tumlerKeyData.Item2;
            ClassicTumblerParameters.VoucherKey = voucherKeyData.Item2;

            TumblerKey = tumlerKeyData.Item1;
            VoucherKey = voucherKeyData.Item1;


            if (!conf.TorMandatory)
            {
                var httpUri = new TumblerUrlBuilder()
                {
                    Host = LocalEndpoint.Address.ToString(),
                    Port = LocalEndpoint.Port,
                };
                TumblerUris.Add(httpUri);
                if (String.IsNullOrEmpty(ClassicTumblerParameters.ExpectedAddress))
                {
                    ClassicTumblerParameters.ExpectedAddress = httpUri.GetRoutableUri(false).AbsoluteUri;
                }
            }
            ClassicTumblerParametersHash = ClassicTumblerParameters.GetHash();
            var configurationHash = ClassicTumblerParameters.GetHash();

            foreach (var uri in TumblerUris)
            {
                uri.ConfigurationHash = configurationHash;
            }

            Logs.Configuration.LogInformation("");
            Logs.Configuration.LogInformation($"--------------------------------");
            Logs.Configuration.LogInformation($"Shareable URIs of the running tumbler are:");
            foreach (var uri in TumblerUris)
            {
                Logs.Configuration.LogInformation(uri.ToString());
            }
            Logs.Configuration.LogInformation($"--------------------------------");
            Logs.Configuration.LogInformation("");

            var dbreeze = new DBreezeRepository(Path.Combine(conf.DataDir, "db2"));

            Repository = dbreeze;
            _Resources.Add(dbreeze);
            Tracker  = new Tracker(dbreeze, Network);
            Services = ExternalServices.CreateFromRPCClient(rpcClient, dbreeze, Tracker, true);
        }
        public TumblerClientConfiguration LoadArgs(String[] args)
        {
            ConfigurationFile = args.Where(a => a.StartsWith("-conf=", StringComparison.Ordinal)).Select(a => a.Substring("-conf=".Length).Replace("\"", "")).FirstOrDefault();
            DataDir           = args.Where(a => a.StartsWith("-datadir=", StringComparison.Ordinal)).Select(a => a.Substring("-datadir=".Length).Replace("\"", "")).FirstOrDefault();
            if (DataDir != null && ConfigurationFile != null)
            {
                var isRelativePath = Path.GetFullPath(ConfigurationFile).Length > ConfigurationFile.Length;
                if (isRelativePath)
                {
                    ConfigurationFile = Path.Combine(DataDir, ConfigurationFile);
                }
            }

            Network = args.Contains("-testnet", StringComparer.OrdinalIgnoreCase) ? Network.TestNet :
                      args.Contains("-regtest", StringComparer.OrdinalIgnoreCase) ? Network.RegTest :
                      null;

            if (ConfigurationFile != null)
            {
                AssetConfigFileExists();
                var configTemp = TextFileConfiguration.Parse(File.ReadAllText(ConfigurationFile));
                Network = Network ?? (configTemp.GetOrDefault <bool>("testnet", false) ? Network.TestNet :
                                      configTemp.GetOrDefault <bool>("regtest", false) ? Network.RegTest : null);
            }
            Network = Network ?? Network.Main;

            if (DataDir == null)
            {
                DataDir = DefaultDataDirectory.GetDefaultDirectory("NTumbleBit", Network);
            }

            if (ConfigurationFile == null)
            {
                ConfigurationFile = GetDefaultConfigurationFile(DataDir, Network);
            }
            Logs.Configuration.LogInformation("Network: " + Network);

            Logs.Configuration.LogInformation("Data directory set to " + DataDir);
            Logs.Configuration.LogInformation("Configuration file set to " + ConfigurationFile);

            if (!Directory.Exists(DataDir))
            {
                throw new ConfigurationException("Data directory does not exists");
            }

            var consoleConfig = new TextFileConfiguration(args);
            var config        = TextFileConfiguration.Parse(File.ReadAllText(ConfigurationFile));

            consoleConfig.MergeInto(config, true);
            config.AddAlias("server", "tumbler.server");

            OnlyMonitor   = config.GetOrDefault <bool>("onlymonitor", false);
            Cooperative   = config.GetOrDefault <bool>("cooperative", true);
            TumblerServer = config.GetOrDefault("tumbler.server", null as TumblerUrlBuilder);
            TorPath       = config.GetOrDefault <string>("torpath", "tor");

            RPCArgs = RPCArgs.Parse(config, Network);

            if (!OnlyMonitor && TumblerServer == null)
            {
                throw new ConfigException("tumbler.server not configured");
            }

            try
            {
                var key = config.GetOrDefault("outputwallet.extpubkey", null as string);
                if (key != null)
                {
                    OutputWallet.RootKey = new BitcoinExtPubKey(key, Network);
                }
            }
            catch
            {
                throw new ConfigException("outputwallet.extpubkey is not configured correctly");
            }

            OutputWallet.KeyPath = new KeyPath("0");
            string keyPathString = config.GetOrDefault("outputwallet.keypath", null as string);

            if (keyPathString != null)
            {
                try
                {
                    OutputWallet.KeyPath = new KeyPath(keyPathString);
                }
                catch
                {
                    throw new ConfigException("outputwallet.keypath is not configured correctly");
                }
            }

            if (OutputWallet.KeyPath.ToString().Contains("'"))
            {
                throw new ConfigException("outputwallet.keypath should not contain any hardened derivation");
            }

            if (OutputWallet.RootKey != null && OutputWallet.RootKey.Network != Network)
            {
                throw new ConfigException("outputwallet.extpubkey is pointing an incorrect network");
            }

            OutputWallet.RPCArgs = RPCArgs.Parse(config, Network, "outputwallet");

            AliceConnectionSettings = ConnectionSettingsBase.ParseConnectionSettings("alice", config);
            BobConnectionSettings   = ConnectionSettingsBase.ParseConnectionSettings("bob", config);

            AllowInsecure = config.GetOrDefault <bool>("allowinsecure", IsTest(Network));

            RPCClient rpc = null;

            try
            {
                rpc = RPCArgs.ConfigureRPCClient(Network);
            }
            catch
            {
                throw new ConfigException("Please, fix rpc settings in " + ConfigurationFile);
            }

            DBreezeRepository = new DBreezeRepository(Path.Combine(DataDir, "db2"));
            Tracker           = new Tracker(DBreezeRepository, Network);
            Services          = ExternalServices.CreateFromRPCClient(rpc, DBreezeRepository, Tracker, true);

            if (OutputWallet.RootKey != null && OutputWallet.KeyPath != null)
            {
                DestinationWallet = new ClientDestinationWallet(OutputWallet.RootKey, OutputWallet.KeyPath, DBreezeRepository, Network);
            }
            else if (OutputWallet.RPCArgs != null)
            {
                try
                {
                    DestinationWallet = new RPCDestinationWallet(OutputWallet.RPCArgs.ConfigureRPCClient(Network));
                }
                catch
                {
                    throw new ConfigException("Please, fix outputwallet rpc settings in " + ConfigurationFile);
                }
            }
            else
            {
                throw new ConfigException("Missing configuration for outputwallet");
            }

            return(this);
        }
Пример #7
0
        public static IWebHostBuilder UseAppConfiguration(this IWebHostBuilder builder, TumblerConfiguration configuration)
        {
            builder.ConfigureServices(services =>
            {
                services.AddSingleton(provider =>
                {
                    var conf = provider.GetRequiredService <TumblerConfiguration>();
                    var repo = provider.GetRequiredService <IRepository>();
                    return(new ClassicTumblerRepository(conf, repo));
                });

                services.AddSingleton <IRepository>(provider =>
                {
                    var conf    = provider.GetRequiredService <TumblerConfiguration>();
                    var dbreeze = new DBreezeRepository(Path.Combine(conf.DataDir, "db"));
                    return(dbreeze);
                });

                services.AddSingleton((provider) =>
                {
                    var conf = provider.GetRequiredService <TumblerConfiguration>();
                    var repo = provider.GetRequiredService <IRepository>();
                    return(ExternalServices.CreateFromRPCClient(conf.RPCClient, repo));
                });
                services.AddSingleton((provider) =>
                {
                    var conf = provider.GetRequiredService <TumblerConfiguration>();
                    return(conf.CreateClassicTumblerParameters());
                });
                services.AddSingleton((provider) =>
                {
                    var conf = configuration ?? new TumblerConfiguration().LoadArgs(new string[0]);

                    var rsaFile = Path.Combine(conf.DataDir, "Tumbler.pem");

                    if (conf.TumblerKey == null)
                    {
                        if (!File.Exists(rsaFile))
                        {
                            Logs.Configuration.LogWarning("RSA private key not found, please backup it. Creating...");
                            conf.TumblerKey = new RsaKey();
                            File.WriteAllBytes(rsaFile, conf.TumblerKey.ToBytes());
                            Logs.Configuration.LogInformation("RSA key saved (" + rsaFile + ")");
                        }
                        else
                        {
                            Logs.Configuration.LogInformation("RSA private key found (" + rsaFile + ")");
                            conf.TumblerKey = new RsaKey(File.ReadAllBytes(rsaFile));
                        }
                    }

                    if (conf.VoucherKey == null)
                    {
                        var voucherFile = Path.Combine(conf.DataDir, "Voucher.pem");
                        if (!File.Exists(voucherFile))
                        {
                            Logs.Configuration.LogWarning("Creation of Voucher Key");
                            conf.VoucherKey = new RsaKey();
                            File.WriteAllBytes(voucherFile, conf.VoucherKey.ToBytes());
                            Logs.Configuration.LogInformation("RSA key saved (" + voucherFile + ")");
                        }
                        else
                        {
                            Logs.Configuration.LogInformation("Voucher key found (" + voucherFile + ")");
                            conf.VoucherKey = new RsaKey(File.ReadAllBytes(voucherFile));
                        }
                    }

                    try
                    {
                        conf.RPCClient = conf.RPCClient ?? conf.RPC.ConfigureRPCClient(conf.Network);
                    }
                    catch
                    {
                        throw new ConfigException("Please, fix rpc settings in " + conf.ConfigurationFile);
                    }
                    return(configuration);
                });
            });

            builder.UseUrls(configuration.GetUrls());

            return(builder);
        }
        public async Task ConfigureAsync(TumblerClientConfiguration configuration, ClientInteraction interaction)
        {
            interaction = interaction ?? new AcceptAllClientInteraction();

            Network       = configuration.Network;
            TumblerServer = configuration.TumblerServer;
            BobSettings   = configuration.BobConnectionSettings;
            AliceSettings = configuration.AliceConnectionSettings;
            AllowInsecure = configuration.AllowInsecure;

            await SetupTorAsync(interaction, configuration.TorPath).ConfigureAwait(false);

            RPCClient rpc = null;

            try
            {
                rpc = configuration.RPCArgs.ConfigureRPCClient(configuration.Network);
            }
            catch
            {
                throw new ConfigException("Please, fix rpc settings in " + configuration.ConfigurationFile);
            }

            var dbreeze = new DBreezeRepository(Path.Combine(configuration.DataDir, "db2"));

            Cooperative = configuration.Cooperative;
            Repository  = dbreeze;
            _Disposables.Add(dbreeze);
            Tracker  = new Tracker(dbreeze, Network);
            Services = ExternalServices.CreateFromRPCClient(rpc, dbreeze, Tracker);

            if (configuration.OutputWallet.RootKey != null && configuration.OutputWallet.KeyPath != null)
            {
                DestinationWallet = new ClientDestinationWallet(configuration.OutputWallet.RootKey, configuration.OutputWallet.KeyPath, dbreeze, configuration.Network);
            }
            else if (configuration.OutputWallet.RPCArgs != null)
            {
                try
                {
                    DestinationWallet = new RPCDestinationWallet(configuration.OutputWallet.RPCArgs.ConfigureRPCClient(Network));
                }
                catch
                {
                    throw new ConfigException("Please, fix outputwallet rpc settings in " + configuration.ConfigurationFile);
                }
            }
            else
            {
                throw new ConfigException("Missing configuration for outputwallet");
            }

            TumblerParameters = dbreeze.Get <ClassicTumbler.ClassicTumblerParameters>("Configuration", configuration.TumblerServer.Uri.AbsoluteUri);

            if (TumblerParameters != null && TumblerParameters.GetHash() != configuration.TumblerServer.ConfigurationHash)
            {
                TumblerParameters = null;
            }

            if (!configuration.OnlyMonitor)
            {
                var client = CreateTumblerClient(0);
                if (TumblerParameters == null)
                {
                    Logs.Configuration.LogInformation("Downloading tumbler information of " + configuration.TumblerServer.Uri.AbsoluteUri);
                    var parameters = Retry(3, () => client.GetTumblerParameters());
                    if (parameters == null)
                    {
                        throw new ConfigException("Unable to download tumbler's parameters");
                    }

                    if (parameters.GetHash() != configuration.TumblerServer.ConfigurationHash)
                    {
                        throw new ConfigException("The tumbler returned an invalid configuration");
                    }

                    var standardCycles = new StandardCycles(configuration.Network);
                    var standardCycle  = standardCycles.GetStandardCycle(parameters);

                    if (standardCycle == null || !parameters.IsStandard())
                    {
                        Logs.Configuration.LogWarning("This tumbler has non standard parameters");
                        if (!AllowInsecure)
                        {
                            throw new ConfigException("This tumbler has non standard parameters");
                        }
                        standardCycle = null;
                    }

                    await interaction.ConfirmParametersAsync(parameters, standardCycle).ConfigureAwait(false);

                    Repository.UpdateOrInsert("Configuration", TumblerServer.Uri.AbsoluteUri, parameters, (o, n) => n);
                    TumblerParameters = parameters;

                    Logs.Configuration.LogInformation("Tumbler parameters saved");
                }

                Logs.Configuration.LogInformation($"Using tumbler {TumblerServer.Uri.AbsoluteUri}");
            }
        }
Пример #9
0
        private static void StartTumbler(string[] args)
        {
            Logs.Configure(new FuncLoggerFactory(i => new ConsoleLogger(i, (a, b) => true, false)));
            CancellationTokenSource broadcasterCancel = new CancellationTokenSource();
            DBreezeRepository       dbreeze           = null;

            try
            {
                var network = args.Contains("-testnet", StringComparer.OrdinalIgnoreCase) ? Network.TestNet :
                              args.Contains("-regtest", StringComparer.OrdinalIgnoreCase) ? Network.RegTest :
                              Network.Main;
                Logs.Configuration.LogInformation("Network: " + network);

                var dataDir     = DefaultDataDirectory.GetDefaultDirectory("NTumbleBit", network);
                var consoleArgs = new TextFileConfiguration(args);
                var configFile  = GetDefaultConfigurationFile(dataDir, network);
                var config      = TextFileConfiguration.Parse(File.ReadAllText(configFile));
                consoleArgs.MergeInto(config, true);
                config.AddAlias("server", "tumbler.server");

                var onlymonitor = config.GetOrDefault <bool>("onlymonitor", false);

                RPCClient rpc = null;
                try
                {
                    rpc = RPCArgs.ConfigureRPCClient(config, network);
                }
                catch
                {
                    throw new ConfigException("Please, fix rpc settings in " + configFile);
                }
                dbreeze = new DBreezeRepository(Path.Combine(dataDir, "db"));

                var services = ExternalServices.CreateFromRPCClient(rpc, dbreeze);

                var broadcaster = new BroadcasterJob(services, Logs.Main);
                broadcaster.Start(broadcasterCancel.Token);
                Logs.Main.LogInformation("BroadcasterJob started");

                if (!onlymonitor)
                {
                    var server = config.GetOrDefault("tumbler.server", null as Uri);
                    if (server == null)
                    {
                        Logs.Main.LogError("tumbler.server not configured");
                        throw new ConfigException();
                    }
                    var client = new TumblerClient(network, server);
                    Logs.Configuration.LogInformation("Downloading tumbler information of " + server.AbsoluteUri);
                    var parameters = Retry(3, () => client.GetTumblerParameters());
                    Logs.Configuration.LogInformation("Tumbler Server Connection successfull");
                    var existingConfig = dbreeze.Get <ClassicTumbler.ClassicTumblerParameters>("Configuration", client.Address.AbsoluteUri);
                    if (existingConfig != null)
                    {
                        if (Serializer.ToString(existingConfig) != Serializer.ToString(parameters))
                        {
                            Logs.Configuration.LogError("The configuration file of the tumbler changed since last connection, it should never happen");
                            throw new ConfigException();
                        }
                    }
                    else
                    {
                        dbreeze.UpdateOrInsert("Configuration", client.Address.AbsoluteUri, parameters, (o, n) => n);
                    }

                    if (parameters.Network != rpc.Network)
                    {
                        throw new ConfigException("The tumbler server run on a different network than the local rpc server");
                    }

                    IDestinationWallet destinationWallet = null;
                    try
                    {
                        destinationWallet = GetDestinationWallet(config, rpc.Network, dbreeze);
                    }
                    catch (Exception ex)
                    {
                        Logs.Main.LogInformation("outputwallet.extpubkey is not configured, trying to use outputwallet.rpc settings.");
                        try
                        {
                            destinationWallet = GetRPCDestinationWallet(config, rpc.Network);
                        }
                        catch { throw ex; }                         //Not a bug, want to throw the other exception
                    }
                    var stateMachine = new StateMachinesExecutor(parameters, client, destinationWallet, services, dbreeze, Logs.Main);
                    stateMachine.Start(broadcasterCancel.Token);
                    Logs.Main.LogInformation("State machines started");
                }
                Logs.Main.LogInformation("Press enter to stop");
                Console.ReadLine();
                broadcasterCancel.Cancel();
            }
            catch (ConfigException ex)
            {
                if (!string.IsNullOrEmpty(ex.Message))
                {
                    Logs.Configuration.LogError(ex.Message);
                }
            }
            catch (Exception ex)
            {
                Logs.Configuration.LogError(ex.Message);
                Logs.Configuration.LogDebug(ex.StackTrace);
            }
            finally
            {
                if (!broadcasterCancel.IsCancellationRequested)
                {
                    broadcasterCancel.Cancel();
                }
                dbreeze?.Dispose();
            }
        }
Пример #10
0
        private static ClientDestinationWallet GetDestinationWallet(TextFileConfiguration config, Network network, DBreezeRepository dbreeze)
        {
            BitcoinExtPubKey pubKey  = null;
            KeyPath          keypath = new KeyPath("0");

            try
            {
                pubKey = new BitcoinExtPubKey(config.GetOrDefault("outputwallet.extpubkey", null as string), network);
            }
            catch
            {
                throw new ConfigException("outputwallet.extpubkey is not configured correctly");
            }

            string keyPathString = config.GetOrDefault("outputwallet.keypath", null as string);

            if (keyPathString != null)
            {
                try
                {
                    keypath = new KeyPath(keyPathString);
                }
                catch
                {
                    throw new ConfigException("outputwallet.keypath is not configured correctly");
                }
            }
            var destinationWallet = new ClientDestinationWallet("", pubKey, keypath, dbreeze);

            return(destinationWallet);
        }
Пример #11
0
        async Task ConfigureAsyncCore(TumblerConfiguration conf, ClientInteraction interaction)
        {
            Cooperative = conf.Cooperative;
            ClassicTumblerParameters = conf.ClassicTumblerParameters.Clone();
            Network       = conf.Network;
            LocalEndpoint = conf.Listen;
            RPCClient rpcClient = null;

            try
            {
                rpcClient = conf.RPC.ConfigureRPCClient(conf.Network);
            }
            catch
            {
                throw new ConfigException("Please, fix rpc settings in " + conf.ConfigurationFile);
            }

            bool torConfigured = false;

            if (conf.TorSettings != null)
            {
                Exception error = null;
                try
                {
                    _Resources.Add(await conf.TorSettings.SetupAsync(interaction, conf.TorPath).ConfigureAwait(false));
                    Logs.Configuration.LogInformation("Successfully authenticated to Tor");
                    var torRSA = Path.Combine(conf.DataDir, "Tor.rsa");


                    string privateKey = null;
                    if (File.Exists(torRSA))
                    {
                        privateKey = File.ReadAllText(torRSA, Encoding.UTF8);
                    }

                    TorConnection = conf.TorSettings.CreateTorClient2();
                    _Resources.Add(TorConnection);

                    await TorConnection.ConnectAsync().ConfigureAwait(false);

                    await TorConnection.AuthenticateAsync().ConfigureAwait(false);

                    var result = await TorConnection.RegisterHiddenServiceAsync(conf.Listen, conf.TorSettings.VirtualPort, privateKey).ConfigureAwait(false);

                    if (privateKey == null)
                    {
                        File.WriteAllText(torRSA, result.PrivateKey, Encoding.UTF8);
                        Logs.Configuration.LogWarning($"Tor RSA private key generated to {torRSA}");
                    }

                    var tumblerUri = new TumblerUrlBuilder();
                    tumblerUri.Port = result.HiddenServiceUri.Port;
                    tumblerUri.Host = result.HiddenServiceUri.Host;
                    TumblerUris.Add(tumblerUri);
                    TorUri = tumblerUri.RoutableUri;
                    Logs.Configuration.LogInformation($"Tor configured on {result.HiddenServiceUri}");
                    torConfigured = true;
                }
                catch (ConfigException ex)
                {
                    error = ex;
                }
                catch (TorException ex)
                {
                    error = ex;
                }
                catch (ClientInteractionException)
                {
                }
                if (error != null)
                {
                    Logs.Configuration.LogWarning("Error while configuring Tor hidden service: " + error.Message);
                }
            }

            if (!torConfigured)
            {
                Logs.Configuration.LogWarning("The tumbler is not configured as a Tor Hidden service");
            }

            var rsaFile = Path.Combine(conf.DataDir, "Tumbler.pem");

            if (!File.Exists(rsaFile))
            {
                Logs.Configuration.LogWarning("RSA private key not found, please backup it. Creating...");
                TumblerKey = new RsaKey();
                File.WriteAllBytes(rsaFile, TumblerKey.ToBytes());
                Logs.Configuration.LogInformation("RSA key saved (" + rsaFile + ")");
            }
            else
            {
                Logs.Configuration.LogInformation("RSA private key found (" + rsaFile + ")");
                TumblerKey = new RsaKey(File.ReadAllBytes(rsaFile));
            }

            var voucherFile = Path.Combine(conf.DataDir, "Voucher.pem");

            if (!File.Exists(voucherFile))
            {
                Logs.Configuration.LogWarning("Creation of Voucher Key");
                VoucherKey = new RsaKey();
                File.WriteAllBytes(voucherFile, VoucherKey.ToBytes());
                Logs.Configuration.LogInformation("RSA key saved (" + voucherFile + ")");
            }
            else
            {
                Logs.Configuration.LogInformation("Voucher key found (" + voucherFile + ")");
                VoucherKey = new RsaKey(File.ReadAllBytes(voucherFile));
            }

            ClassicTumblerParameters.ServerKey  = TumblerKey.PubKey;
            ClassicTumblerParameters.VoucherKey = VoucherKey.PubKey;
            ClassicTumblerParametersHash        = ClassicTumblerParameters.GetHash();

            if (conf.AllowInsecure)
            {
                TumblerUris.Add(new TumblerUrlBuilder()
                {
                    Host = LocalEndpoint.Address.ToString(),
                    Port = LocalEndpoint.Port,
                });
            }

            var configurationHash = ClassicTumblerParameters.GetHash();

            foreach (var uri in TumblerUris)
            {
                uri.ConfigurationHash = configurationHash;
            }

            Logs.Configuration.LogInformation("");
            Logs.Configuration.LogInformation($"--------------------------------");
            Logs.Configuration.LogInformation($"Shareable URIs of the running tumbler are:");
            foreach (var uri in TumblerUris)
            {
                Logs.Configuration.LogInformation(uri.Uri.AbsoluteUri);
            }
            Logs.Configuration.LogInformation($"--------------------------------");
            Logs.Configuration.LogInformation("");

            var dbreeze = new DBreezeRepository(Path.Combine(conf.DataDir, "db2"));

            Repository = dbreeze;
            _Resources.Add(dbreeze);
            Tracker  = new Tracker(dbreeze, Network);
            Services = ExternalServices.CreateFromRPCClient(rpcClient, dbreeze, Tracker);
        }
Пример #12
0
 public DBreezeUtils(string path, Network network)
 {
     _path       = path;
     _repository = new DBreezeRepository(path);
     _network    = network;
 }