Example #1
0
        public static void Main(string[] args)
        {
            Logs.Configure(new FuncLoggerFactory(i => new ConsoleLogger(i, (a, b) => true, false)));
            var configuration = new TumblerConfiguration();

            configuration.LoadArgs(args);
            try
            {
                IWebHost         host     = null;
                ExternalServices services = null;
                if (!configuration.OnlyMonitor)
                {
                    host = new WebHostBuilder()
                           .UseKestrel()
                           .UseAppConfiguration(configuration)
                           .UseContentRoot(Directory.GetCurrentDirectory())
                           .UseIISIntegration()
                           .UseStartup <Startup>()
                           .Build();
                    services = (ExternalServices)host.Services.GetService(typeof(ExternalServices));
                }
                else
                {
                    services = ExternalServices.CreateFromRPCClient(configuration.RPC.ConfigureRPCClient(configuration.Network), new DBreezeRepository(Path.Combine(configuration.DataDir, "db")));
                }

                CancellationTokenSource cts = new CancellationTokenSource();
                var job = new BroadcasterJob(services, Logs.Main);
                job.Start(cts.Token);
                Logs.Main.LogInformation("BroadcasterJob started");

                if (!configuration.OnlyMonitor)
                {
                    host.Run();
                }
                else
                {
                    Console.ReadLine();
                }
                cts.Cancel();
            }
            catch (ConfigException ex)
            {
                if (!string.IsNullOrEmpty(ex.Message))
                {
                    Logs.Main.LogError(ex.Message);
                }
            }
            catch (Exception exception)
            {
                Logs.Main.LogError("Exception thrown while running the server " + exception.Message);
            }
        }
        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);
        }
Example #3
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);
        }
