예제 #1
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);
            }
        }
예제 #2
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}");
                    }
                }
            }
        }