예제 #1
0
    private BobClient CreateBobClient(RoundState roundState)
    {
        var arenaRequestHandler = new WabiSabiHttpApiClient(HttpClientFactory.NewHttpClientWithCircuitPerRequest());

        return(new BobClient(
                   roundState.Id,
                   new(
                       roundState.CreateAmountCredentialClient(SecureRandom),
                       roundState.CreateVsizeCredentialClient(SecureRandom),
                       arenaRequestHandler)));
    }
예제 #2
0
    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());
    }