コード例 #1
0
        public async Task payment_claim_should_not_be_sent_while_units_are_less_than_units_range_to()
        {
            var unitsRange   = new UnitsRange(0, 5);
            var paymentClaim = new PaymentClaim(id: Keccak.Zero,
                                                depositId: Keccak.Zero,
                                                assetId: Keccak.Zero,
                                                assetName: "test",
                                                units: 3,
                                                claimedUnits: 3,
                                                unitsRange: unitsRange,
                                                value: 10,
                                                claimedValue: 30,
                                                expiryTime: 10,
                                                pepper: Array.Empty <byte>(),
                                                provider: TestItem.AddressA,
                                                consumer: TestItem.AddressB,
                                                signature: new Signature(1, 2, 37),
                                                timestamp: 12,
                                                transactions: Array.Empty <TransactionInfo>(),
                                                status: PaymentClaimStatus.Unknown
                                                );

            Keccak?transactionHash = await _processor.SendTransactionAsync(paymentClaim, 10);

            Assert.IsNull(transactionHash);
            Assert.IsTrue(paymentClaim.Status != PaymentClaimStatus.Sent);
        }
コード例 #2
0
        private DataDeliveryReceiptRequest CreateRequest(Keccak depositId, Keccak sessionId, uint unpaidSessionUnits,
                                                         bool isSettlement = false)
        {
            if (_logger.IsInfo)
            {
                _logger.Info($"Creating a receipt request for deposit: '{depositId}', session: '{sessionId}'.");
            }
            IDepositNodesHandler?deposit = GetDepositNodesHandler(depositId);

            if (deposit == null)
            {
                throw new InvalidDataException($"Cannot resolve deposit for deposit ID {depositId}");
            }

            uint number = deposit.GetNextReceiptRequestNumber();
            uint latestReceiptRangeTo = deposit.LatestReceipt?.Request.UnitsRange.To ?? 0;
            uint rangeFrom            = deposit.LatestReceipt is null ? 0 : latestReceiptRangeTo + 1;
            uint rangeTo = rangeFrom + unpaidSessionUnits - 1;

            rangeTo = rangeTo >= deposit.PurchasedUnits ? (uint)deposit.PurchasedUnits - 1 : rangeTo;
            UnitsRange unitsRange = new UnitsRange(rangeFrom, rangeTo);

            if (_logger.IsInfo)
            {
                _logger.Info($"Created a receipt request for deposit: '{depositId}', session: '{sessionId}', range: [{unitsRange.From}, {unitsRange.To}].");
            }

            return(new DataDeliveryReceiptRequest(number, depositId, unitsRange, isSettlement));
        }
コード例 #3
0
        public DataDeliveryReceiptToMerge Decode(RlpStream rlpStream,
                                                 RlpBehaviors rlpBehaviors = RlpBehaviors.None)
        {
            rlpStream.ReadSequenceLength();
            UnitsRange unitsRange = Serialization.Rlp.Rlp.Decode <UnitsRange>(rlpStream);
            Signature  signature  = SignatureDecoder.DecodeSignature(rlpStream);

            return(new DataDeliveryReceiptToMerge(unitsRange, signature));
        }
コード例 #4
0
        public DataDeliveryReceiptRequest Decode(RlpStream rlpStream,
                                                 RlpBehaviors rlpBehaviors = RlpBehaviors.None)
        {
            rlpStream.ReadSequenceLength();
            uint       number       = rlpStream.DecodeUInt();
            Keccak     depositId    = rlpStream.DecodeKeccak();
            UnitsRange unitsRange   = Serialization.Rlp.Rlp.Decode <UnitsRange>(rlpStream);
            bool       isSettlement = rlpStream.DecodeBool();
            var        receipts     = Serialization.Rlp.Rlp.DecodeArray <DataDeliveryReceiptToMerge>(rlpStream);

            return(new DataDeliveryReceiptRequest(number, depositId, unitsRange, isSettlement, receipts));
        }
コード例 #5
0
        public async Task given_null_transaction_hash_returned_payment_claim_should_have_status_unknown()
        {
            var unitsRange = new UnitsRange(0, 1);
            var consumer   = CreateConsumer();

            _consumerRepository.GetAsync(Arg.Any <Keccak>()).Returns(consumer);
            var receiptRequest = new DataDeliveryReceiptRequest(1, Keccak.Zero, unitsRange);
            var paymentClaim   = await _processor.ProcessAsync(receiptRequest, null);

            paymentClaim.Transaction.Should().BeNull();
            paymentClaim.Status.Should().Be(PaymentClaimStatus.Unknown);
        }
