示例#1
0
        public async Task <Coin> OutpointToCoinAsync(InputRegistrationRequest request, CancellationToken cancellationToken)
        {
            OutPoint input = request.Input;

            if (Prison.TryGet(input, out var inmate) && (!Config.AllowNotedInputRegistration || inmate.Punishment != Punishment.Noted))
            {
                throw new WabiSabiProtocolException(WabiSabiProtocolErrorCode.InputBanned);
            }

            var txOutResponse = await Rpc.GetTxOutAsync(input.Hash, (int)input.N, includeMempool : true, cancellationToken).ConfigureAwait(false);

            if (txOutResponse is null)
            {
                throw new WabiSabiProtocolException(WabiSabiProtocolErrorCode.InputSpent);
            }
            if (txOutResponse.Confirmations == 0)
            {
                throw new WabiSabiProtocolException(WabiSabiProtocolErrorCode.InputUnconfirmed);
            }
            if (txOutResponse.IsCoinBase && txOutResponse.Confirmations <= 100)
            {
                throw new WabiSabiProtocolException(WabiSabiProtocolErrorCode.InputImmature);
            }

            return(new Coin(input, txOutResponse.TxOut));
        }
示例#2
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;
     }
 }
示例#3
0
    public async Task <Coin> OutpointToCoinAsync(InputRegistrationRequest request, CancellationToken cancellationToken)
    {
        OutPoint input = request.Input;

        if (Prison.TryGet(input, out var inmate))
        {
            DateTimeOffset bannedUntil;
            if (inmate.Punishment == Punishment.LongBanned)
            {
                bannedUntil = inmate.Started + Config.ReleaseUtxoFromPrisonAfterLongBan;
                throw new WabiSabiProtocolException(WabiSabiProtocolErrorCode.InputLongBanned, exceptionData: new InputBannedExceptionData(bannedUntil));
            }

            if (!Config.AllowNotedInputRegistration || inmate.Punishment != Punishment.Noted)
            {
                bannedUntil = inmate.Started + Config.ReleaseUtxoFromPrisonAfter;
                throw new WabiSabiProtocolException(WabiSabiProtocolErrorCode.InputBanned, exceptionData: new InputBannedExceptionData(bannedUntil));
            }
        }

        var txOutResponse = await Rpc.GetTxOutAsync(input.Hash, (int)input.N, includeMempool : true, cancellationToken).ConfigureAwait(false);

        if (txOutResponse is null)
        {
            throw new WabiSabiProtocolException(WabiSabiProtocolErrorCode.InputSpent);
        }
        if (txOutResponse.Confirmations == 0)
        {
            throw new WabiSabiProtocolException(WabiSabiProtocolErrorCode.InputUnconfirmed);
        }
        if (txOutResponse.IsCoinBase && txOutResponse.Confirmations <= 100)
        {
            throw new WabiSabiProtocolException(WabiSabiProtocolErrorCode.InputImmature);
        }

        return(new Coin(input, txOutResponse.TxOut));
    }
示例#4
0
 public async Task <InputRegistrationResponse> RegisterInputAsync(InputRegistrationRequest request, CancellationToken cancellationToken)
 {
     return(await IdempotencyRequestCache.GetCachedResponseAsync(request, action : (request, token) => Arena.RegisterInputAsync(request, token), cancellationToken));
 }
示例#5
0
 public Task <InputRegistrationResponse> RegisterInputAsync(InputRegistrationRequest request, CancellationToken cancellableToken)
 {
     return(RequestHandler.RegisterInputAsync(request, cancellableToken));
 }
示例#6
0
 public Task <InputRegistrationResponse> RegisterInputAsync(InputRegistrationRequest request, CancellationToken cancellationToken) =>
 SendAndReceiveAsync <InputRegistrationRequest, InputRegistrationResponse>(RemoteAction.RegisterInput, request, cancellationToken);
