示例#1
0
        public async Task send_should_succeed_when_receipt_is_valid()
        {
            var timestamp = _timestamper.EpochSeconds;
            var receipt   = GetDataDeliveryReceiptRequest();
            var deposit   = GetDepositDetails();
            var session   = GetConsumerSession();
            var provider  = Substitute.For <INdmPeer>();
            var receiptId = Keccak.Compute(Rlp.Encode(Rlp.Encode(receipt.DepositId), Rlp.Encode(receipt.Number),
                                                      Rlp.Encode(timestamp)).Bytes);

            _depositProvider.GetAsync(receipt.DepositId).Returns(deposit);
            _sessionService.GetActive(receipt.DepositId).Returns(session);
            _providerService.GetPeer(deposit.DataAsset.Provider.Address).Returns(provider);
            _receiptRequestValidator.IsValid(receipt, session.UnpaidUnits, session.ConsumedUnits,
                                             deposit.Deposit.Units).Returns(true);
            _ecdsa.RecoverPublicKey(Arg.Any <Signature>(), Arg.Any <Keccak>())
            .Returns(session.ConsumerNodeId);
            await _receiptService.SendAsync(receipt, 0, 0);

            await _sessionRepository.Received().UpdateAsync(session);

            await _receiptRepository.Received().AddAsync(Arg.Is <DataDeliveryReceiptDetails>(x =>
                                                                                             x.Id == receiptId &&
                                                                                             x.SessionId == session.Id &&
                                                                                             x.DataAssetId == session.DataAssetId &&
                                                                                             x.ConsumerNodeId == _nodePublicKey &&
                                                                                             x.Request.Equals(receipt) &&
                                                                                             x.Timestamp == timestamp &&
                                                                                             !x.IsClaimed));

            provider.Received().SendDataDeliveryReceipt(receipt.DepositId, Arg.Is <DataDeliveryReceipt>(x =>
                                                                                                        x.StatusCode == StatusCodes.Ok));
        }
示例#2
0
        public async Task SendAsync(DataDeliveryReceiptRequest request, int fetchSessionRetries = 3,
                                    int fetchSessionRetryDelayMilliseconds = 3000)
        {
            var depositId = request.DepositId;

            var(deposit, session) = await TryGetDepositAndSessionAsync(depositId,
                                                                       fetchSessionRetries, fetchSessionRetryDelayMilliseconds);

            if (deposit is null || session is null)
            {
                return;
            }

            var providerAddress = deposit.DataAsset.Provider.Address;
            var providerPeer    = _providerService.GetPeer(providerAddress);

            if (providerPeer is null)
            {
                if (_logger.IsWarn)
                {
                    _logger.Warn($"Provider: '{providerAddress}' was not found.");
                }

                return;
            }

            var receiptId = Keccak.Compute(Rlp.Encode(Rlp.Encode(depositId), Rlp.Encode(request.Number),
                                                      Rlp.Encode(_timestamper.EpochSeconds)));

            if (!_receiptRequestValidator.IsValid(request, session.UnpaidUnits, session.ConsumedUnits,
                                                  deposit.Deposit.Units))
            {
                if (_logger.IsWarn)
                {
                    _logger.Warn($"Provider: '{providerPeer.NodeId}' sent an invalid data delivery receipt request.");
                }
                var receipt = new DataDeliveryReceipt(StatusCodes.InvalidReceiptRequestRange,
                                                      session.ConsumedUnits, session.UnpaidUnits, new Signature(1, 1, 27));
                await _receiptRepository.AddAsync(new DataDeliveryReceiptDetails(receiptId, session.Id,
                                                                                 session.DataAssetId, _nodePublicKey, request, receipt, _timestamper.EpochSeconds, false));

                await _sessionRepository.UpdateAsync(session);

                providerPeer.SendDataDeliveryReceipt(depositId, receipt);
                return;
            }

            var abiHash = _abiEncoder.Encode(AbiEncodingStyle.Packed, _dataDeliveryReceiptAbiSig,
                                             depositId.Bytes, new[] { request.UnitsRange.From, request.UnitsRange.To });
            var receiptHash      = Keccak.Compute(abiHash);
            var signature        = _wallet.Sign(receiptHash, deposit.Consumer);
            var recoveredAddress = _ecdsa.RecoverPublicKey(signature, receiptHash)?.Address;

            if (deposit.Consumer != recoveredAddress)
            {
                if (_logger.IsError)
                {
                    _logger.Error($"Signature failure when signing the receipt from provider: '{providerPeer.NodeId}', invalid recovered address.");
                }
                var receipt = new DataDeliveryReceipt(StatusCodes.InvalidReceiptAddress,
                                                      session.ConsumedUnits, session.UnpaidUnits, new Signature(1, 1, 27));
                await _receiptRepository.AddAsync(new DataDeliveryReceiptDetails(receiptId, session.Id,
                                                                                 session.DataAssetId, _nodePublicKey, request, receipt, _timestamper.EpochSeconds, false));

                await _sessionRepository.UpdateAsync(session);

                providerPeer.SendDataDeliveryReceipt(depositId, receipt);
                return;
            }

            if (_logger.IsInfo)
            {
                _logger.Info($"Provider: '{providerPeer.NodeId}' sent a valid data delivery receipt request.");
            }
            if (request.ReceiptsToMerge.Any())
            {
                if (_logger.IsInfo)
                {
                    _logger.Info($"Processing a merged receipt request for deposit: {session.DepositId}, session: '{session.Id} - units will not be updated.");
                }
            }
            else
            {
                var paidUnits   = request.UnitsRange.To - request.UnitsRange.From + 1;
                var unpaidUnits = session.UnpaidUnits > paidUnits ? session.UnpaidUnits - paidUnits : 0;
                session.SetUnpaidUnits(unpaidUnits);
                session.AddPaidUnits(paidUnits);
                if (request.IsSettlement)
                {
                    session.SetPaidUnits(paidUnits);
                    session.SettleUnits(paidUnits);
                    if (_logger.IsInfo)
                    {
                        _logger.Info($"Settled {paidUnits} units for deposit: '{session.DepositId}', session: '{session.Id}'.");
                    }
                }

                await _sessionRepository.UpdateAsync(session);
            }

            if (_logger.IsInfo)
            {
                _logger.Info($"Sending data delivery receipt for deposit: '{depositId}', range: [{request.UnitsRange.From}, {request.UnitsRange.To}].");
            }
            var deliveryReceipt = new DataDeliveryReceipt(StatusCodes.Ok, session.ConsumedUnits,
                                                          session.UnpaidUnits, signature);
            await _receiptRepository.AddAsync(new DataDeliveryReceiptDetails(receiptId, session.Id,
                                                                             session.DataAssetId, _nodePublicKey, request, deliveryReceipt, _timestamper.EpochSeconds, false));

            providerPeer.SendDataDeliveryReceipt(depositId, deliveryReceipt);
            if (_logger.IsInfo)
            {
                _logger.Info($"Sent data delivery receipt for deposit: '{depositId}', range: [{request.UnitsRange.From}, {request.UnitsRange.To}].");
            }
        }