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 TumblerClient(Network network, TumblerUrlBuilder serverAddress, int cycleId) { if (serverAddress == null) { throw new ArgumentNullException(nameof(serverAddress)); } if (network == null) { throw new ArgumentNullException(nameof(network)); } _Address = serverAddress; _Network = network; this.cycleId = cycleId; }
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); }
async Task ConfigureAsyncCore(TumblerConfiguration conf, ClientInteraction interaction) { Cooperative = conf.Cooperative; ClassicTumblerParameters = conf.ClassicTumblerParameters.Clone(); Network = conf.Network; LocalEndpoint = conf.Listen; TumblerProtocol = conf.TumblerProtocol; 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 { Host = result.HiddenServiceUri.Host, Port = result.HiddenServiceUri.Port }; 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) { // Construct a valid 16 character long onion address which will be used as a reference (it is not meant to be a valid IP address or hostname) string dummyOnionAddress = Environment.MachineName; if (dummyOnionAddress.Length < 16) { dummyOnionAddress = dummyOnionAddress.PadRight(16, '-'); } TumblerUrlBuilder httpUri; //Set the Tor URI only if the Tor address has not been already set if (TorUri == null) { //Add onion style address, this is just a display address used when running MasterNode without Tor httpUri = new TumblerUrlBuilder() { Host = $"{dummyOnionAddress}.dummy", Port = conf.Listen.Port }; TumblerUris.Add(httpUri); TorUri = httpUri.GetRoutableUri(false); //Add IP address of the network card with Internet connection httpUri = new TumblerUrlBuilder() { Host = LocalEndpoint.Address.ToString(), Port = LocalEndpoint.Port }; TumblerUris.Add(httpUri); if (String.IsNullOrEmpty(ClassicTumblerParameters.ExpectedAddress)) { ClassicTumblerParameters.ExpectedAddress = httpUri.GetRoutableUri(false).AbsoluteUri; } } else { if (String.IsNullOrEmpty(ClassicTumblerParameters.ExpectedAddress)) { ClassicTumblerParameters.ExpectedAddress = TorUri.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(""); Repository = conf.DBreezeRepository; _Resources.Add(Repository); Tracker = conf.Tracker; Services = conf.Services; }
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); }
static void Main(string[] args) { // args[0] = server CTB URL // args[1] = cycle number (not too important) // args[2] = cookie file path for Tor // args[3] & args[4] = -noTor and/or -tumblerProtocol=http |-tumblerProtocol=tcp var useTor = !args.Contains("-noTor"); TumblerProtocolType?tumblerProtocol = null; try { string tumblerProtocolString = args.Where(a => a.StartsWith("-tumblerProtocol=")).Select(a => a.Substring("-tumblerProtocol=".Length).Replace("\"", "")).FirstOrDefault(); if (tumblerProtocolString != null) { tumblerProtocol = Enum.Parse <TumblerProtocolType>(tumblerProtocolString, true); } if (useTor && tumblerProtocol.HasValue && tumblerProtocol.Value == TumblerProtocolType.Http) { Console.WriteLine("TumblerProtocol can only be changed to Http when Tor is disabled. Please use -NoTor switch to disable Tor."); return; } } catch { Console.WriteLine($"Incorrect tumbling prococol specified; the valid values are {TumblerProtocolType.Tcp} and {TumblerProtocolType.Http}"); return; } var serverAddress = new TumblerUrlBuilder(args[0]); var cycle = int.Parse(args[1]); var client = new TumblerClient(Network.Main, serverAddress, cycle); var cookieFile = new FileInfo(args[2]); IPEndPoint endpoint; var settings = new SocksConnectionSettings(); if (useTor) { using (var tor = new TorClient("127.0.0.1", 9051, cookieFile)) { try { tor.ConnectAsync().GetAwaiter().GetResult(); } catch { Console.WriteLine("Error in connect"); } if (!tor.AuthenticateAsync().GetAwaiter().GetResult()) { Console.WriteLine("Error in authenticate"); } var endpoints = tor.GetSocksListenersAsync().GetAwaiter().GetResult(); endpoint = endpoints.FirstOrDefault(); if (endpoint == null) { throw new TorException("Tor has no socks listener", ""); } } settings.Proxy = endpoint; } var handler = settings.CreateHttpHandler(tumblerProtocol ?? TumblerProtocolType.Tcp); if (handler != null) { client.SetHttpHandler(handler); } else { Console.WriteLine("Handler is null"); } Console.WriteLine(DateTime.Now + " Obtaining MasterNode parameters"); try { var parameters = client.GetTumblerParameters(); Console.WriteLine("Core settings"); Console.WriteLine($"Network: {parameters.Network}"); Console.WriteLine($"ExpectedAddress: {parameters.ExpectedAddress}"); Console.WriteLine($"Denomination: {parameters.Denomination}"); Console.WriteLine($"Fee: {parameters.Fee}"); Console.WriteLine(); Console.WriteLine("Standard Server Check"); Console.WriteLine($" - IsStandard (MasterNode value =? ExpectedValue): {parameters.IsStandard()}"); Console.WriteLine($" - Version ({parameters.Version} =? {ClassicTumblerParameters.LAST_VERSION}): {parameters.Version == ClassicTumblerParameters.LAST_VERSION}"); Console.WriteLine($" - VoucherKey: {parameters.VoucherKey.CheckKey()}"); Console.WriteLine($" - ServerKey: {parameters.ServerKey.CheckKey()}"); Console.WriteLine($" - FakePuzzleCount ({parameters.FakePuzzleCount} =? {285}): {parameters.FakePuzzleCount == 285}"); Console.WriteLine($" - RealPuzzleCount ({parameters.RealPuzzleCount} =? {15}): {parameters.RealPuzzleCount == 15}"); Console.WriteLine($" - RealTransactionCount ({parameters.RealTransactionCount} =? {42}): {parameters.RealTransactionCount == 42}"); Console.WriteLine($" - FakeTransactionCount ({parameters.FakeTransactionCount} =? {42}): {parameters.FakeTransactionCount == 42}"); Console.WriteLine($" - Denomination ({parameters.Denomination} =? {new Money(0.1m, MoneyUnit.BTC)}): {parameters.Denomination == new Money(0.1m, MoneyUnit.BTC)}"); Console.WriteLine($" - Fee ({parameters.Fee} =? {new Money(0.00155m, MoneyUnit.BTC)}): {parameters.Fee == new Money(0.00155m, MoneyUnit.BTC)}"); Console.WriteLine($" - FakeFormat ({parameters.FakeFormat} =? {new uint256(Enumerable.Range(0, 32).Select(o => o == 0 ? (byte)0 : (byte)1).ToArray())}): {parameters.FakeFormat == new uint256(Enumerable.Range(0, 32).Select(o => o == 0 ? (byte)0 : (byte)1).ToArray())}"); Console.WriteLine(); Console.WriteLine($"Cycles"); Console.WriteLine($" - CycleGenerator: {parameters.CycleGenerator.FirstCycle.ToString()}"); Console.WriteLine($" - RegistrationOverlap: {parameters.CycleGenerator.RegistrationOverlap}"); Console.WriteLine(); Console.WriteLine("Cryptography"); Console.WriteLine($" - FakeFormat: {parameters.FakeFormat}"); Console.WriteLine($" - FakeTransactionCount: {parameters.FakeTransactionCount}"); Console.WriteLine($" - RealPuzzleCount: {parameters.RealPuzzleCount}"); Console.WriteLine($" - FakePuzzleCount: {parameters.FakePuzzleCount}"); Console.WriteLine($" - RealTransactionCount: {parameters.RealTransactionCount}"); Console.WriteLine($" - Version: {parameters.Version}"); Console.WriteLine($" - FakeFormat: {parameters.Version}"); Console.WriteLine(); } catch (Exception ex) { } Console.WriteLine(); Console.WriteLine(DateTime.Now + " Starting tor connectivity test..."); while (true) { Stopwatch stopwatch = Stopwatch.StartNew(); try { var parameters = client.GetTumblerParameters(); stopwatch.Stop(); Console.WriteLine(DateTime.Now + " Received parameter response in " + stopwatch.ElapsedMilliseconds + "ms"); } catch { stopwatch.Stop(); Console.WriteLine(DateTime.Now + " Timed out after " + stopwatch.ElapsedMilliseconds + "ms"); } Thread.Sleep(1000); } }
async Task ConfigureAsyncCore(TumblerConfiguration conf, ClientInteraction interaction) { Cooperative = conf.Cooperative; ClassicTumblerParameters = conf.ClassicTumblerParameters.Clone(); Network = conf.Network; LocalEndpoint = conf.Listen; 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.ToString()); } Logs.Configuration.LogInformation($"--------------------------------"); Logs.Configuration.LogInformation(""); Repository = conf.DBreezeRepository; _Resources.Add(Repository); Tracker = conf.Tracker; Services = conf.Services; }
static void Main(string[] args) { // args[0] = server CTB URL // args[1] = cycle number (not too important) // args[2] = cookie file path for Tor var serverAddress = new TumblerUrlBuilder(args[0]); var cycle = int.Parse(args[1]); var client = new TumblerClient(Network.Main, serverAddress, cycle); var cookieFile = new FileInfo(args[2]); IPEndPoint endpoint; using (var tor = new TorClient("127.0.0.1", 9051, cookieFile)) { try { tor.ConnectAsync().GetAwaiter().GetResult(); } catch { Console.WriteLine("Error in connect"); } if (!tor.AuthenticateAsync().GetAwaiter().GetResult()) { Console.WriteLine("Error in authenticate"); } var endpoints = tor.GetSocksListenersAsync().GetAwaiter().GetResult(); endpoint = endpoints.FirstOrDefault(); if (endpoint == null) { throw new TorException("Tor has no socks listener", ""); } } var settings = new SocksConnectionSettings(); settings.Proxy = endpoint; var handler = settings.CreateHttpHandler(TumblerProtocolType.Tcp); if (handler != null) { client.SetHttpHandler(handler); } else { Console.WriteLine("Handler is null"); } Console.WriteLine(DateTime.Now + " Starting tor connectivity test..."); while (true) { Stopwatch stopwatch = Stopwatch.StartNew(); try { var parameters = client.GetTumblerParameters(); stopwatch.Stop(); Console.WriteLine(DateTime.Now + " Received parameter response in " + stopwatch.ElapsedMilliseconds + "ms"); } catch { stopwatch.Stop(); Console.WriteLine(DateTime.Now + " Timed out after " + stopwatch.ElapsedMilliseconds + "ms"); } } }