Esempio n. 1
0
        public async Task returns_unclaimed_units_correctly()
        {
            var          depositId = Keccak.Zero;
            TestConsumer consumer  = TestConsumer.ForDeposit(depositId)
                                     .WithNode(1).AddSession().WithUnpaidUnits(10)
                                     .And.WithNode(2).AddSession().WithUnpaidUnits(20)
                                     .And.Build();

            ConfigureMocks(consumer);

            _sessionManager.GetSession(depositId, consumer.Node(1).Node.Peer)
            .Returns(consumer.Node(1).Node.Sessions.First(s => s.DepositId == depositId));

            IDepositNodesHandler depositHandler = await _depositManager.InitAsync(depositId);

            AddReciptsToMerge(consumer, depositHandler);
            _receiptsPolicies.CanMergeReceipts(depositHandler.UnmergedUnits, depositHandler.UnitPrice).Returns(true);

            depositHandler.SetConsumedUnits(80);
            depositHandler.SetUnmergedUnits(50);

            await _depositManager.HandleUnpaidUnitsAsync(depositId, consumer.Node(1).Node.Peer);

            var unclaimedUnits = _depositManager.GetUnclaimedUnits(depositId);

            Assert.AreEqual(10, unclaimedUnits);
        }
Esempio n. 2
0
        public void Setup()
        {
            _depositNodesHandlerFactory = Substitute.For <IDepositNodesHandlerFactory>();
            _sessionManager             = Substitute.For <ISessionManager>();
            _receiptsPolicies           = Substitute.For <IReceiptsPolicies>();
            _receiptProcessor           = Substitute.For <IReceiptProcessor>();
            _paymentClaimProcessor      = Substitute.For <IPaymentClaimProcessor>();
            _consumerRepository         = Substitute.For <IConsumerRepository>();
            _paymentClaimRepository     = Substitute.For <IPaymentClaimRepository>();
            _sessionRepository          = Substitute.For <IProviderSessionRepository>();
            _sessionRepository.BrowseAsync(Arg.Any <GetProviderSessions>()).Returns(PagedResult <ProviderSession> .Empty);
            _receiptRepository = Substitute.For <IReceiptRepository>();
            var unixTime = UnixTime.FromSeconds(100);

            _timestamper = Substitute.For <ITimestamper>();
            _timestamper.UnixTime.Returns(unixTime);
            _gasPriceService     = Substitute.For <IGasPriceService>();
            _logManager          = Substitute.For <ILogManager>();
            _wallet              = Substitute.For <IWallet>();
            _address             = Address.Zero;
            _consumer            = Address.Zero;
            _depositNodesHandler = new InMemoryDepositNodesHandler(Keccak.Zero, _consumer, DataAssetUnitType.Unit, 0,
                                                                   100, 0,
                                                                   0, 0, 0, 0, 0, 0, null, null, 0);
            _depositNodesHandlerFactory.CreateInMemory(Arg.Any <Keccak>(), _consumer, Arg.Any <DataAssetUnitType>(),
                                                       Arg.Any <uint>(), Arg.Any <uint>(), Arg.Any <UInt256>(), Arg.Any <uint>(), Arg.Any <uint>(), Arg.Any <uint>(),
                                                       Arg.Any <uint>(), Arg.Any <uint>(), Arg.Any <uint>(), Arg.Any <PaymentClaim>(),
                                                       Arg.Any <IEnumerable <DataDeliveryReceiptDetails> >(), Arg.Any <uint>()).Returns(_depositNodesHandler);
            _depositManager = new DepositManager(_depositNodesHandlerFactory, _sessionManager, _receiptsPolicies,
                                                 _wallet, _address, _receiptProcessor, _paymentClaimProcessor, _consumerRepository,
                                                 _paymentClaimRepository, _receiptRepository, _sessionRepository, _timestamper, _gasPriceService,
                                                 _logManager);
        }
