Example #1
0
 public async Task <InputRegistrationResponse> RegisterInputAsync(InputRegistrationRequest request, CancellationToken cancellationToken)
 {
     try
     {
         return(await RegisterInputCoreAsync(request, cancellationToken).ConfigureAwait(false));
     }
     catch (Exception ex) when(IsUserCheating(ex))
     {
         Prison.Ban(request.Input, request.RoundId);
         throw;
     }
 }
Example #2
0
    public async Task <ConnectionConfirmationResponse> ConfirmConnectionAsync(ConnectionConfirmationRequest request, CancellationToken cancellationToken)
    {
        try
        {
            return(await ConfirmConnectionCoreAsync(request, cancellationToken).ConfigureAwait(false));
        }
        catch (Exception ex) when(IsUserCheating(ex))
        {
            var round = GetRound(request.RoundId);
            var alice = GetAlice(request.AliceId, round);

            Prison.Ban(alice.Coin.Outpoint, round.Id);
            throw;
        }
    }
Example #3
0
        public async Task <ConnectionConfirmationResponse> ConfirmConnectionAsync(ConnectionConfirmationRequest request, CancellationToken cancellationToken)
        {
            Round round;
            Alice alice;
            var   realAmountCredentialRequests = request.RealAmountCredentialRequests;
            var   realVsizeCredentialRequests  = request.RealVsizeCredentialRequests;

            using (await AsyncLock.LockAsync(cancellationToken).ConfigureAwait(false))
            {
                round = GetRound(request.RoundId, Phase.InputRegistration, Phase.ConnectionConfirmation);

                alice = GetAlice(request.AliceId, round);

                if (alice.ConfirmedConnection)
                {
                    Prison.Ban(alice, round.Id);
                    throw new WabiSabiProtocolException(WabiSabiProtocolErrorCode.AliceAlreadyConfirmedConnection, $"Round ({request.RoundId}): Alice ({request.AliceId}) already confirmed connection.");
                }

                if (realVsizeCredentialRequests.Delta != alice.CalculateRemainingVsizeCredentials(round.MaxVsizeAllocationPerAlice))
                {
                    throw new WabiSabiProtocolException(WabiSabiProtocolErrorCode.IncorrectRequestedVsizeCredentials, $"Round ({request.RoundId}): Incorrect requested vsize credentials.");
                }
                if (realAmountCredentialRequests.Delta != alice.CalculateRemainingAmountCredentials(round.FeeRate))
                {
                    throw new WabiSabiProtocolException(WabiSabiProtocolErrorCode.IncorrectRequestedAmountCredentials, $"Round ({request.RoundId}): Incorrect requested amount credentials.");
                }
            }

            var amountZeroCredentialTask = round.AmountCredentialIssuer.HandleRequestAsync(request.ZeroAmountCredentialRequests, cancellationToken);
            var vsizeZeroCredentialTask  = round.VsizeCredentialIssuer.HandleRequestAsync(request.ZeroVsizeCredentialRequests, cancellationToken);
            Task <CredentialsResponse>?amountRealCredentialTask = null;
            Task <CredentialsResponse>?vsizeRealCredentialTask  = null;

            if (round.Phase is Phase.ConnectionConfirmation)
            {
                amountRealCredentialTask = round.AmountCredentialIssuer.HandleRequestAsync(realAmountCredentialRequests, cancellationToken);
                vsizeRealCredentialTask  = round.VsizeCredentialIssuer.HandleRequestAsync(realVsizeCredentialRequests, cancellationToken);
            }

            using (await AsyncLock.LockAsync(cancellationToken).ConfigureAwait(false))
            {
                alice = GetAlice(request.AliceId, round);

                switch (round.Phase)
                {
                case Phase.InputRegistration:
                {
                    var commitAmountZeroCredentialResponse = await amountZeroCredentialTask.ConfigureAwait(false);

                    var commitVsizeZeroCredentialResponse = await vsizeZeroCredentialTask.ConfigureAwait(false);

                    alice.SetDeadlineRelativeTo(round.ConnectionConfirmationTimeFrame.Duration);
                    return(new(
                               commitAmountZeroCredentialResponse,
                               commitVsizeZeroCredentialResponse));
                }

                case Phase.ConnectionConfirmation:
                {
                    // If the phase was InputRegistration before then we did not pre-calculate real credentials.
                    amountRealCredentialTask ??= round.AmountCredentialIssuer.HandleRequestAsync(realAmountCredentialRequests, cancellationToken);
                    vsizeRealCredentialTask ??= round.VsizeCredentialIssuer.HandleRequestAsync(realVsizeCredentialRequests, cancellationToken);

                    ConnectionConfirmationResponse response = new(
                        await amountZeroCredentialTask.ConfigureAwait(false),
                        await vsizeZeroCredentialTask.ConfigureAwait(false),
                        await amountRealCredentialTask.ConfigureAwait(false),
                        await vsizeRealCredentialTask.ConfigureAwait(false));

                    // Update the CoinJoin state, adding the confirmed input.
                    round.CoinjoinState       = round.Assert <ConstructionState>().AddInput(alice.Coin);
                    alice.ConfirmedConnection = true;

                    return(response);
                }

                default:
                    throw new WabiSabiProtocolException(WabiSabiProtocolErrorCode.WrongPhase, $"Round ({request.RoundId}): Wrong phase ({round.Phase}).");
                }
            }
        }