コード例 #6
0
        public void given_units_range_from_5_to_9_and_6_unpaid_units_request_should_be_valid()
        {
            var unpaidUnits    = 6;
            var consumedUnits  = 0;
            var purchasedUnits = 100;
            var unitsRange     = new UnitsRange(5, 9);
            var receiptRequest = CreateRequest(unitsRange);

            var isValid = _validator.IsValid(receiptRequest, unpaidUnits, consumedUnits, purchasedUnits);

            isValid.Should().BeTrue();
        }
コード例 #7
0
        public void given_previous_range_from_0_to_9_and_actual_range_from_10_to_19_and_10_unpaid_units_request_should_be_valid()
        {
            var unpaidUnits        = 10;
            var consumedUnits      = 0;
            var purchasedUnits     = 100;
            var previousUnitsRange = new UnitsRange(0, 9);
            var unitsRange         = new UnitsRange(10, 19);
            var previousReceipt    = new DataDeliveryReceiptToMerge(previousUnitsRange, null);
            var receiptRequest     = CreateRequest(unitsRange, new[] { previousReceipt });

            var isValid = _validator.IsValid(receiptRequest, unpaidUnits, consumedUnits, purchasedUnits);

            isValid.Should().BeTrue();
        }
コード例 #8
0
        public async Task given_receipt_request_range_0_to_19_payment_claim_range_should_be_0_to_19()
        {
            var unitsRange = new UnitsRange(0, 19);
            var consumer   = CreateConsumer();

            _consumerRepository.GetAsync(Arg.Any <Keccak>()).Returns(consumer);
            _paymentService.ClaimPaymentAsync(Arg.Any <PaymentClaim>(), _coldWalletAddress, _gasPrice)
            .Returns(_transaction.Hash);
            var receiptRequest = new DataDeliveryReceiptRequest(1, Keccak.Zero, unitsRange);
            var paymentClaim   = await _processor.ProcessAsync(receiptRequest, null);

            paymentClaim.ClaimedUnits.Should().Be(20);
            paymentClaim.UnitsRange.Should().Be(unitsRange);
        }
コード例 #9
0
        public async Task given_valid_transaction_hash_returned_payment_claim_should_have_status_sent()
        {
            var unitsRange = new UnitsRange(0, 1);
            var consumer   = CreateConsumer();

            _consumerRepository.GetAsync(Arg.Any <Keccak>()).Returns(consumer);
            _paymentService.ClaimPaymentAsync(Arg.Any <PaymentClaim>(), _coldWalletAddress, _gasPrice)
            .Returns(_transaction.Hash);
            var receiptRequest = new DataDeliveryReceiptRequest(1, Keccak.Zero, unitsRange);
            var paymentClaim   = await _processor.ProcessAsync(receiptRequest, null);

            paymentClaim.Transaction.Hash.Should().Be(_transaction.Hash);
            paymentClaim.Status.Should().Be(PaymentClaimStatus.Sent);
        }
コード例 #10
0
        public async Task given_invalid_consumer_address_delivery_receipt_should_not_be_processed()
        {
            _signer.RecoverPublicKey(Arg.Any <Signature>(), Arg.Any <Keccak>()).ReturnsForAnyArgs(TestItem.PublicKeyB);
            _peer.ConsumerAddress.Returns(TestItem.AddressC);

            var currentReceiptRequestUnitsRange = new UnitsRange(0, 9);
            var receiptRequest  = new DataDeliveryReceiptRequest(1, Keccak.Zero, currentReceiptRequestUnitsRange);
            var deliveryReceipt = new DataDeliveryReceipt(StatusCodes.Ok, 0, 0, new Signature(new byte[65]));

            var wasProcessed = await _processor.TryProcessAsync(_session, _publicKey.Address, _peer, receiptRequest,
                                                                deliveryReceipt);

            wasProcessed.Should().BeFalse();
            _session.DataAvailability.Should().Be(DataAvailability.DataDeliveryReceiptInvalid);
        }