Esempio n. 3
0
        // There is no need to match merge threshold while all of the units has been consumed
        public async Task will_merge_if_consumed_all_but_did_not_match_threshold()
        {
            var          depositId = Keccak.Zero;
            TestConsumer consumer  = TestConsumer.ForDeposit(depositId)
                                     .WithNode(1).AddSession().WithUnpaidUnits(10)
                                     .And.WithNode(2).AddSession().WithUnpaidUnits(20)
                                     .And.Build();

            ConfigureMocks(consumer);

            _sessionManager.GetSession(depositId, consumer.Node(1).Node.Peer)
            .Returns(consumer.Node(1).Node.Sessions.First(s => s.DepositId == depositId));

            IDepositNodesHandler depositHandler = await _depositManager.InitAsync(depositId);

            AddReciptsToMerge(consumer, depositHandler);
            _receiptsPolicies.CanMergeReceipts(depositHandler.UnmergedUnits, depositHandler.UnitPrice).Returns(false);

            depositHandler.SetConsumedUnits(100);
            depositHandler.SetUnmergedUnits(50);

            await _depositManager.HandleUnpaidUnitsAsync(depositId, consumer.Node(1).Node.Peer);

            Assert.IsTrue(depositHandler.UnmergedUnits == 0);
        }
Esempio n. 4
0
        private async Task TryClaimPaymentAsync(IDepositNodesHandler deposit)
        {
            if (_accountLocked)
            {
                if (_logger.IsWarn)
                {
                    _logger.Warn($"Account: '{_providerAddress}' is locked, can't claim a payment.");
                }

                return;
            }

            if (!deposit.Receipts.Any())
            {
                return;
            }

            if (deposit.HasClaimedAllUnits)
            {
                if (_logger.IsInfo)
                {
                    _logger.Info($"Last payment was already claimed for deposit: '{deposit.DepositId}'.");
                }

                return;
            }

            try
            {
                var unclaimedUnits = GetUnclaimedUnits(deposit);
                if (deposit.ConsumedAll || await _receiptsPolicies.CanClaimPayment(unclaimedUnits, deposit.UnitPrice))
                {
                    UInt256 gasPrice = await _gasPriceService.GetCurrentGasPriceAsync();

                    UInt256 fee    = gasPrice * GasLimit;
                    UInt256 profit = unclaimedUnits * deposit.UnitPrice;
                    if (fee >= profit)
                    {
                        if (_logger.IsWarn)
                        {
                            _logger.Warn($"Claiming a payment would cause loss (fee: {fee} wei >= profit: {profit} wei).");
                        }
                        return;
                    }

                    await ClaimPaymentAsync(deposit);
                }
            }
            catch (Exception ex)
            {
                if (_logger.IsWarn)
                {
                    _logger.Warn($"There was an error when claiming a payment for deposit: '{deposit.DepositId}'. {ex}");
                }
            }
        }
Esempio n. 5
0
        private uint GetUnclaimedUnits(IDepositNodesHandler deposit)
        {
            var latestReceiptUnitsRange = deposit.LatestReceipt?.IsClaimed == true
                                            ? null
                                            : deposit.LatestReceipt?.Request.UnitsRange;

            var unclaimedRange = deposit.LatestMergedReceipt?.IsClaimed == true
                ? latestReceiptUnitsRange
                : deposit.LatestMergedReceipt?.Request.UnitsRange;

            return(unclaimedRange is null ? 0 : unclaimedRange.To - unclaimedRange.From + 1);
        }
