An exception that is thrown when anything stub related went wrong.
Inheritance: Exception
Example #1
0
        public static void Validate(IReadOnlyCollection <Transfer> transfers)
        {
            if (transfers == null || !transfers.Any())
            {
                throw RequestValidationException.ShouldBeNotEmptyCollection(nameof(transfers));
            }

            var duplicatedTransfers = transfers
                                      .GroupBy(x => new
            {
                x.Asset,
                x.SourceAddress,
                x.DestinationAddress
            })
                                      .Where(x => x.Count() > 1)
                                      .ToArray();

            if (duplicatedTransfers.Any())
            {
                var duplicatesMessage = new StringBuilder();

                duplicatesMessage.AppendLine();

                foreach (var group in duplicatedTransfers)
                {
                    duplicatesMessage.AppendLine($"Asset: {group.Key.Asset}, source address: {group.Key.SourceAddress}, destination address: {group.Key.DestinationAddress}");
                }

                throw new RequestValidationException(
                          $"Only one transfer per asset, source address, destination address is allowed. Duplicates are: {duplicatesMessage}",
                          nameof(transfers));
            }
        }
Example #2
0
        /// <summary>
        /// Coin to receive for the transaction.
        /// </summary>
        /// <param name="coinNumber">Number of the coin inside the transaction.</param>
        /// <param name="asset">Asset of the coin.</param>
        /// <param name="value">Coin value to receive.</param>
        /// <param name="address">Address which should receive the coin.</param>
        /// <param name="addressTag">
        /// Optional.
        /// Receiving address tag.
        /// </param>
        /// <param name="addressTagType">
        /// Optional.
        /// Type of the receiving address tag.
        /// </param>
        public CoinToReceive(
            int coinNumber,
            Asset asset,
            UMoney value,
            Address address,
            AddressTag addressTag         = null,
            AddressTagType?addressTagType = null)
        {
            if (coinNumber < 0)
            {
                throw RequestValidationException.ShouldBeZeroOrPositiveNumber(coinNumber, nameof(coinNumber));
            }

            if (addressTagType.HasValue && addressTag == null)
            {
                throw new RequestValidationException("If the tag type is specified, the tag should be specified too", new [] { nameof(addressTagType), nameof(addressTag) });
            }

            CoinNumber     = coinNumber;
            Asset          = asset ?? throw RequestValidationException.ShouldBeNotNull(nameof(asset));
            Value          = value;
            Address        = address ?? throw RequestValidationException.ShouldBeNotNull(nameof(address));
            AddressTag     = addressTag;
            AddressTagType = addressTagType;
        }
        /// <summary>
        /// Endpoint: [POST] /api/addresses
        /// </summary>
        /// <param name="encryptionPublicKey">
        /// Encryption public key which should be used to encrypt
        /// the private key of the address being created before
        /// return it in the encryptedPrivateKey field of the
        /// response.
        /// </param>
        public CreateAddressRequest(Base64String encryptionPublicKey)
        {
            if (string.IsNullOrWhiteSpace(encryptionPublicKey?.ToString()))
            {
                throw RequestValidationException.ShouldBeNotEmptyString(nameof(encryptionPublicKey));
            }

            EncryptionPublicKey = encryptionPublicKey;
        }
Example #4
0
        /// <summary>
        /// Endpoint: [POST] /api/transactions/broadcasted
        /// </summary>
        /// <param name="signedTransaction">The signed transaction.</param>
        public BroadcastTransactionRequest(Base64String signedTransaction)
        {
            if (string.IsNullOrWhiteSpace(signedTransaction?.ToString()))
            {
                throw RequestValidationException.ShouldBeNotEmptyString(nameof(signedTransaction));
            }

            SignedTransaction = signedTransaction;
        }
        public async Task <ActionResult <TransactionStateResponse> > GetState([FromRoute] TransactionId transactionId)
        {
            if (transactionId == null)
            {
                throw RequestValidationException.ShouldBeNotNull(nameof(transactionId));
            }

            var state = await _transactionsStateProvider.GetStateAsync(transactionId);

            return(Ok(new TransactionStateResponse(state)));
        }