コード例 #11
0
        public void given_previous_ranges_from_0_to_11_and_actual_range_from_0_to_22_and_11_unpaid_units_request_should_be_valid()
        {
            var unpaidUnits      = 11;
            var consumedUnits    = 0;
            var purchasedUnits   = 100;
            var unitsRange       = new UnitsRange(0, 22);
            var previousReceipts = new[]
            {
                new DataDeliveryReceiptToMerge(new UnitsRange(0, 11), null)
            };
            var receiptRequest = CreateRequest(unitsRange, previousReceipts);

            var isValid = _validator.IsValid(receiptRequest, unpaidUnits, consumedUnits, purchasedUnits);

            isValid.Should().BeTrue();
        }
コード例 #12
0
        private async Task <TxReceipt> ClaimPaymentFor(DataRequest dataRequest, Keccak depositId, uint start, uint end, Address payToAccount)
        {
            UInt256 payToBalanceBefore    = _state.GetBalance(payToAccount);
            UInt256 providerBalanceBefore = _state.GetBalance(_providerAccount);
            UInt256 feeBalanceBefore      = _state.GetBalance(_feeAccount);

            UnitsRange unitRange    = new UnitsRange(start, end);
            UInt256    value        = dataRequest.Units * (UInt256)dataRequest.Value / dataRequest.Units;
            uint       claimedUnits = unitRange.Units;
            UInt256    claimedValue = claimedUnits * (UInt256)dataRequest.Value / dataRequest.Units;

            byte[]       receiptData  = _abiEncoder.Encode(AbiEncodingStyle.Packed, _receiptAbiDef, depositId.Bytes, unitRange.From, unitRange.To);
            Signature    receiptSig   = _wallet.Sign(Keccak.Compute(receiptData), _consumerAccount);
            PaymentClaim paymentClaim = new PaymentClaim(Keccak.Zero, depositId, dataRequest.DataAssetId,
                                                         "data asset", dataRequest.Units, claimedUnits, unitRange, value, (UInt256)claimedValue,
                                                         dataRequest.ExpiryTime, dataRequest.Pepper, _providerAccount, _consumerAccount, receiptSig, 0, Array.Empty <TransactionInfo>(), PaymentClaimStatus.Unknown);

            UInt256 gasPrice      = 20.GWei();
            Keccak  paymentTxHash = await _paymentService.ClaimPaymentAsync(paymentClaim, payToAccount, gasPrice);

            _bridge.IncrementNonce(_providerAccount);

            UInt256 feeBalanceAfter      = _state.GetBalance(_feeAccount);
            UInt256 providerBalanceAfter = _state.GetBalance(_providerAccount);
            UInt256 payToBalanceAfter    = _state.GetBalance(payToAccount);

            TxReceipt txReceipt = _bridge.GetReceipt(paymentTxHash);

            TestContext.WriteLine("GAS USED FOR PAYMENT CLAIM: {0}", txReceipt.GasUsed);
            TestContext.WriteLine($"(FEE) BALANCE BEFORE: {feeBalanceBefore}");
            TestContext.WriteLine($"(FEE) DIFFERENCE: {feeBalanceAfter - feeBalanceBefore}");
            TestContext.WriteLine($"(PAY TO) BALANCE BEFORE: {payToBalanceBefore}");
            TestContext.WriteLine($"(PAY TO) DIFFERENCE: {payToBalanceAfter - payToBalanceBefore}");
            TestContext.WriteLine($"(PROVIDER) BALANCE BEFORE: {providerBalanceBefore}");
            TestContext.WriteLine($"(PROVIDER) DIFFERENCE: {(BigInteger) providerBalanceAfter - (BigInteger) providerBalanceBefore}");

            bool    isProviderSameAsPayTo = _providerAccount.Equals(payToAccount);
            UInt256 expectedPayment       = (8 * dataRequest.Value * (unitRange.To - unitRange.From + 1)) / (dataRequest.Units * 10);
            UInt256 expectedGasFee        = (UInt256)txReceipt.GasUsed * 20.GWei();
            UInt256 expectedFee           = 2 * dataRequest.Value * unitRange.Units / (dataRequest.Units * 10);

            Assert.AreEqual((UInt256)20, 100 * expectedFee / (expectedPayment + expectedFee), "fee %");
            Assert.AreEqual(expectedFee, feeBalanceAfter - feeBalanceBefore, "fee");
            Assert.AreEqual(providerBalanceBefore - expectedGasFee + (isProviderSameAsPayTo ? UInt256.One : UInt256.Zero) * expectedPayment, providerBalanceAfter, $"before: {providerBalanceBefore}, after: {providerBalanceAfter}");
            Assert.AreEqual(payToBalanceBefore - (isProviderSameAsPayTo ? UInt256.One : UInt256.Zero) * expectedGasFee + expectedPayment, payToBalanceAfter, $"before: {payToBalanceBefore}, after: {payToBalanceAfter}");
            return(txReceipt);
        }