Esempio n. 6
0
        public async Task will_calculate_units_correctly_when_unit_type_is_time()
        {
            var          depositId = Keccak.Zero;
            TestConsumer consumer  = TestConsumer.ForDeposit(depositId, DataAssetUnitType.Time)
                                     .WithNode(1).AddSession().WithUnpaidUnits(10).WithConsumedUnits(30)
                                     .And.Build();

            ConfigureMocks(consumer);

            var depositNodesHandler = new InMemoryDepositNodesHandler(Keccak.Zero,
                                                                      _consumer,
                                                                      DataAssetUnitType.Time,
                                                                      1,
                                                                      100,
                                                                      1,
                                                                      60,
                                                                      50,
                                                                      30,
                                                                      50,
                                                                      0,
                                                                      0,
                                                                      null,
                                                                      null,
                                                                      0);

            _depositNodesHandlerFactory.CreateInMemory(depositId,
                                                       Arg.Any <Address>(),
                                                       DataAssetUnitType.Time, Arg.Any <uint>(),
                                                       Arg.Any <uint>(), Arg.Any <UInt256>(), Arg.Any <uint>(),
                                                       Arg.Any <uint>(),
                                                       Arg.Any <uint>(),
                                                       Arg.Any <uint>(),
                                                       Arg.Any <uint>(),
                                                       Arg.Any <uint>(),
                                                       Arg.Any <PaymentClaim>(),
                                                       Arg.Any <IEnumerable <DataDeliveryReceiptDetails> >(),
                                                       Arg.Any <uint>())
            .Returns(depositNodesHandler);

            IDepositNodesHandler depositHandler = await _depositManager.InitAsync(depositId);

            await _depositManager.HandleConsumedUnitAsync(depositId);

            Assert.IsTrue(depositHandler.ConsumedUnits == 99);
            Assert.IsTrue(depositHandler.UnpaidUnits == 79);
            Assert.IsTrue(depositHandler.UnclaimedUnits == 89);
            Assert.IsTrue(depositHandler.UnmergedUnits == 69);
        }
Esempio n. 7
0
        private void AddReciptsToMerge(TestConsumer consumer, IDepositNodesHandler depositHandler)
        {
            DataDeliveryReceiptRequest request = new DataDeliveryReceiptRequest(1, consumer.DepositId, new UnitsRange(0, 5), false, new List <DataDeliveryReceiptToMerge> {
                new DataDeliveryReceiptToMerge(new UnitsRange(0, 1), new Signature(1, 2, 37))
            });
            DataDeliveryReceipt        receipt        = new DataDeliveryReceipt(StatusCodes.Ok, 50, 0, new Signature(1, 2, 37));
            DataDeliveryReceiptDetails receiptDetails = new DataDeliveryReceiptDetails(Keccak.OfAnEmptyString, consumer.Sessions.First().Id, consumer.DataAsset.Id, null, request, receipt, 10, true);

            depositHandler.AddReceipt(receiptDetails);

            DataDeliveryReceiptRequest request2        = new DataDeliveryReceiptRequest(1, consumer.DepositId, new UnitsRange(6, 49));
            DataDeliveryReceipt        receipt2        = new DataDeliveryReceipt(StatusCodes.Ok, 50, 0, new Signature(1, 2, 37));
            DataDeliveryReceiptDetails receiptDetails2 = new DataDeliveryReceiptDetails(Keccak.OfAnEmptyString, consumer.Sessions.First().Id, consumer.DataAsset.Id, null, request2, receipt2, 10, false);

            depositHandler.AddReceipt(receiptDetails2);
        }
Esempio n. 8
0
        // While running HandleUnpaidUnitsAsync() DepositManager will try to claim payment for
        // unpaid units.
        // The method starts with previous session and checks whether there are any unpaid units and then
        // moves to the current one.
        public async Task can_handle_unpaid_units()
        {
            var          depositId = Keccak.Zero;
            TestConsumer consumer  = TestConsumer.ForDeposit(depositId)
                                     .WithNode(1).AddSession().WithUnpaidUnits(10)
                                     .And.WithNode(2).AddSession().WithUnpaidUnits(20)
                                     .And.Build();

            ConfigureMocks(consumer);

            _sessionManager.GetSession(depositId, consumer.Node(1).Node.Peer)
            .Returns(consumer.Node(1).Node.Sessions.First(s => s.DepositId == depositId));

            IDepositNodesHandler depositHandler = await _depositManager.InitAsync(depositId);

            await _depositManager.HandleUnpaidUnitsAsync(depositId, consumer.Node(1).Node.Peer);

            Assert.IsTrue(depositHandler.UnpaidUnits == 0);
        }
