/// <summary> /// Gets mempool hashes, but strips the last x characters of each hash. /// </summary> /// <param name="compactness">1 to 64</param> public async Task <ISet <string> > GetMempoolHashesAsync(int compactness, CancellationToken cancel = default) { using (var response = await TorClient.SendAndRetryAsync(HttpMethod.Get, HttpStatusCode.OK, $"/api/v{Helpers.Constants.BackendMajorVersion}/btc/blockchain/mempool-hashes?compactness={compactness}", cancel: cancel)) { if (response.StatusCode != HttpStatusCode.OK) { await response.ThrowRequestExceptionFromContentAsync(); } using (HttpContent content = response.Content) { var strings = await content.ReadAsJsonAsync <ISet <string> >(); return(strings); } } }
public async Task <IEnumerable <uint256> > GetMempoolHashesAsync(CancellationToken cancel = default) { using var response = await TorClient.SendAndRetryAsync( HttpMethod.Get, HttpStatusCode.OK, $"/api/v{Constants.BackendMajorVersion}/btc/blockchain/mempool-hashes", cancel : cancel); if (response.StatusCode != HttpStatusCode.OK) { await response.ThrowRequestExceptionFromContentAsync(); } using HttpContent content = response.Content; var strings = await content.ReadAsJsonAsync <IEnumerable <string> >(); var ret = strings.Select(x => new uint256(x)); return(ret); }
/// <remarks> /// Throws OperationCancelledException if <paramref name="cancel"/> is set. /// </remarks> public async Task <SynchronizeResponse> GetSynchronizeAsync(uint256 bestKnownBlockHash, int count, EstimateSmartFeeMode?estimateMode = null, CancellationToken cancel = default) { string relativeUri = $"/api/v{Constants.BackendMajorVersion}/btc/batch/synchronize?bestKnownBlockHash={bestKnownBlockHash}&maxNumberOfFilters={count}"; if (estimateMode != null) { relativeUri = $"{relativeUri}&estimateSmartFeeMode={estimateMode}"; } using var response = await TorClient.SendAndRetryAsync(HttpMethod.Get, HttpStatusCode.OK, relativeUri, cancel : cancel); if (response.StatusCode != HttpStatusCode.OK) { await response.ThrowRequestExceptionFromContentAsync(); } using HttpContent content = response.Content; var ret = await content.ReadAsJsonAsync <SynchronizeResponse>(); return(ret); }
/// <returns>null or roundHash</returns> public async Task <string> PostConfirmationAsync() { using (HttpResponseMessage response = await TorClient.SendAsync(HttpMethod.Post, $"/api/v{Helpers.Constants.BackendMajorVersion}/btc/chaumiancoinjoin/confirmation?uniqueId={UniqueId}&roundId={RoundId}")) { if (response.StatusCode == HttpStatusCode.NoContent) { Logger.LogInfo <AliceClient>($"Round ({RoundId}), Alice ({UniqueId}): Confirmed connection."); return(null); } if (response.StatusCode != HttpStatusCode.OK) { await response.ThrowRequestExceptionFromContentAsync(); } string roundHash = await response.Content.ReadAsJsonAsync <string>(); Logger.LogInfo <AliceClient>($"Round ({RoundId}), Alice ({UniqueId}): Confirmed connection. Acquired roundHash: {roundHash}."); return(roundHash); } }
/// <remarks> /// Throws OperationCancelledException if <paramref name="cancel"/> is set. /// </remarks> public async Task <FiltersResponse> GetFiltersAsync(uint256 bestKnownBlockHash, int count, CancellationToken cancel = default) { using var response = await TorClient.SendAndRetryAsync(HttpMethod.Get, HttpStatusCode.OK, $"/api/v{Constants.BackendMajorVersion}/btc/blockchain/filters?bestKnownBlockHash={bestKnownBlockHash}&count={count}", cancel : cancel); if (response.StatusCode == HttpStatusCode.NoContent) { return(null); } if (response.StatusCode != HttpStatusCode.OK) { await response.ThrowRequestExceptionFromContentAsync(); } using HttpContent content = response.Content; var ret = await content.ReadAsJsonAsync <FiltersResponse>(); return(ret); }
/// <returns>If the phase is still in OutputRegistration.</returns> public async Task <bool> PostOutputAsync(long roundId, ActiveOutput activeOutput) { Guard.MinimumAndNotNull(nameof(roundId), roundId, 0); Guard.NotNull(nameof(activeOutput), activeOutput); var request = new OutputRequest { OutputAddress = activeOutput.Address, UnblindedSignature = activeOutput.Signature, Level = activeOutput.MixingLevel }; using var response = await TorClient.SendAsync(HttpMethod.Post, $"/api/v{WasabiClient.ApiVersion}/btc/chaumiancoinjoin/output?roundId={roundId}", request.ToHttpStringContent()).ConfigureAwait(false); if (response.StatusCode == HttpStatusCode.Conflict) { return(false); } else if (response.StatusCode != HttpStatusCode.NoContent) { await response.ThrowRequestExceptionFromContentAsync().ConfigureAwait(false); } return(true); }
public async Task <IDictionary <int, FeeEstimationPair> > GetFeesAsync(params int[] confirmationTargets) { var confirmationTargetsString = string.Join(",", confirmationTargets); using (var response = await TorClient.SendAndRetryAsync(HttpMethod.Get, HttpStatusCode.OK, $"/api/v1/btc/blockchain/fees/{confirmationTargetsString}")) { if (response.StatusCode != HttpStatusCode.OK) { string error = await response.Content.ReadAsJsonAsync <string>(); var errorMessage = error == null ? string.Empty : $"\n{error}"; throw new HttpRequestException($"{response.StatusCode.ToReasonString()}{errorMessage}"); } using (HttpContent content = response.Content) { var ret = await content.ReadAsJsonAsync <IDictionary <int, FeeEstimationPair> >(); return(ret); } } }
public async Task <(Version ClientVersion, int BackendMajorVersion)> GetVersionsAsync(CancellationToken cancel) { using (var response = await TorClient.SendAndRetryAsync(HttpMethod.Get, HttpStatusCode.OK, "/api/software/versions", cancel: cancel)) { if (response.StatusCode == HttpStatusCode.NotFound) { // Meaning this things was not just yet implemented on the running server. return(new Version(0, 7), 1); } if (response.StatusCode != HttpStatusCode.OK) { await response.ThrowRequestExceptionFromContentAsync(); } using (HttpContent content = response.Content) { var resp = await content.ReadAsJsonAsync <VersionsResponse>(); return(Version.Parse(resp.ClientVersion), int.Parse(resp.BackendMajorVersion)); } } }
/// <returns>null or roundHash</returns> public async Task PostUnConfirmationAsync() { using (var cts = new CancellationTokenSource(TimeSpan.FromSeconds(3))) { try { using (HttpResponseMessage response = await TorClient.SendAsync(HttpMethod.Post, $"/api/v{Helpers.Constants.BackendMajorVersion}/btc/chaumiancoinjoin/unconfirmation?uniqueId={UniqueId}&roundId={RoundId}", cancel: cts.Token)) { if (response.StatusCode == HttpStatusCode.BadRequest || response.StatusCode == HttpStatusCode.Gone) // Otherwise maybe some internet connection issue there's. Let's consider that as timed out. { await response.ThrowRequestExceptionFromContentAsync(); } } } catch (TaskCanceledException) // If couldn't do it within 3 seconds then it'll likely time out and take it as unconfirmed. { return; } catch (OperationCanceledException) // If couldn't do it within 3 seconds then it'll likely time out and take it as unconfirmed. { return; } catch (TimeoutException) // If couldn't do it within 3 seconds then it'll likely time out and take it as unconfirmed. { return; } catch (ConnectionException) // If some internet connection issue then it'll likely time out and take it as unconfirmed. { return; } catch (TorSocks5FailureResponseException) // If some Tor connection issue then it'll likely time out and take it as unconfirmed. { return; } } Logger.LogInfo <AliceClient>($"Round ({RoundId}), Alice ({UniqueId}): Unconfirmed connection."); }
/// <returns>null or roundHash</returns> public async Task <string> PostConfirmationAsync() { using (HttpResponseMessage response = await TorClient.SendAsync(HttpMethod.Post, $"/api/v1/btc/chaumiancoinjoin/confirmation?uniqueId={UniqueId}&roundId={RoundId}")) { if (response.StatusCode == HttpStatusCode.NoContent) { Logger.LogInfo <AliceClient>($"Round ({RoundId}), Alice ({UniqueId}): Confirmed connection."); return(null); } if (response.StatusCode == HttpStatusCode.OK) { string roundHash = await response.Content.ReadAsJsonAsync <string>(); Logger.LogInfo <AliceClient>($"Round ({RoundId}), Alice ({UniqueId}): Confirmed connection. Acquired roundHash: {roundHash}."); return(roundHash); } string error = await response.Content.ReadAsJsonAsync <string>(); var errorMessage = error == null ? string.Empty : $"\n{error}"; throw new HttpRequestException($"{response.StatusCode.ToReasonString()}{errorMessage}"); } }
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); } }
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"); } } }