コード例 #13
0
        public async Task <Keccak?> SendTransactionAsync(PaymentClaim paymentClaim, UInt256 gasPrice)
        {
            bool isPaymentClaimCorrect = IsPaymentClaimCorrect(paymentClaim);

            if (!isPaymentClaimCorrect)
            {
                if (_logger.IsWarn)
                {
                    _logger.Warn($"Payment claim id: {paymentClaim.Id} was incorrect. Claim will be rejected");
                }

                paymentClaim.Reject();
                await _paymentClaimRepository.UpdateAsync(paymentClaim);

                return(null);
            }

            Keccak     depositId       = paymentClaim.DepositId;
            UnitsRange range           = paymentClaim.UnitsRange;
            Keccak?    transactionHash = await _paymentService.ClaimPaymentAsync(paymentClaim, _coldWalletAddress, gasPrice);

            bool isTransactionHashValid = !(transactionHash is null) && transactionHash != Keccak.Zero;

            if (isTransactionHashValid)
            {
                if (_logger.IsInfo)
                {
                    _logger.Info($"Received a transaction hash: {transactionHash} for payment claim (id: '{paymentClaim.Id}') for deposit: '{depositId}', range: [{range.From}, {range.To}], units: {paymentClaim.Units}.");
                }
                return(transactionHash);
            }

            if (_logger.IsError)
            {
                _logger.Error($"There was an error when claiming a payment (id: '{paymentClaim.Id}') for deposit: '{depositId}', range: [{range.From}, {range.To}] with receipt [{range.From}, {range.To}], units: {paymentClaim.Units} - returned transaction is empty.");
            }

            return(null);
        }
コード例 #14
0
        private DataDeliveryReceiptRequest?CreateMergedRequest(IDepositNodesHandler deposit)
        {
            if (deposit.LatestReceipt == null)
            {
                return(null);
            }

            if (_logger.IsInfo)
            {
                _logger.Info($"Creating merged receipt request for deposit: '{deposit.DepositId}'.");
            }
            bool isLastReceipt = deposit.LatestReceipt.Request.UnitsRange.To == deposit.PurchasedUnits - 1;

            if (isLastReceipt && _logger.IsInfo)
            {
                _logger.Info($"Merged receipt request for deposit: '{deposit.DepositId}' will be the last one.");
            }

            uint latestPaymentClaimRangeTo = deposit.LatestPaymentClaim?.UnitsRange.To ?? 0;

            DataDeliveryReceiptDetails?latestMergedReceipt = deposit.Receipts.OrderBy(r => r.Timestamp)
                                                             .ThenBy(r => r.Request.UnitsRange.To)
                                                             .LastOrDefault(r => r.IsMerged);

            uint latestMergedReceiptRangeFrom = latestMergedReceipt?.Request.UnitsRange.From ?? 0;
            long latestMergedReceiptRangeTo   = latestMergedReceipt?.Request.UnitsRange.To ?? 0;

            var mergeableReceipts = deposit.Receipts
                                    .Where(r => r.Timestamp >= (latestMergedReceipt?.Timestamp ?? 0) &&
                                           r.Request.UnitsRange.To >
                                           (latestMergedReceipt is null ? -1 : latestMergedReceiptRangeTo))
                                    .OrderBy(r => r.Timestamp)
                                    .ThenBy(r => r.Request.UnitsRange.To)
                                    .ToList();

            var  paymentClaimExist = deposit.LatestPaymentClaim is { };
            uint rangeFrom;

            if (paymentClaimExist)
            {
                rangeFrom = latestPaymentClaimRangeTo + 1;
            }
            else
            {
                if (latestMergedReceiptRangeFrom > 0)
                {
                    rangeFrom = latestMergedReceiptRangeFrom + 1;
                }
                else
                {
                    rangeFrom = 0;
                }
            }

            uint rangeTo = deposit.LatestReceipt.Request.UnitsRange.To;

            if (rangeFrom > rangeTo)
            {
                return(null);
            }

            if (!(latestMergedReceipt is null))
            {
                mergeableReceipts.Insert(0, latestMergedReceipt);
            }

            UnitsRange unitsRange      = new UnitsRange(rangeFrom, rangeTo);
            var        receiptsToMerge = mergeableReceipts.Select(r => new DataDeliveryReceiptToMerge(
                                                                      r.Request.UnitsRange, r.Receipt.Signature)).OrderBy(r => r.UnitsRange.To).ToList();
            uint number = deposit.GetNextReceiptRequestNumber();

            if (_logger.IsInfo)
            {
                _logger.Info($"Created merged receipt request for deposit: '{deposit.DepositId}' [{rangeFrom}, {rangeTo}].");
            }

            return(new DataDeliveryReceiptRequest(number, deposit.DepositId, unitsRange,
                                                  receiptsToMerge: receiptsToMerge));
        }