Esempio n. 9
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);
            }
        }
Esempio n. 10
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));
        }
Esempio n. 11
0
        private async Task ClaimPaymentAsync(IDepositNodesHandler deposit)
        {
            if (deposit.LatestPaymentClaim?.UnitsRange.To == deposit.PurchasedUnits - 1)
            {
                if (_logger.IsInfo)
                {
                    _logger.Info($"Last receipt request for deposit: '{deposit.DepositId}' was already claimed.");
                }
                return;
            }

            var claimableReceipts = deposit.Receipts
                                    .Where(r => !r.IsClaimed)
                                    .OrderBy(r => r.Timestamp)
                                    .ThenBy(r => r.Request.UnitsRange.To)
                                    .ToArray();

            DataDeliveryReceiptDetails latestClaimableReceipt = claimableReceipts.LastOrDefault(r => r.IsMerged) ??
                                                                claimableReceipts.FirstOrDefault(r =>
                                                                                                 r.Request.UnitsRange.To == deposit.PurchasedUnits - 1);

            if (latestClaimableReceipt is null)
            {
                if (_logger.IsWarn)
                {
                    _logger.Warn($"Cannot claim a payment for deposit: '{deposit.DepositId}' - claimable receipt was not found.");
                }
                return;
            }

            if (latestClaimableReceipt.IsClaimed)
            {
                if (_logger.IsWarn)
                {
                    _logger.Warn($"Cannot claim a payment for deposit: '{deposit.DepositId}' - receipt was already claimed, timestamp: {latestClaimableReceipt.Timestamp}.");
                }
                return;
            }

            DataDeliveryReceiptDetails?receipt = await _receiptRepository.GetAsync(latestClaimableReceipt.Id);

            if (receipt == null)
            {
                throw new InvalidDataException($"Unable to make a claim for the receipt with ID: {latestClaimableReceipt.Id} - receipt missing");
            }

            receipt.Claim();
            await _receiptRepository.UpdateAsync(receipt);

            PaymentClaim?paymentClaim = await _paymentClaimProcessor.ProcessAsync(latestClaimableReceipt.Request,
                                                                                  latestClaimableReceipt.Receipt.Signature);

            if (paymentClaim is null)
            {
                throw new InvalidDataException($"Unable to make a claim for the receipt with ID: {latestClaimableReceipt.Id} - claim processing failure");
            }

            latestClaimableReceipt.Claim();
            deposit.AddReceipt(latestClaimableReceipt); // so the receipt become LatestReceipt
            deposit.ClearReceipts();
            deposit.SetLatestPaymentClaim(paymentClaim);
            uint claimedUnits = deposit.UnclaimedUnits < paymentClaim.ClaimedUnits
                ? deposit.UnclaimedUnits
                : paymentClaim.ClaimedUnits;

            deposit.SubtractUnclaimedUnits(claimedUnits);
            if (_logger.IsInfo)
            {
                _logger.Info($"Successfully claimed payment ({claimedUnits} units) for deposit: '{deposit.DepositId}'.");
            }
        }
Esempio n. 12
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}");
                    }
                }
            }
        }
