private BobClient CreateBobClient(RoundState roundState) { var arenaRequestHandler = new WabiSabiHttpApiClient(HttpClientFactory.NewHttpClientWithCircuitPerRequest()); return(new BobClient( roundState.Id, new( roundState.CreateAmountCredentialClient(SecureRandom), roundState.CreateVsizeCredentialClient(SecureRandom), arenaRequestHandler))); }
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()); }