コード例 #15
0
        private async Task <DataDeliveryReceiptDetails?> TryHandleReceiptAsync(ProviderSession session, Address consumer,
                                                                               INdmProviderPeer peer, DataDeliveryReceiptRequest request)
        {
            Keccak depositId             = session.DepositId;
            IDepositNodesHandler?deposit = GetDepositNodesHandler(depositId);

            if (deposit == null)
            {
                throw new InvalidDataException($"Cannot resolve deposit handle for deposit ID: {depositId}");
            }

            try
            {
                UnitsRange unitsRange = request.UnitsRange;
                if (_logger.IsInfo)
                {
                    _logger.Info($"Sending data delivery receipt request ({request.Number}), deposit: '{depositId}', session: '{session.Id}', range: [{unitsRange.From}, {unitsRange.To}].");
                }
                if (request.ReceiptsToMerge.Any())
                {
                    if (_logger.IsInfo)
                    {
                        _logger.Info($"Receipts to merge for deposit: '{depositId}': {string.Join(", ", request.ReceiptsToMerge.Select(r => $"[{r.UnitsRange.From}, {r.UnitsRange.To}]"))}");
                    }
                }

                (DataDeliveryReceipt receipt, RequestReceiptStatus status) = await TryHandleDeliveryReceipt(deposit, consumer, session, request, peer);

                Keccak id = Keccak.Compute(Rlp.Encode(Rlp.Encode(depositId), Rlp.Encode(request.Number)).Bytes);
                DataDeliveryReceiptDetails receiptDetails = new DataDeliveryReceiptDetails(id, session.Id, session.DataAssetId, peer.NodeId,
                                                                                           request, receipt, _timestamper.UnixTime.Seconds, false);
                await _receiptRepository.AddAsync(receiptDetails);

                if (status != RequestReceiptStatus.Ok)
                {
                    return(null);
                }

                UnitsRange range        = request.UnitsRange;
                uint       claimedUnits = range.To - range.From + 1;
                deposit.AddReceipt(receiptDetails);
                if (!request.ReceiptsToMerge.Any())
                {
                    deposit.SubtractUnpaidUnits(claimedUnits);
                }

                if (_logger.IsInfo)
                {
                    _logger.Info($"Successfully processed receipt ({claimedUnits} units) for deposit: '{depositId}' with node: '{peer.NodeId}'.");
                }

                return(receiptDetails);
            }
            catch (Exception ex)
            {
                if (_logger.IsWarn)
                {
                    _logger.Warn($"There was an error when processing a receipt for deposit: '{depositId}'. {ex}");
                }
                session.SetDataAvailability(DataAvailability.DataDeliveryReceiptNotProvided);
                await _sessionRepository.UpdateAsync(session);

                peer.SendDataAvailability(depositId, DataAvailability.DataDeliveryReceiptInvalid);

                return(null);
            }
        }