Example #6
0
        /// <summary>
        /// Build response for <see cref="RequestValidationException"/>.
        /// </summary>
        /// <param name="ex">Exception information about an error that happened in the WebApi project.</param>
        private static Task BuildAndSendAsync(RequestValidationException ex, ErrorBuilder errorBuilder)
        {
            foreach (var error in ex.Errors)
            {
                errorBuilder.AddData($"Invalid property: {error.PropertyName}", string.Join("; ", error.Messages));
            }

            return(errorBuilder
                   .SetDescription("Invalid request parameters")
                   .SetHttpCode(HttpStatusCode.BadRequest)
                   .SetErrorCode("RequestValidationError")
                   .BuildAndSendAsync());
        }
            public void GivenExceptionIsRequestValidationException_WhenRunningPipeline_ThenReturnsBadRequestWithExceptionDetails()
            {
                var requestValidationException = new RequestValidationException("Exception info 1");
                var expectedExceptionModel     = requestValidationException.Message;

                var result = _sut.Invoke(A.Dummy <NancyContext>(), requestValidationException) as Negotiator;

                result.Should().NotBeNull();
                result.NegotiationContext.StatusCode.Should().Be(HttpStatusCode.BadRequest);
                var actualExceptionModel = result.NegotiationContext.GetModelForMediaRange("application/json") as object;

                actualExceptionModel.Should().BeAssignableTo <string>();
                ((string)actualExceptionModel).ShouldBeEquivalentTo(expectedExceptionModel);
            }
    private async Task HandleRequestValidationException(string correlation, RequestValidationException e)
    {
        _httpContextService.SetStatusCode(HttpStatusCode.NotImplemented);
        _httpContextService.TryAddHeader(CorrelationHeaderKey, correlation);
        if (_settings?.Gui?.EnableUserInterface == true)
        {
            var pageContents =
                StaticResources.stub_not_configured_html_page.Replace("[ROOT_URL]", _httpContextService.RootUrl);
            _httpContextService.AddHeader("Content-Type", Constants.HtmlMime);
            await _httpContextService.WriteAsync(pageContents);
        }

        _logger.LogInformation($"Request validation exception thrown: {e.Message}");
    }
        /// <summary>
        /// Transaction expiration options.
        /// </summary>
        /// <param name="afterMoment">Transaction should be expired after given moment.</param>
        /// <param name="afterBlockNumber">Transaction should be expired after given block number.</param>
        public ExpirationOptions(DateTime?afterMoment = null, long?afterBlockNumber = null)
        {
            if (!afterMoment.HasValue && !afterBlockNumber.HasValue)
            {
                throw new RequestValidationException("At least one option should be specified", new [] { nameof(afterMoment), nameof(afterBlockNumber) });
            }

            if (afterBlockNumber < 1)
            {
                throw RequestValidationException.ShouldBePositiveNumber(afterBlockNumber, nameof(afterBlockNumber));
            }

            AfterMoment      = afterMoment;
            AfterBlockNumber = afterBlockNumber;
        }
Example #10
0
 /// <summary>
 /// Coin to spend for the transaction.
 /// </summary>
 /// <param name="coinId">Reference to the coin which should be spend.</param>
 /// <param name="asset">Asset of the coin.</param>
 /// <param name="value">Coin value to spend.</param>
 /// <param name="address">Address that owns the coin.</param>
 /// <param name="addressContext">
 /// Optional.
 /// Address context associated with the owner address.
 /// </param>
 /// <param name="addressNonce">
 /// Optional.
 /// Nonce number of the transaction for the owner address.
 /// </param>
 public CoinToSpend(
     CoinId coinId,
     Asset asset,
     UMoney value,
     Address address,
     Base64String addressContext = null,
     long?addressNonce           = null)
 {
     Coin           = coinId ?? throw RequestValidationException.ShouldBeNotNull(nameof(coinId));
     Asset          = asset ?? throw RequestValidationException.ShouldBeNotNull(nameof(asset));
     Value          = value;
     Address        = address ?? throw RequestValidationException.ShouldBeNotNull(nameof(address));
     AddressContext = addressContext;
     AddressNonce   = addressNonce;
 }