示例#7
0
        public async Task <InputRegistrationResponse> RegisterInputAsync(InputRegistrationRequest request, CancellationToken cancellationToken)
        {
            var coin = await OutpointToCoinAsync(request, cancellationToken).ConfigureAwait(false);

            using (await AsyncLock.LockAsync(cancellationToken).ConfigureAwait(false))
            {
                var round = GetRound(request.RoundId);

                var registeredCoins = Rounds.Where(x => !(x.Phase == Phase.Ended && !x.WasTransactionBroadcast))
                                      .SelectMany(r => r.Alices.Select(a => a.Coin));

                if (registeredCoins.Any(x => x.Outpoint == coin.Outpoint))
                {
                    throw new WabiSabiProtocolException(WabiSabiProtocolErrorCode.AliceAlreadyRegistered);
                }

                if (round.IsInputRegistrationEnded(Config.MaxInputCountByRound))
                {
                    throw new WabiSabiProtocolException(WabiSabiProtocolErrorCode.WrongPhase);
                }

                if (round is BlameRound blameRound && !blameRound.BlameWhitelist.Contains(coin.Outpoint))
                {
                    throw new WabiSabiProtocolException(WabiSabiProtocolErrorCode.InputNotWhitelisted);
                }

                // Compute but don't commit updated CoinJoin to round state, it will
                // be re-calculated on input confirmation. This is computed it here
                // for validation purposes.
                _ = round.Assert <ConstructionState>().AddInput(coin);

                var coinJoinInputCommitmentData = new CoinJoinInputCommitmentData("CoinJoinCoordinatorIdentifier", round.Id);
                if (!OwnershipProof.VerifyCoinJoinInputProof(request.OwnershipProof, coin.TxOut.ScriptPubKey, coinJoinInputCommitmentData))
                {
                    throw new WabiSabiProtocolException(WabiSabiProtocolErrorCode.WrongOwnershipProof);
                }

                // Generate a new GUID with the secure random source, to be sure
                // that it is not guessable (Guid.NewGuid() documentation does
                // not say anything about GUID version or randomness source,
                // only that the probability of duplicates is very low).
                var id    = new Guid(Random.GetBytes(16));
                var alice = new Alice(coin, request.OwnershipProof, round, id);

                if (alice.TotalInputAmount < round.MinAmountCredentialValue)
                {
                    throw new WabiSabiProtocolException(WabiSabiProtocolErrorCode.NotEnoughFunds);
                }
                if (alice.TotalInputAmount > round.MaxAmountCredentialValue)
                {
                    throw new WabiSabiProtocolException(WabiSabiProtocolErrorCode.TooMuchFunds);
                }

                if (alice.TotalInputVsize > round.MaxVsizeAllocationPerAlice)
                {
                    throw new WabiSabiProtocolException(WabiSabiProtocolErrorCode.TooMuchVsize);
                }

                var amountCredentialTask = round.AmountCredentialIssuer.HandleRequestAsync(request.ZeroAmountCredentialRequests, cancellationToken);
                var vsizeCredentialTask  = round.VsizeCredentialIssuer.HandleRequestAsync(request.ZeroVsizeCredentialRequests, cancellationToken);

                if (round.RemainingInputVsizeAllocation < round.MaxVsizeAllocationPerAlice)
                {
                    throw new WabiSabiProtocolException(WabiSabiProtocolErrorCode.VsizeQuotaExceeded);
                }

                var commitAmountCredentialResponse = await amountCredentialTask.ConfigureAwait(false);

                var commitVsizeCredentialResponse = await vsizeCredentialTask.ConfigureAwait(false);

                alice.SetDeadlineRelativeTo(round.ConnectionConfirmationTimeFrame.Duration);
                round.Alices.Add(alice);

                return(new(alice.Id,
                           commitAmountCredentialResponse,
                           commitVsizeCredentialResponse));
            }
        }
示例#8
0
    private static async Task RegisterAndAssertWrongPhaseAsync(InputRegistrationRequest req, Arena handler)
    {
        var ex = await Assert.ThrowsAsync <WrongPhaseException>(async() => await handler.RegisterInputAsync(req, CancellationToken.None));

        Assert.Equal(WabiSabiProtocolErrorCode.WrongPhase, ex.ErrorCode);
    }
 public Task <InputRegistrationResponse> RegisterInputAsync(InputRegistrationRequest request, CancellationToken cancellationToken)
 => arena.RegisterInputAsync((request));