コード例 #16
0
        private async Task <(DataDeliveryReceipt, RequestReceiptStatus)> TryHandleDeliveryReceipt(IDepositNodesHandler deposit,
                                                                                                  Address consumer, ProviderSession session, DataDeliveryReceiptRequest request, INdmProviderPeer peer,
                                                                                                  bool isRetry = false)
        {
            while (true)
            {
                Keccak depositId            = session.DepositId;
                DataDeliveryReceipt receipt = await peer.SendRequestDataDeliveryReceiptAsync(request, CancellationToken.None);

                if (_logger.IsInfo)
                {
                    _logger.Info($"Received a delivery receipt for deposit: '{depositId}' from node: '{peer.NodeId}', status code: '{receipt.StatusCode}'.");
                }
                if (isRetry && receipt.StatusCode != StatusCodes.Ok)
                {
                    if (_logger.IsWarn)
                    {
                        _logger.Warn($"Request receipt retry failed for: '{depositId}' from node: '{peer.NodeId}', status code: '{receipt.StatusCode}'.");
                    }

                    return(receipt, RequestReceiptStatus.Invalid);
                }

                switch (receipt.StatusCode)
                {
                case StatusCodes.Ok:
                    if (await _receiptProcessor.TryProcessAsync(session, consumer, peer, request, receipt))
                    {
                        return(receipt, RequestReceiptStatus.Ok);
                    }

                    return(receipt, RequestReceiptStatus.Invalid);

                case StatusCodes.InvalidReceiptRequestRange:
                {
                    if (_logger.IsInfo)
                    {
                        _logger.Info($"Consumer for deposit: '{depositId}' from node: '{peer.NodeId}' claims {receipt.ConsumedUnits} consumed and {receipt.UnpaidUnits} unpaid units.");
                    }
                    UnitsRange range          = request.UnitsRange;
                    uint       requestedUnits = range.To - range.From + 1;
                    if (requestedUnits <= receipt.UnpaidUnits)
                    {
                        if (_logger.IsWarn)
                        {
                            _logger.Warn($"Consumer for deposit: '{depositId}' from node: '{peer.NodeId}' claimed an invalid range  (while it was actually valid).");
                        }

                        break;
                    }

                    uint graceUnits          = requestedUnits - receipt.UnpaidUnits;
                    uint totalGraceUnits     = graceUnits + deposit.GraceUnits;
                    bool hasReachedThreshold = await _receiptsPolicies.CanClaimPayment(totalGraceUnits, deposit.UnitPrice);

                    if (hasReachedThreshold)
                    {
                        peer.SendGraceUnitsExceeded(depositId, deposit.ConsumedUnits, totalGraceUnits);
                        if (_logger.IsWarn)
                        {
                            _logger.Warn($"Consumer for deposit: '{depositId}' from node: '{peer.NodeId}' claimed too many unpaid units, grace units exceeded ({totalGraceUnits}).");
                        }

                        return(receipt, RequestReceiptStatus.GraceUnitsExceeded);
                    }

                    if (_logger.IsInfo)
                    {
                        _logger.Info($"Unpaid units difference is: {graceUnits} ({requestedUnits} - {receipt.UnpaidUnits}). Lowering units amount for deposit: '{depositId}'.");
                    }
                    deposit.SubtractUnpaidUnits(graceUnits);
                    deposit.SubtractUnmergedUnits(graceUnits);
                    deposit.SubtractUnclaimedUnits(graceUnits);
                    deposit.AddGraceUnits(graceUnits);
                    session.SubtractUnpaidUnits(graceUnits);
                    session.AddGraceUnits(graceUnits);
                    if (range.To < graceUnits)
                    {
                        peer.SendGraceUnitsExceeded(depositId, deposit.ConsumedUnits, totalGraceUnits);
                        if (_logger.IsWarn)
                        {
                            _logger.Warn($"Cannot request a receipt for deposit: '{depositId}'  - grace units amount is greater than the receipt range ({graceUnits} > {range.To}).");
                        }

                        return(receipt, RequestReceiptStatus.GraceUnitsExceeded);
                    }

                    uint updatedRangeTo = range.To - graceUnits;
                    if (range.From > updatedRangeTo)
                    {
                        if (_logger.IsWarn)
                        {
                            _logger.Warn($"Invalid updated range [{range.From}, {updatedRangeTo}] for: '{depositId}' - receipt request will not be send.");
                        }

                        return(receipt, RequestReceiptStatus.Invalid);
                    }

                    if (_logger.IsInfo)
                    {
                        _logger.Info($"Grace units for deposit: '{depositId}' is: {deposit.GraceUnits} (added {graceUnits}).");
                    }
                    UnitsRange updatedRange = new UnitsRange(range.From, updatedRangeTo);
                    if (_logger.IsInfo)
                    {
                        _logger.Info($"Updated range for deposit: '{depositId}' [{updatedRange.From}, {updatedRange.To}]. Requesting receipt once again.");
                    }
                    request = request.WithRange(updatedRange, deposit.GetNextReceiptRequestNumber());
                    isRetry = true;
                    continue;
                }

                case StatusCodes.InvalidReceiptAddress:
                {
                    break;
                }

                case StatusCodes.Error:
                {
                    break;
                }
                }

                return(receipt, RequestReceiptStatus.Invalid);
            }
        }
