public static ImmutableList <TimeSpan> SamplePoissonDelays(this TimeSpan timeFrame, int numberOfEvents)
    {
        using var random = new SecureRandom();
        TimeSpan Sample(int milliseconds) =>
        milliseconds <= 0 ? TimeSpan.Zero : TimeSpan.FromMilliseconds(random.GetInt(0, milliseconds));

        return(Enumerable
               .Range(0, numberOfEvents)
               .Select(_ => 0.8 * Sample((int)timeFrame.TotalMilliseconds))
               .OrderBy(t => t)
               .ToImmutableList());
    }
Beispiel #2
0
    public static ImmutableList <DateTimeOffset> SamplePoisson(this TimeSpan timeFrame, int numberOfEvents)
    {
        var startTime = DateTimeOffset.UtcNow;

        using var random = new SecureRandom();
        TimeSpan Sample(int milliseconds) =>
        milliseconds <= 0 ? TimeSpan.Zero : TimeSpan.FromMilliseconds(random.GetInt(0, milliseconds));

        return(Enumerable
               .Range(0, numberOfEvents)
               .Select(_ => startTime + (0.8 * Sample((int)timeFrame.TotalMilliseconds)))
               .OrderBy(t => t)
               .ToImmutableList());
    }
Beispiel #3
0
    ProceedWithSigningStateAsync(uint256 roundId, ImmutableArray <AliceClient> registeredAliceClients, IEnumerable <TxOut> outputTxOuts, CancellationToken cancellationToken)
    {
        // Signing.
        var roundState = await RoundStatusUpdater.CreateRoundAwaiter(roundId, Phase.TransactionSigning, cancellationToken).ConfigureAwait(false);

        var remainingTime       = roundState.CoinjoinState.Parameters.TransactionSigningTimeout - RoundStatusUpdater.Period;
        var signingStateEndTime = DateTimeOffset.UtcNow + remainingTime;

        CoinJoinClientProgress.SafeInvoke(this, new EnteringSigningPhase(roundState, signingStateEndTime));

        using CancellationTokenSource phaseTimeoutCts = new(remainingTime + ExtraPhaseTimeoutMargin);
        using CancellationTokenSource linkedCts       = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, phaseTimeoutCts.Token);

        roundState.LogDebug($"Transaction signing phase started - it will end in: {signingStateEndTime - DateTimeOffset.UtcNow:hh\\:mm\\:ss}.");

        var signingState     = roundState.Assert <SigningState>();
        var unsignedCoinJoin = signingState.CreateUnsignedTransaction();

        // If everything is okay, then sign all the inputs. Otherwise, in case there are missing outputs, the server is
        // lying (it lied us before when it responded with 200 OK to the OutputRegistration requests or it is lying us
        // now when we identify as satoshi.
        // In this scenario we should ban the coordinator and stop dealing with it.
        // see more: https://github.com/zkSNACKs/WalletWasabi/issues/8171
        bool mustSignAllInputs = SanityCheck(outputTxOuts, unsignedCoinJoin);

        if (!mustSignAllInputs)
        {
            roundState.LogInfo($"There are missing outputs. A subset of inputs will be signed.");
        }

        // Send signature.
        var combinedToken = linkedCts.Token;
        var alicesToSign  = mustSignAllInputs
                        ? registeredAliceClients
                        : registeredAliceClients.RemoveAt(SecureRandom.GetInt(0, registeredAliceClients.Length));

        await SignTransactionAsync(alicesToSign, unsignedCoinJoin, signingStateEndTime, combinedToken).ConfigureAwait(false);

        roundState.LogDebug($"{alicesToSign.Length} out of {registeredAliceClients.Length} Alices have signed the coinjoin tx.");

        return(unsignedCoinJoin, alicesToSign);
    }