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)); }
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; } }
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)); }
public async Task <InputRegistrationResponse> RegisterInputAsync(InputRegistrationRequest request, CancellationToken cancellationToken) { return(await IdempotencyRequestCache.GetCachedResponseAsync(request, action : (request, token) => Arena.RegisterInputAsync(request, token), cancellationToken)); }
public Task <InputRegistrationResponse> RegisterInputAsync(InputRegistrationRequest request, CancellationToken cancellableToken) { return(RequestHandler.RegisterInputAsync(request, cancellableToken)); }
public Task <InputRegistrationResponse> RegisterInputAsync(InputRegistrationRequest request, CancellationToken cancellationToken) => SendAndReceiveAsync <InputRegistrationRequest, InputRegistrationResponse>(RemoteAction.RegisterInput, request, cancellationToken);
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)); } }
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));