public async Task given_valid_consumer_address_delivery_receipt_should_be_processed() { _signer.RecoverPublicKey(Arg.Any <Signature>(), Arg.Any <Keccak>()).ReturnsForAnyArgs(_publicKey); _peer.ConsumerAddress.Returns(_publicKey.Address); 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().BeTrue(); _session.DataAvailability.Should().NotBe(DataAvailability.DataDeliveryReceiptInvalid); }
private void ConfigureMocks(TestConsumer consumer) { var depositId = consumer.DepositId; _consumerRepository.GetAsync(depositId).Returns(consumer.Consumer); _paymentClaimRepository.BrowseAsync(Arg.Any <GetPaymentClaims>()) .Returns(PagedResult <PaymentClaim> .Empty); _sessionRepository.BrowseAsync(new GetProviderSessions { DepositId = depositId }) .Returns(PagedResult <ProviderSession> .Create(new List <ProviderSession>(consumer.Sessions), 1, 1, 1, 1)); _receiptsPolicies.CanRequestReceipts(Arg.Any <long>(), Arg.Any <UInt256>()).Returns(true); _sessionManager.GetConsumerNodes(depositId).Returns(consumer.Nodes.Select(n => n.Node).ToArray()); _receiptProcessor.TryProcessAsync(Arg.Any <ProviderSession>(), _consumer, Arg.Any <INdmProviderPeer>(), Arg.Any <DataDeliveryReceiptRequest>(), Arg.Any <DataDeliveryReceipt>()).Returns(true); }
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); } }