Example #11
0
        /// <summary>
        /// Endpoint: [POST] /api/transactions/signed
        /// </summary>
        /// <param name="privateKeys">
        /// Private keys of the addresses which should sign the transaction.
        /// Multiple keys can be used for the/ transactions with multiple inputs.
        /// </param>
        /// <param name="transactionContext">
        /// Implementation specific transaction context.
        /// </param>
        public SignTransactionRequest(IReadOnlyCollection <EncryptedString> privateKeys, Base64String transactionContext)
        {
            if (privateKeys == null || !privateKeys.Any() || privateKeys.Any(x => x == null))
            {
                throw RequestValidationException.ShouldBeNotEmptyCollection(nameof(privateKeys));
            }

            if (string.IsNullOrWhiteSpace(transactionContext?.ToString()))
            {
                throw RequestValidationException.ShouldBeNotEmptyString(nameof(transactionContext));
            }

            PrivateKeys        = privateKeys;
            TransactionContext = transactionContext;
        }
        public async Task <ActionResult <CreateAddressTagResponse> > CreateAddressTag([FromRoute] Address address, [FromBody] CreateAddressTagRequest request)
        {
            if (address == null)
            {
                throw RequestValidationException.ShouldBeNotNull(nameof(address));
            }

            var response = await _addressGenerator.CreateAddressTagAsync(address, request);

            if (response == null)
            {
                throw new InvalidOperationException("Not null response object expected");
            }

            return(Ok(response));
        }
        public async Task <ActionResult <AddressFormatsResponse> > GetFormats([FromRoute] Address address)
        {
            if (address == null)
            {
                throw RequestValidationException.ShouldBeNotNull(nameof(address));
            }

            var response = await _addressFormatsProvider.GetFormatsAsync(address);

            if (response == null)
            {
                throw new InvalidOperationException("Not null response object expected");
            }

            return(Ok(response));
        }
        public async Task <ActionResult <RawObjectResponse> > GetRaw([FromRoute] TransactionId transactionId)
        {
            if (transactionId == null)
            {
                throw RequestValidationException.ShouldBeNotNull(nameof(transactionId));
            }

            var raw = await _rawObjectsRepository.GetOrDefaultAsync(RawObjectType.Transaction, transactionId);

            if (raw == null)
            {
                return(NotFound(BlockchainErrorResponse.Create($"Raw transaction [{transactionId}] not found")));
            }

            return(Ok(new RawObjectResponse(raw)));
        }
        /// <summary>
        /// Endpoint: [POST] /api/transactions/built/transfers/amount
        /// </summary>
        /// <param name="transfers">Transaction transfers.</param>
        /// <param name="fees">Fees amount in particular asset to spend for the given transaction.</param>
        /// <param name="expiration">
        /// Optional.
        /// Transaction expiration options. Used if blockchain
        /// supports transaction expiration. If blockchain supports
        /// transaction expiration and the value is omitted,
        /// it should be interpreted as infinite expiration.
        /// If several expiration options are specified at once,
        /// and blockchain supports both of them, then transaction
        /// should be expired when earliest condition is met.
        /// </param>
        public BuildTransferAmountTransactionRequest(
            IReadOnlyCollection <Transfer> transfers,
            IReadOnlyCollection <Fee> fees,
            ExpirationOptions expiration = null)
        {
            if (fees == null)
            {
                throw RequestValidationException.ShouldBeNotNull(nameof(fees));
            }

            TransactionTransfersValidator.Validate(transfers);
            FeesValidator.ValidateFeesInRequest(fees);

            Transfers  = transfers;
            Fees       = fees;
            Expiration = expiration;
        }
        /// <summary>
        /// Translate certain "special" classes of exception to classes that can be passed through the service boundary.
        /// </summary>
        /// <param name="e"></param>
        /// <returns></returns>
        private static bool TranslateException(ref Exception e)
        {
            // special handling of EntityVersionException
            // assume all such exceptions occured because of concurrent modifications
            // wrap in ConcurrentModificationException will be used in the fault contract
            if (e is EntityVersionException)
            {
                e = new ConcurrentModificationException(e.Message);
                return(true);
            }

            // special handling of EntityValidationException
            // convert to RequestValidationException
            if (e is EntityValidationException)
            {
                e = new RequestValidationException(e.Message);
                return(true);
            }

            return(false);
        }
        public async Task <ActionResult <AddressValidityResponse> > Validate(
            [FromRoute] Address address,
            [FromQuery] AddressTagType?tagType = null,
            [FromQuery] AddressTag tag         = null)
        {
            if (address == null)
            {
                throw RequestValidationException.ShouldBeNotNull(nameof(address));
            }

            if (tagType.HasValue && tag == null)
            {
                throw new RequestValidationException("If the tag type is specified, the tag should be specified too", new [] { nameof(tagType), nameof(tag) });
            }

            var response = await _addressValidator.ValidateAsync(address, tagType, tag);

            if (response == null)
            {
                throw new InvalidOperationException("Not null response object expected");
            }

            return(Ok(response));
        }
