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); }
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); }
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; } }
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); }
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}"); } }
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(); } }
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); }