Example #4
0
        public TumblerServerTester(string directory, bool shouldBeStandard)
        {
            try
            {
                var rootTestData = "TestData";
                directory  = rootTestData + "/" + directory;
                _Directory = directory;
                if (!Directory.Exists(rootTestData))
                {
                    Directory.CreateDirectory(rootTestData);
                }

                if (!TryDelete(directory, false))
                {
                    foreach (var process in Process.GetProcessesByName("bitcoind"))
                    {
                        if (process.MainModule.FileName.Replace("\\", "/").StartsWith(Path.GetFullPath(rootTestData).Replace("\\", "/"), StringComparison.Ordinal))
                        {
                            process.Kill();
                            process.WaitForExit();
                        }
                    }
                    TryDelete(directory, true);
                }

                _NodeBuilder = NodeBuilder.Create(directory);
                _NodeBuilder.ConfigParameters.Add("prematurewitness", "1");
                _NodeBuilder.ConfigParameters.Add("walletprematurewitness", "1");

                _TumblerNode = _NodeBuilder.CreateNode(false);
                _AliceNode   = _NodeBuilder.CreateNode(false);
                _BobNode     = _NodeBuilder.CreateNode(false);

                Directory.CreateDirectory(directory);

                _NodeBuilder.StartAll();

                //Activate segwit
                SyncNodes();
                _TumblerNode.Generate(440);
                _TumblerNode.CreateRPCClient().SendToAddress(_AliceNode.CreateRPCClient().GetNewAddress(), Money.Coins(100m));
                _TumblerNode.Generate(1);
                SyncNodes();

                var conf = new TumblerConfiguration();
                conf.DataDir = Path.Combine(directory, "server");
                Directory.CreateDirectory(conf.DataDir);
                File.WriteAllBytes(Path.Combine(conf.DataDir, "Tumbler.pem"), TestKeys.Default.ToBytes());
                File.WriteAllBytes(Path.Combine(conf.DataDir, "Voucher.pem"), TestKeys.Default2.ToBytes());

                conf.RPC.Url = TumblerNode.CreateRPCClient().Address;
                var creds = ExtractCredentials(File.ReadAllText(_TumblerNode.Config));
                conf.RPC.User          = creds.Item1;
                conf.RPC.Password      = creds.Item2;
                conf.TorMandatory      = false;
                conf.Network           = Network.RegTest;
                conf.Listen            = new System.Net.IPEndPoint(IPAddress.Parse("127.0.0.1"), 5000);
                conf.AllowInsecure     = !shouldBeStandard;
                conf.DBreezeRepository = new DBreezeRepository(Path.Combine(conf.DataDir, "db2"));
                conf.Tracker           = new Tracker(conf.DBreezeRepository, conf.Network);

                conf.NoRSAProof = !shouldBeStandard;
                if (!shouldBeStandard)
                {
                    conf.ClassicTumblerParameters.FakePuzzleCount                 = 10;
                    conf.ClassicTumblerParameters.FakeTransactionCount            = 10;
                    conf.ClassicTumblerParameters.RealTransactionCount            = 10;
                    conf.ClassicTumblerParameters.RealPuzzleCount                 = 2;
                    conf.ClassicTumblerParameters.CycleGenerator.FirstCycle.Start = 105;
                }
                else
                {
                    var standard = new StandardCycles(conf.Network).Shorty2x;
                    conf.ClassicTumblerParameters.CycleGenerator = standard.Generator;
                    conf.ClassicTumblerParameters.Denomination   = standard.Denomination;
                }

                RPCClient rpc = conf.RPC.ConfigureRPCClient(conf.Network);
                conf.Services = ExternalServices.CreateFromRPCClient(rpc, conf.DBreezeRepository, conf.Tracker, true);

                var runtime = TumblerRuntime.FromConfiguration(conf, new AcceptAllClientInteraction());
                _Host = new WebHostBuilder()
                        .UseAppConfiguration(runtime)
                        .UseContentRoot(Path.GetFullPath(directory))
                        .UseStartup <Startup>()
                        .Build();

                _Host.Start();
                ServerRuntime = runtime;

                //Overrides server fee
                ((RPCFeeService)runtime.Services.FeeService).FallBackFeeRate     = new FeeRate(Money.Satoshis(100), 1);
                ((RPCWalletService)runtime.Services.WalletService).BatchInterval = TimeSpan.FromMilliseconds(10);
                ((RPCWalletService)runtime.Services.WalletService).AddressGenerationBatchInterval = TimeSpan.FromMilliseconds(10);
                ((RPCBroadcastService)runtime.Services.BroadcastService).BatchInterval            = TimeSpan.FromMilliseconds(10);
                ((RPCBlockExplorerService)runtime.Services.BlockExplorerService).BatchInterval    = TimeSpan.FromMilliseconds(10);


                var clientConfig = new TumblerClientConfiguration();
                clientConfig.DataDir       = Path.Combine(directory, "client");
                clientConfig.AllowInsecure = !shouldBeStandard;
                Directory.CreateDirectory(clientConfig.DataDir);
                clientConfig.Network              = conf.Network;
                clientConfig.CheckIp              = false;
                clientConfig.TorMandatory         = false;
                clientConfig.OutputWallet.KeyPath = new KeyPath("0");
                clientConfig.OutputWallet.RootKey = new ExtKey().Neuter().GetWif(conf.Network);
                clientConfig.RPCArgs.Url          = AliceNode.CreateRPCClient().Address;
                creds = ExtractCredentials(File.ReadAllText(AliceNode.Config));
                clientConfig.RPCArgs.User      = creds.Item1;
                clientConfig.RPCArgs.Password  = creds.Item2;
                clientConfig.DBreezeRepository = new DBreezeRepository(Path.Combine(clientConfig.DataDir, "db2"));
                clientConfig.Tracker           = new Tracker(clientConfig.DBreezeRepository, clientConfig.Network);
                clientConfig.TumblerServer     = runtime.TumblerUris.First();

                RPCClient rpcClient = clientConfig.RPCArgs.ConfigureRPCClient(clientConfig.Network);
                clientConfig.Services          = ExternalServices.CreateFromRPCClient(rpcClient, clientConfig.DBreezeRepository, clientConfig.Tracker, false);
                clientConfig.DestinationWallet = new ClientDestinationWallet(clientConfig.OutputWallet.RootKey, clientConfig.OutputWallet.KeyPath, clientConfig.DBreezeRepository, clientConfig.Network);
                ClientRuntime = TumblerClientRuntime.FromConfiguration(clientConfig, new AcceptAllClientInteraction());

                //Overrides client fee
                ((RPCFeeService)ClientRuntime.Services.FeeService).FallBackFeeRate = new FeeRate(Money.Satoshis(50), 1);
            }
            catch { Dispose(); throw; }
        }
Example #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);
        }
Example #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}");
            }
        }
Example #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();
            }
        }
Example #10
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);
        }