public async Task StartParticipatingAsync(CancellationToken cancellationToken) { ThrowIfDisposed(); var apiClient = new WabiSabiHttpApiClient(HttpClientFactory.NewHttpClientWithDefaultCircuit()); using var roundStateUpdater = new RoundStateUpdater(TimeSpan.FromSeconds(3), apiClient); await roundStateUpdater.StartAsync(cancellationToken).ConfigureAwait(false); var coinJoinClient = new CoinJoinClient( HttpClientFactory, Wallet, Wallet, roundStateUpdater, consolidationMode: true); // Run the coinjoin client task. var walletHdPubKey = new HdPubKey(Wallet.PubKey, KeyPath.Parse("m/84'/0/0/0/0"), SmartLabel.Empty, KeyState.Clean); walletHdPubKey.SetAnonymitySet(1); // bug if not settled if (SplitTransaction is null) { throw new InvalidOperationException($"{nameof(GenerateCoinsAsync)} has to be called first."); } var smartCoins = SplitTransaction.Transaction.Outputs.AsIndexedOutputs() .Select(x => new SmartCoin(SplitTransaction, x.N, walletHdPubKey)) .ToList(); // Run the coinjoin client task. await coinJoinClient.StartCoinJoinAsync(smartCoins, cancellationToken).ConfigureAwait(false); await roundStateUpdater.StopAsync(cancellationToken).ConfigureAwait(false); }
public Participant(IRPCClient rpc, WabiSabiHttpApiClient apiClient) { Rpc = rpc; ApiClient = apiClient; KeyManager = KeyManager.CreateNew(out var _, password: ""); KeyManager.AssertCleanKeysIndexed(); }
private BobClient CreateBobClient(RoundState roundState) { var arenaRequestHandler = new WabiSabiHttpApiClient(HttpClientFactory.NewHttpClientWithCircuitPerRequest()); return(new BobClient( roundState.Id, new( roundState.CreateAmountCredentialClient(SecureRandom), roundState.CreateVsizeCredentialClient(SecureRandom), arenaRequestHandler))); }
public async Task <ArenaClient> CreateArenaClientAsync(WabiSabiHttpApiClient wabiSabiHttpApiClient) { var rounds = (await wabiSabiHttpApiClient.GetStatusAsync(RoundStateRequest.Empty, CancellationToken.None)).RoundStates; var round = rounds.First(x => x.CoinjoinState is ConstructionState); var insecureRandom = new InsecureRandom(); var arenaClient = new ArenaClient( round.CreateAmountCredentialClient(insecureRandom), round.CreateVsizeCredentialClient(insecureRandom), wabiSabiHttpApiClient); return(arenaClient); }
public async Task StartParticipatingAsync(CancellationToken cancellationToken) { if (SplitTransaction is null) { throw new InvalidOperationException($"{nameof(GenerateCoinsAsync)} has to be called first."); } var apiClient = new WabiSabiHttpApiClient(HttpClientFactory.NewHttpClientWithDefaultCircuit()); using var roundStateUpdater = new RoundStateUpdater(TimeSpan.FromSeconds(3), apiClient); await roundStateUpdater.StartAsync(cancellationToken).ConfigureAwait(false); var coinJoinClient = WabiSabiFactory.CreateTestCoinJoinClient(HttpClientFactory, Wallet, Wallet, roundStateUpdater);
private async Task <ImmutableArray <(AliceClient AliceClient, PersonCircuit PersonCircuit)> > CreateRegisterAndConfirmCoinsAsync(IEnumerable <SmartCoin> smartCoins, RoundState roundState, CancellationToken cancellationToken) { int eventInvokedAlready = 0; async Task <(AliceClient?AliceClient, PersonCircuit?PersonCircuit)> RegisterInputAsync(SmartCoin coin, CancellationToken cancellationToken) { PersonCircuit?personCircuit = null; try { personCircuit = HttpClientFactory.NewHttpClientWithPersonCircuit(out Tor.Http.IHttpClient httpClient); // Alice client requests are inherently linkable to each other, so the circuit can be reused var arenaRequestHandler = new WabiSabiHttpApiClient(httpClient); var aliceArenaClient = new ArenaClient( roundState.CreateAmountCredentialClient(SecureRandom), roundState.CreateVsizeCredentialClient(SecureRandom), arenaRequestHandler); var aliceClient = await AliceClient.CreateRegisterAndConfirmInputAsync(roundState, aliceArenaClient, coin, KeyChain, RoundStatusUpdater, cancellationToken).ConfigureAwait(false); // Right after the first real-cred confirmation happened we entered into critical phase. if (Interlocked.Exchange(ref eventInvokedAlready, 1) == 0) { CoinJoinClientProgress.SafeInvoke(this, new EnteringCriticalPhase()); } return(aliceClient, personCircuit); } catch (WabiSabiProtocolException) { personCircuit?.Dispose(); return(null, null); } catch (Exception) { personCircuit?.Dispose(); throw; } } // Gets the list of scheduled dates/time in the remaining available time frame when each alice has to be registered. var remainingTimeForRegistration = roundState.InputRegistrationEnd - DateTimeOffset.UtcNow; roundState.LogDebug($"Inputs({smartCoins.Count()}) registration started - it will end in: {remainingTimeForRegistration:hh\\:mm\\:ss}."); var scheduledDates = GetScheduledDates(smartCoins.Count(), roundState.InputRegistrationEnd); // Creates scheduled tasks (tasks that wait until the specified date/time and then perform the real registration) var aliceClients = smartCoins.Zip( scheduledDates, async(coin, date) => { var delay = date - DateTimeOffset.UtcNow; if (delay > TimeSpan.Zero) { await Task.Delay(delay, cancellationToken).ConfigureAwait(false); } return(await RegisterInputAsync(coin, cancellationToken).ConfigureAwait(false)); }) .ToImmutableArray(); await Task.WhenAll(aliceClients).ConfigureAwait(false); return(aliceClients .Select(x => x.Result) .Where(r => r.AliceClient is not null && r.PersonCircuit is not null) .Select(r => (r.AliceClient !, r.PersonCircuit !)) .ToImmutableArray()); }