コード例 #17
0
        public async Task <PaymentClaim?> ProcessAsync(DataDeliveryReceiptRequest receiptRequest, Signature signature)
        {
            Keccak   depositId = receiptRequest.DepositId;
            Consumer?consumer  = await _consumerRepository.GetAsync(depositId);

            if (consumer is null)
            {
                if (_logger.IsError)
                {
                    _logger.Error($"Could not find any consumers for deposit {depositId} in the repository.");
                }
                return(null);
            }

            DataRequest  dataRequest   = consumer.DataRequest;
            UnitsRange   range         = receiptRequest.UnitsRange;
            uint         claimedUnits  = range.Units;
            BigInteger   claimedValue  = claimedUnits * (BigInteger)consumer.DataRequest.Value / consumer.DataRequest.Units;
            ulong        timestamp     = _timestamper.UnixTime.Seconds;
            Rlp          unitsRangeRlp = _unitsRangeRlpDecoder.Encode(range);
            Keccak       id            = Keccak.Compute(Rlp.Encode(Rlp.Encode(depositId), Rlp.Encode(timestamp), unitsRangeRlp).Bytes);
            PaymentClaim paymentClaim  = new PaymentClaim(id, consumer.DepositId, consumer.DataAsset.Id,
                                                          consumer.DataAsset.Name, dataRequest.Units, claimedUnits, range, dataRequest.Value,
                                                          (UInt256)claimedValue, dataRequest.ExpiryTime, dataRequest.Pepper, dataRequest.Provider,
                                                          dataRequest.Consumer, signature, timestamp, Array.Empty <TransactionInfo>(), PaymentClaimStatus.Unknown);
            await _paymentClaimRepository.AddAsync(paymentClaim);

            if (_logger.IsInfo)
            {
                _logger.Info($"Claiming a payment (id: '{paymentClaim.Id}') for deposit: '{depositId}', range: [{range.From}, {range.To}], units: {claimedUnits}.");
            }
            UInt256 gasPrice = await _gasPriceService.GetCurrentPaymentClaimGasPriceAsync();

            Keccak?transactionHash = null;

            if (_disableSendingPaymentClaimTransaction)
            {
                if (_logger.IsWarn)
                {
                    _logger.Warn("*** NDM provider sending payment claim transaction is disabled ***");
                }
            }
            else
            {
                transactionHash = await SendTransactionAsync(paymentClaim, gasPrice);

                if (transactionHash is null)
                {
                    if (_logger.IsInfo)
                    {
                        _logger.Info($"Payment claim (id: {paymentClaim.Id}) for deposit: '{paymentClaim.DepositId}' did not receive a transaction hash.");
                    }
                    return(paymentClaim);
                }
            }

            if (_logger.IsInfo)
            {
                _logger.Info($"Payment claim (id: {paymentClaim.Id}) for deposit: '{paymentClaim.DepositId}' received a transaction hash: '{transactionHash}'.");
            }
            paymentClaim.AddTransaction(TransactionInfo.Default(transactionHash, 0, gasPrice, _paymentService.GasLimit,
                                                                timestamp));
            paymentClaim.SetStatus(PaymentClaimStatus.Sent);
            await _paymentClaimRepository.UpdateAsync(paymentClaim);

            string claimedEth = ((decimal)claimedValue / Eth).ToString("0.0000");

            if (_logger.IsInfo)
            {
                _logger.Info($"Sent a payment claim (id: '{paymentClaim.Id}') for deposit: '{depositId}', range: [{range.From}, {range.To}], units: {claimedUnits}, units: {claimedUnits}, value: {claimedValue} wei ({claimedEth} ETH, transaction hash: '{transactionHash}'.");
            }

            return(paymentClaim);
        }