Example #18
0
        /// <summary>
        /// Transfer of the transaction.
        /// </summary>
        /// <param name="asset">Asset to transfer.</param>
        /// <param name="amount">Amount to transfer from the source address to the destination address.</param>
        /// <param name="sourceAddress">Address to transfer from.</param>
        /// <param name="destinationAddress">Address to transfer to.</param>
        /// <param name="sourceAddressContext">
        /// Optional.
        /// Source address context associated with the address.
        /// </param>
        /// <param name="sourceAddressNonce">
        /// Optional.
        /// Nonce number of the transaction for the source address.
        /// </param>
        /// <param name="destinationAddressTag">
        /// Optional.
        /// Destination address tag.
        /// </param>
        /// <param name="destinationAddressTagType">
        /// Optional.
        /// Type of the destination address tag.
        /// </param>
        public Transfer(
            Asset asset,
            UMoney amount,
            Address sourceAddress,
            Address destinationAddress,
            Base64String sourceAddressContext        = null,
            long?sourceAddressNonce                  = null,
            AddressTag destinationAddressTag         = null,
            AddressTagType?destinationAddressTagType = null)
        {
            if (destinationAddressTagType.HasValue && destinationAddressTag == null)
            {
                throw new RequestValidationException("If the tag type is specified, the tag should be specified too", new [] { nameof(destinationAddressTagType), nameof(destinationAddressTag) });
            }

            Asset                     = asset ?? throw RequestValidationException.ShouldBeNotNull(nameof(asset));
            Amount                    = amount;
            SourceAddress             = sourceAddress ?? throw RequestValidationException.ShouldBeNotNull(nameof(sourceAddress));
            SourceAddressContext      = sourceAddressContext;
            SourceAddressNonce        = sourceAddressNonce;
            DestinationAddress        = destinationAddress ?? throw RequestValidationException.ShouldBeNotNull(nameof(destinationAddress));
            DestinationAddressTag     = destinationAddressTag;
            DestinationAddressTagType = destinationAddressTagType;
        }
        public static void Validate(IReadOnlyCollection <CoinToSpend> coinsToSpend, IReadOnlyCollection <CoinToReceive> coinsToReceive)
        {
            if (coinsToSpend == null || !coinsToSpend.Any())
            {
                throw RequestValidationException.ShouldBeNotEmptyCollection(nameof(coinsToSpend));
            }

            if (coinsToReceive == null || !coinsToReceive.Any())
            {
                throw RequestValidationException.ShouldBeNotEmptyCollection(nameof(coinsToReceive));
            }

            var coinsToReceiveNumbers = coinsToReceive.Select(x => x.CoinNumber).OrderBy(x => x).ToArray();

            if (coinsToReceiveNumbers[0] > 0)
            {
                throw new RequestValidationException("Least coins to receive number should be 0", coinsToReceive.Select(x => x.CoinNumber), nameof(coinsToReceive));
            }

            var previousCoinToReceiveNumber = 0;

            foreach (var number in coinsToReceiveNumbers.Skip(1))
            {
                if (number - 1 != previousCoinToReceiveNumber++)
                {
                    throw new RequestValidationException("Coins to receive numbers should be in a row without gaps", coinsToReceive.Select(x => x.CoinNumber), nameof(coinsToReceive));
                }
            }

            var coinsToSpendByAssets = coinsToSpend
                                       .GroupBy(x => x.Asset)
                                       .Select(g => new
            {
                Asset = g.Key,
                Sum   = g.Sum(x => x.Value)
            })
                                       .OrderBy(x => x.Asset)
                                       .ToArray();
            var coinsToReceiveByAssets = coinsToReceive
                                         .GroupBy(x => x.Asset)
                                         .Select(g => new
            {
                Asset = g.Key,
                Sum   = g.Sum(x => x.Value)
            })
                                         .OrderBy(x => x.Asset)
                                         .ToArray();
            var assetsToSpend   = coinsToSpendByAssets.Select(x => x.Asset.ToString()).ToArray();
            var assetsToReceive = coinsToReceiveByAssets.Select(x => x.Asset.ToString()).ToArray();

            if (!assetsToSpend.SequenceEqual(assetsToReceive))
            {
                throw new RequestValidationException(
                          "Sets of coins to spend and coins to receive assets should be equal." +
                          $"{Environment.NewLine}Actual coins to spend assets: [{string.Join(", ", assetsToSpend)}]" +
                          $"{Environment.NewLine}Actual coins to receive assets: [{string.Join(", ", assetsToReceive)}]",
                          new[] { nameof(coinsToSpend), nameof(coinsToReceive) });
            }

            var mismatchedAssetSums = coinsToSpendByAssets
                                      .Join(
                coinsToReceiveByAssets,
                x => x.Asset,
                x => x.Asset,
                (input, output) => new
            {
                // ReSharper disable once RedundantAnonymousTypePropertyName
                Asset        = input.Asset,
                SumToSpend   = input.Sum,
                SumToReceive = output.Sum
            })
                                      .Where(x => x.SumToSpend < x.SumToReceive)
                                      .ToArray();

            if (mismatchedAssetSums.Any())
            {
                var mismatchesMessage = new StringBuilder();

                mismatchesMessage.AppendLine();

                foreach (var assetSum in mismatchedAssetSums)
                {
                    mismatchesMessage.AppendLine($"Asset: {assetSum.Asset}, sum to spend: {assetSum.SumToSpend}, sum to receive: {assetSum.SumToReceive}");
                }

                throw new RequestValidationException(
                          $"Sum to spend and to receive of each asset should be equal. Mismatched sum: {mismatchesMessage}",
                          new[] { nameof(coinsToSpend), nameof(coinsToReceive) });
            }
        }