Esempio n. 13
0
        private async Task RequestReceiptsAsync(IDepositNodesHandler deposit)
        {
            Keccak depositId    = deposit.DepositId;
            int    nodesCount   = _sessionManager.GetNodesCount(depositId);
            int    nodesCounter = 0;

            foreach (ConsumerNode node in _sessionManager.GetConsumerNodes(depositId))
            {
                nodesCounter++;
                if (deposit.HasSentAllReceipts)
                {
                    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;
                }

                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;
                }

                if (session.UnpaidUnits == 0)
                {
                    if (_logger.IsInfo)
                    {
                        _logger.Info($"Session: '{session.Id}' has no unpaid units.");
                    }
                    continue;
                }

                if (_logger.IsTrace)
                {
                    _logger.Trace($"Session: '{session.Id}' has {session.UnpaidUnits} unpaid units.");
                }
                if (!deposit.ConsumedAll && await _receiptsPolicies.CanRequestReceipts(session.UnpaidUnits * nodesCount, deposit.UnitPrice) == false)
                {
                    if (_logger.IsTrace)
                    {
                        _logger.Trace($"Session: '{session.Id}' has too low unpaid units to be processed.");
                    }
                    continue;
                }

                if (_logger.IsInfo)
                {
                    _logger.Info($"Requesting receipt for deposit: '{depositId}' from node: '{node.Peer.NodeId}' ({nodesCounter}/{nodesCount}).");
                }
                DataDeliveryReceiptDetails?details = await TryHandleReceiptAsync(session, deposit.Consumer, node.Peer);

                if (details is null)
                {
                    if (_logger.IsInfo)
                    {
                        _logger.Info($"Couldn't request receipt for deposit: '{depositId}' from node: '{node.Peer.NodeId}'.");
                    }

                    continue;
                }

                if (_logger.IsInfo)
                {
                    _logger.Info($"Successfully requested receipt for deposit: '{depositId}' from node: '{node.Peer.NodeId}'.");
                }
            }
        }
Esempio n. 14
0
        private async Task TryHandleDepositAsync(IDepositNodesHandler deposit, bool isRetry = false)
        {
            if (_logger.IsTrace)
            {
                _logger.Trace($"Started handling consumed units for deposit: '{deposit.DepositId}'.");
            }
            if (deposit.ConsumedAll || await _receiptsPolicies.CanRequestReceipts(deposit.UnpaidUnits, deposit.UnitPrice))
            {
                await RequestReceiptsAsync(deposit);
            }

            if (deposit.ConsumedAll || await _receiptsPolicies.CanMergeReceipts(deposit.UnmergedUnits, deposit.UnitPrice))
            {
                await TryMergeReceiptsAsync(deposit);
            }

            await TryClaimPaymentAsync(deposit);

            if (_logger.IsTrace)
            {
                _logger.Trace($"Finished handling consumed units for deposit: '{deposit.DepositId}'.");
            }
            if (isRetry)
            {
                return;
            }

            if (!deposit.ConsumedAll)
            {
                return;
            }

            if (deposit.HasClaimedAllUnits)
            {
                if (_logger.IsInfo)
                {
                    _logger.Info($"Last payment claim for deposit: '{deposit.DepositId}' was already processed.");
                }

                return;
            }

            deposit.FinishHandling();
            while (deposit.CurrentLastClaimRetry < LastClaimRetries)
            {
                if (_logger.IsInfo)
                {
                    _logger.Info($"Missing payment claim for deposit: '{deposit.DepositId}', retry {deposit.CurrentLastClaimRetry + 1}/{LastClaimRetries}.");
                }
                foreach (ConsumerNode node in _sessionManager.GetConsumerNodes(deposit.DepositId))
                {
                    ProviderSession?session = node.GetSession(deposit.DepositId);
                    if (session is null)
                    {
                        if (_logger.IsInfo)
                        {
                            _logger.Info($"Session was not found for deposit: '{deposit.DepositId}', node: '{node.Peer.NodeId}'.");
                        }
                        continue;
                    }

                    if (_logger.IsInfo)
                    {
                        _logger.Info($"Consumer: '{node.Peer.NodeId}', session: '{session.Id}' has {session.UnpaidUnits} unpaid units.");
                    }
                }
                await TryHandleDepositAsync(deposit, true);

                deposit.IncrementLastClaimRetries();
                if (deposit.HasClaimedAllUnits)
                {
                    return;
                }
            }
        }