コード例 #18
0
 public UnitsRangeForRpc(UnitsRange range)
 {
     From = range.From;
     To   = range.To;
 }
コード例 #19
0
        private async Task TryMergeReceiptsAsync(IDepositNodesHandler deposit)
        {
            Keccak depositId = deposit.DepositId;

            if (deposit.HasSentLastMergedReceipt)
            {
                if (_logger.IsInfo)
                {
                    _logger.Info($"Last receipt request for deposit: '{depositId}' was already sent.");
                }
                return;
            }

            if (deposit.HasClaimedAllUnits)
            {
                if (_logger.IsInfo)
                {
                    _logger.Info($"Last receipt request for deposit: '{depositId}' was already claimed.");
                }
                return;
            }

            DataDeliveryReceiptDetails?latestReceipt = deposit.LatestMergedReceipt;

            if (latestReceipt?.Request.UnitsRange.To == deposit.PurchasedUnits)
            {
                if (_logger.IsInfo)
                {
                    _logger.Info($"Last receipt request for deposit: '{depositId}' was already merged.");
                }
                return;
            }

            var consumerNodes = _sessionManager.GetConsumerNodes(depositId);

            foreach (ConsumerNode node in consumerNodes)
            {
                if (_logger.IsInfo)
                {
                    _logger.Info($"Trying to merge receipts for deposit: '{depositId}' with node: '{node.Peer.NodeId}'.");
                }
                try
                {
                    ProviderSession?session = node.GetSession(depositId);
                    if (session is null)
                    {
                        if (_logger.IsInfo)
                        {
                            _logger.Info($"Session was not found for deposit: '{depositId}', node: '{node.Peer.NodeId}'.");
                        }
                        continue;
                    }

                    DataDeliveryReceiptRequest?request = CreateMergedRequest(deposit);
                    if (request is null)
                    {
                        if (_logger.IsInfo)
                        {
                            _logger.Info($"Merged receipt for deposit: '{depositId}' couldn't be created.");
                        }
                        return;
                    }

                    if (latestReceipt?.Request.UnitsRange.Equals(request.UnitsRange) == true)
                    {
                        if (_logger.IsInfo)
                        {
                            _logger.Info($"Merged receipt request for deposit: '{depositId}' would be the same as a previous one (already sent).");
                        }
                        continue;
                    }

                    uint previouslyMergedUnits = latestReceipt?.Request.UnitsRange.To + 1 ?? 0;
                    DataDeliveryReceiptDetails?receiptDetails = await TryHandleReceiptAsync(session, deposit.Consumer, node.Peer, request);

                    if (receiptDetails is null)
                    {
                        if (_logger.IsWarn)
                        {
                            _logger.Warn($"Couldn't merge receipts for deposit: '{depositId}' with node: '{node.Peer.NodeId}'.");
                        }
                        continue;
                    }

                    deposit.AddReceipt(receiptDetails);
                    UnitsRange range    = receiptDetails.Request.UnitsRange;
                    uint       mergedTo = range.To + 1;
                    if (mergedTo <= previouslyMergedUnits)
                    {
                        return;
                    }

                    uint mergedUnits = mergedTo - previouslyMergedUnits;
                    mergedUnits = deposit.UnmergedUnits < mergedUnits ? deposit.UnmergedUnits : mergedUnits;
                    deposit.SubtractUnmergedUnits(mergedUnits);
                    if (_logger.IsInfo)
                    {
                        _logger.Info($"Successfully merged receipts ({mergedUnits} units) for deposit: '{depositId}' with node: '{node.Peer.NodeId}'.");
                    }
                    break;
                }
                catch (Exception ex)
                {
                    if (_logger.IsWarn)
                    {
                        _logger.Warn($"There was an error when merging receipt requests for deposit: '{deposit.DepositId}'. {ex}");
                    }
                }
            }
        }
コード例 #20
0
 private static DataDeliveryReceiptRequest CreateRequest(UnitsRange unitsRange,
                                                         IEnumerable <DataDeliveryReceiptToMerge> previousReceipts = null)
 => new DataDeliveryReceiptRequest(1, Keccak.Zero, unitsRange, false,
                                   previousReceipts ?? Enumerable.Empty <DataDeliveryReceiptToMerge>());