private async Task <(ConsumerSession session, DepositDetails deposit)> TryGetSessionAndDepositAsync( Keccak depositId) { var session = _sessionService.GetActive(depositId); if (session is null) { if (_logger.IsInfo) { _logger.Info($"Session for deposit: '{depositId}' was not found."); } return(null, null); } var deposit = await _depositProvider.GetAsync(depositId); if (deposit is null) { if (_logger.IsInfo) { _logger.Info($"Deposit: '{depositId}' was not found."); } return(session, null); } return(session, deposit); }
public void Setup() { IConsumerNotifier notifier = new ConsumerNotifier(Substitute.For <INdmNotifier>()); DepositsInMemoryDb db = new DepositsInMemoryDb(); IProviderRepository providerRepository = new ProviderInMemoryRepository(db); DataAssetProvider provider = new DataAssetProvider(_providerAddress, "provider"); DataAssetService dataAssetService = new DataAssetService(providerRepository, notifier, LimboLogs.Instance); _asset1 = new DataAsset(_asset1Id, "name", "desc", 1, DataAssetUnitType.Unit, 1000, 10000, new DataAssetRules(new DataAssetRule(1), new DataAssetRule(100)), provider, state: DataAssetState.Published); dataAssetService.AddDiscovered(_asset1, _ndmPeer); _deposit1 = new Deposit(_deposit1Id, 1, 2, 3); _details1 = new DepositDetails(_deposit1, _asset1, Address.Zero, new byte[0], 1, new TransactionInfo[0], 1); _asset2 = new DataAsset(_asset2Id, "name", "desc", 1, DataAssetUnitType.Time, 1000, 10000, new DataAssetRules(new DataAssetRule(1)), provider, state: DataAssetState.Published); dataAssetService.AddDiscovered(_asset2, _ndmPeer); _deposit2 = new Deposit(_deposit2Id, 1, 2, 3); _details2 = new DepositDetails(_deposit2, _asset2, Address.Zero, new byte[0], 1, new TransactionInfo[0], 2); _closed = new DataAsset(_closedId, "name", "desc", 1, DataAssetUnitType.Unit, 1000, 10000, new DataAssetRules(new DataAssetRule(1)), provider, state: DataAssetState.Closed); dataAssetService.AddDiscovered(_closed, _ndmPeer); _depositForClosed = new Deposit(_depositForClosedId, 1, 2, 3); _depositForClosedDetails = new DepositDetails(_depositForClosed, _closed, Address.Zero, new byte[0], 1, new TransactionInfo[0]); _missingAsset = new DataAsset(_missingAssetId, "name", "desc", 1, DataAssetUnitType.Unit, 1000, 10000, new DataAssetRules(new DataAssetRule(1)), provider, state: DataAssetState.Published); _depositForMissing = new Deposit(_depositForMissingId, 1, 2, 3); _depositForMissingDetails = new DepositDetails(_depositForMissing, _missingAsset, Address.Zero, new byte[0], 1, new TransactionInfo[0]); IDepositProvider depositProvider = Substitute.For <IDepositProvider>(); depositProvider.GetAsync(_deposit1Id).Returns(_details1); depositProvider.GetAsync(_deposit2Id).Returns(_details2); depositProvider.GetAsync(_depositForMissingId).Returns(_depositForMissingDetails); depositProvider.GetAsync(_depositForClosedId).Returns(_depositForClosedDetails); _ndmPeer = Substitute.For <INdmPeer>(); _ndmPeer.ProviderAddress.Returns(_providerAddress); _ndmPeer.NodeId.Returns(_providerNodeId); _providerService = new ProviderService(providerRepository, notifier, LimboLogs.Instance); _providerService.Add(_ndmPeer); _sessionRepository = new ConsumerSessionInMemoryRepository(); _sessionService = new SessionService(_providerService, depositProvider, dataAssetService, _sessionRepository, Timestamper.Default, notifier, LimboLogs.Instance); }
public async Task send_should_fail_if_active_session_does_not_exist(int fetchSessionRetries) { const int fetchSessionRetryDelayMilliseconds = 100; var receipt = GetDataDeliveryReceiptRequest(); var deposit = GetDepositDetails(); _depositProvider.GetAsync(receipt.DepositId).Returns(deposit); var stopwatch = new Stopwatch(); stopwatch.Start(); await _receiptService.SendAsync(receipt, fetchSessionRetries, fetchSessionRetryDelayMilliseconds); stopwatch.Stop(); var expectedTime = 0.9 * fetchSessionRetryDelayMilliseconds * fetchSessionRetries; stopwatch.ElapsedMilliseconds.Should().BeGreaterOrEqualTo((long)expectedTime); await _depositProvider.Received().GetAsync(receipt.DepositId); _sessionService.Received(fetchSessionRetries + 1).GetActive(receipt.DepositId); }
public async Task disable_data_stream_should_fail_for_locked_account() { var depositId = Keccak.Zero; var client = "test"; var session = GetConsumerSession(); var deposit = GetDepositDetails(); _sessionService.GetActive(depositId).Returns(session); _providerService.GetPeer(session.ProviderAddress).Returns(_providerPeer); _depositProvider.GetAsync(session.DepositId).Returns(deposit); var result = await _dataStreamService.DisableDataStreamAsync(depositId, client); result.Should().BeNull(); _providerPeer.DidNotReceive().SendDisableDataStream(depositId, client); _sessionService.Received(1).GetActive(depositId); _providerService.Received(1).GetPeer(session.ProviderAddress); await _depositProvider.Received(1).GetAsync(session.DepositId); _wallet.Received(1).IsUnlocked(deposit.Consumer); }
private async Task <(DepositDetails deposit, ConsumerSession session)> TryGetDepositAndSessionAsync( Keccak depositId, int fetchSessionRetries = 5, int fetchSessionRetryDelayMilliseconds = 3000) { var deposit = await _depositProvider.GetAsync(depositId); if (deposit is null) { if (_logger.IsInfo) { _logger.Info($"Deposit: '{depositId}' was not found."); } return(null, null); } var session = _sessionService.GetActive(depositId); if (!(session is null)) { return(deposit, session); } if (fetchSessionRetries <= 0) { return(deposit, null); } var retry = 0; while (retry < fetchSessionRetries) { retry++; if (_logger.IsTrace) { _logger.Trace($"Retrying ({retry}/{fetchSessionRetries}) fetching an active session for deposit: {deposit} in {fetchSessionRetryDelayMilliseconds} ms..."); } await Task.Delay(fetchSessionRetryDelayMilliseconds); session = _sessionService.GetActive(depositId); if (session is null) { continue; } if (_logger.IsInfo) { _logger.Info($"Found an active session: '{session.Id}' for deposit: '{deposit.Id}'."); } break; } return((session is null) ? (deposit, null) : (deposit, session)); }
private async Task VerifyUnitsAsync(DataAssetUnitType unitType, uint paidUnits, Func <DepositDetails, Session, uint> expectedConsumedUnits, Func <DepositDetails, Session, uint> expectedUnpaidUnits) { var depositId = Keccak.Zero; var consumedUnitsFromProvider = 10u; var session = GetConsumerSession(paidUnits); var deposit = GetDepositDetails(unitType); _sessionService.GetActive(depositId).Returns(session); _depositProvider.GetAsync(session.DepositId).Returns(deposit); await _dataConsumerService.SetUnitsAsync(depositId, consumedUnitsFromProvider); session.ConsumedUnitsFromProvider.Should().Be(consumedUnitsFromProvider); session.ConsumedUnits.Should().Be(expectedConsumedUnits(deposit, session)); session.UnpaidUnits.Should().Be(expectedUnpaidUnits(deposit, session)); await _depositProvider.Received(1).GetAsync(depositId); _sessionService.Received(1).GetActive(depositId); await _sessionRepository.Received(1).UpdateAsync(session); }
private async Task <(DepositDetails deposit, ConsumerSession session)> TryGetDepositAndSessionAsync( Keccak depositId) { var deposit = await _depositProvider.GetAsync(depositId); if (deposit is null) { if (_logger.IsInfo) { _logger.Info($"Deposit: '{depositId}' was not found."); } return(null, null); } var session = _sessionService.GetActive(depositId); return((session is null) ? (deposit, null) : (deposit, session)); }
public async Task send_data_request_should_fail_for_locked_account() { var depositId = Keccak.Zero; var deposit = GetDepositDetails(); _depositProvider.GetAsync(depositId).Returns(deposit); var result = await _dataRequestService.SendAsync(depositId); result.Should().Be(DataRequestResult.ConsumerAccountLocked); await _depositProvider.Received(1).GetAsync(depositId); _wallet.Received(1).IsUnlocked(deposit.Consumer); }
public async Task <DataRequestResult> SendAsync(Keccak depositId) { var deposit = await _depositProvider.GetAsync(depositId); if (deposit is null) { return(DataRequestResult.DepositNotFound); } if (!_wallet.IsUnlocked(deposit.Consumer)) { if (_logger.IsWarn) { _logger.Warn($"Account: '{deposit.Consumer}' is locked, can't send a data request."); } return(DataRequestResult.ConsumerAccountLocked); } if (deposit.DataAsset.KycRequired && !(await _kycVerifier.IsVerifiedAsync(deposit.DataAsset.Id, deposit.Consumer))) { if (_logger.IsWarn) { _logger.Warn($"Deposit with id: '{depositId}' has unconfirmed KYC.'"); } return(DataRequestResult.KycUnconfirmed); } if (!deposit.Confirmed) { if (_logger.IsWarn) { _logger.Warn($"Deposit with id: '{depositId}' is unconfirmed.'"); } return(DataRequestResult.DepositUnconfirmed); } if (deposit.IsExpired((uint)_timestamper.EpochSeconds)) { if (_logger.IsWarn) { _logger.Warn($"Deposit with id: '{depositId}' is expired.'"); } return(DataRequestResult.DepositExpired); } var providerPeer = _providerService.GetPeer(deposit.DataAsset.Provider.Address); if (providerPeer is null) { return(DataRequestResult.ProviderNotFound); } var sessions = await _sessionRepository.BrowseAsync(new GetConsumerSessions { DepositId = depositId, Results = int.MaxValue }); var consumedUnits = sessions.Items.Any() ? (uint)sessions.Items.Sum(s => s.ConsumedUnits) : 0; var dataRequest = CreateDataRequest(deposit); if (_logger.IsInfo) { _logger.Info($"Sending data request for deposit with id: '{depositId}', consumed units: {consumedUnits}, address: '{dataRequest.Consumer}'."); } var result = await providerPeer.SendDataRequestAsync(dataRequest, consumedUnits); if (_logger.IsInfo) { _logger.Info($"Received data request result: '{result}' for data asset: '{dataRequest.DataAssetId}', deposit: '{depositId}', consumed units: {consumedUnits}, address: '{dataRequest.Consumer}'."); } await _consumerNotifier.SendDataRequestResultAsync(depositId, result); return(result); }
public async Task StartSessionAsync(Session session, INdmPeer provider) { // var providerPeer = _providerService.GetPeer(provider.ProviderAddress); // if (!_providers.TryGetValue(provider.NodeId, out var providerPeer)) // { // if (_logger.IsWarn) _logger.Warn($"Cannot start the session: '{session.Id}', provider: '{provider.NodeId}' was not found."); // // return; // } var deposit = await _depositProvider.GetAsync(session.DepositId); if (deposit is null) { if (_logger.IsWarn) { _logger.Warn($"Cannot start the session: '{session.Id}', deposit: '{session.DepositId}' was not found."); } return; } var dataAssetId = deposit.DataAsset.Id; var dataAsset = _dataAssetService.GetDiscovered(dataAssetId); if (dataAsset is null) { if (_logger.IsWarn) { _logger.Warn($"Available data asset: '{dataAssetId}' was not found."); } return; } if (!_dataAssetService.IsAvailable(dataAsset)) { if (_logger.IsWarn) { _logger.Warn($"Data asset: '{dataAssetId}' is unavailable, state: {dataAsset.State}."); } return; } if (!provider.ProviderAddress.Equals(deposit.DataAsset.Provider.Address)) { if (_logger.IsWarn) { _logger.Warn($"Cannot start the session: '{session.Id}' for deposit: '{session.DepositId}', provider address (peer): '{provider.ProviderAddress}' doesn't equal the address from data asset: '{deposit.DataAsset.Provider.Address}'."); } return; } var sessions = await _sessionRepository.BrowseAsync(new GetConsumerSessions { DepositId = session.DepositId, Results = int.MaxValue }); var consumedUnits = sessions.Items.Any() ? (uint)sessions.Items.Sum(s => s.ConsumedUnits) : 0; if (_logger.IsInfo) { _logger.Info($"Starting the session: '{session.Id}' for deposit: '{session.DepositId}'. Settings consumed units - provider: {session.StartUnitsFromProvider}, consumer: {consumedUnits}."); } var consumerSession = ConsumerSession.From(session); consumerSession.Start(session.StartTimestamp); var previousSession = await _sessionRepository.GetPreviousAsync(consumerSession); var upfrontUnits = (uint)(deposit.DataAsset.Rules.UpfrontPayment?.Value ?? 0); if (upfrontUnits > 0 && previousSession is null) { consumerSession.AddUnpaidUnits(upfrontUnits); if (_logger.IsInfo) { _logger.Info($"Unpaid units: {upfrontUnits} for session: '{session.Id}' based on upfront payment."); } } var unpaidUnits = previousSession?.UnpaidUnits ?? 0; if (unpaidUnits > 0 && !(previousSession is null)) { consumerSession.AddUnpaidUnits(unpaidUnits); if (_logger.IsInfo) { _logger.Info($"Unpaid units: {unpaidUnits} for session: '{session.Id}' from previous session: '{previousSession.Id}'."); } } if (deposit.DataAsset.UnitType == DataAssetUnitType.Time) { var unpaidTimeUnits = (uint)consumerSession.StartTimestamp - deposit.ConfirmationTimestamp; consumerSession.AddUnpaidUnits(unpaidTimeUnits); if (_logger.IsInfo) { _logger.Info($"Unpaid units: '{unpaidTimeUnits}' for deposit: '{session.DepositId}' based on time."); } } SetActiveSession(consumerSession); await _sessionRepository.AddAsync(consumerSession); await _consumerNotifier.SendSessionStartedAsync(session.DepositId, session.Id); if (_logger.IsInfo) { _logger.Info($"Started a session with id: '{session.Id}' for deposit: '{session.DepositId}', address: '{deposit.Consumer}'."); } }
public async Task StartSessionAsync(Session session, INdmPeer provider) { DepositDetails?deposit = await _depositProvider.GetAsync(session.DepositId); if (deposit is null) { if (_logger.IsWarn) { _logger.Warn($"Cannot start the session: '{session.Id}', deposit: '{session.DepositId}' was not found."); } return; } if (session.StartTimestamp < deposit.ConfirmationTimestamp) { if (_logger.IsWarn) { _logger.Warn($"Cannot start the session: '{session.Id}', session timestamp {session.StartTimestamp} is before deposit confirmation timestamp {deposit.ConfirmationTimestamp}."); } return; } Keccak dataAssetId = deposit.DataAsset.Id; if (dataAssetId != session.DataAssetId) { if (_logger.IsWarn) { _logger.Warn($"Inconsistent data - data asset ID on deposit is '{dataAssetId}' while on session is '{session.DataAssetId}'."); } return; } DataAsset?dataAsset = _dataAssetService.GetDiscovered(dataAssetId); if (dataAsset is null) { if (_logger.IsWarn) { _logger.Warn($"Available data asset: '{dataAssetId}' was not found."); } return; } if (!_dataAssetService.IsAvailable(dataAsset)) { if (_logger.IsWarn) { _logger.Warn($"Data asset: '{dataAssetId}' is unavailable, state: {dataAsset.State}."); } return; } if (session.ProviderAddress == null) { if (_logger.IsWarn) { _logger.Warn($"Session: '{session.Id}' for '{session.DepositId}' cannot be started because of the unknown provider address."); } return; } if (!provider.ProviderAddress !.Equals(deposit.DataAsset.Provider.Address)) { if (_logger.IsWarn) { _logger.Warn($"Cannot start the session: '{session.Id}' for deposit: '{session.DepositId}', provider address (peer): '{provider.ProviderAddress}' doesn't equal the address from data asset: '{deposit.DataAsset.Provider.Address}'."); } return; } PagedResult <ConsumerSession> sessions = await _sessionRepository.BrowseAsync(new GetConsumerSessions { DepositId = session.DepositId, Results = int.MaxValue }); uint consumedUnits = sessions.Items.Any() ? (uint)sessions.Items.Sum(s => s.ConsumedUnits) : 0; if (_logger.IsInfo) { _logger.Info($"Starting the session: '{session.Id}' for deposit: '{session.DepositId}'. Settings consumed units - provider: {session.StartUnitsFromProvider}, consumer: {consumedUnits}."); } ConsumerSession consumerSession = ConsumerSession.From(session); consumerSession.Start(session.StartTimestamp); ConsumerSession?previousSession = await _sessionRepository.GetPreviousAsync(consumerSession); uint upfrontUnits = (uint)(deposit.DataAsset.Rules.UpfrontPayment?.Value ?? 0); if (upfrontUnits > 0 && previousSession is null) { consumerSession.AddUnpaidUnits(upfrontUnits); if (_logger.IsInfo) { _logger.Info($"Unpaid units: {upfrontUnits} for session: '{session.Id}' based on upfront payment."); } } uint unpaidUnits = previousSession?.UnpaidUnits ?? 0; if (unpaidUnits > 0 && !(previousSession is null)) { consumerSession.AddUnpaidUnits(unpaidUnits); if (_logger.IsInfo) { _logger.Info($"Unpaid units: {unpaidUnits} for session: '{session.Id}' from previous session: '{previousSession.Id}'."); } } if (deposit.DataAsset.UnitType == DataAssetUnitType.Time) { uint unpaidTimeUnits = (uint)consumerSession.StartTimestamp - deposit.ConfirmationTimestamp; consumerSession.AddUnpaidUnits(unpaidTimeUnits); if (_logger.IsInfo) { _logger.Info($"Unpaid units: '{unpaidTimeUnits}' for deposit: '{session.DepositId}' based on time."); } } SetActiveSession(consumerSession); await _sessionRepository.AddAsync(consumerSession); await _consumerNotifier.SendSessionStartedAsync(session.DepositId, session.Id); if (_logger.IsInfo) { _logger.Info($"Started a session with id: '{session.Id}' for deposit: '{session.DepositId}', address: '{deposit.Consumer}'."); } }
private async Task <Keccak?> ToggleDataStreamAsync(Keccak depositId, bool enable, string client, string[]?args = null) { ConsumerSession?session = _sessionService.GetActive(depositId); if (session is null) { if (_logger.IsWarn) { _logger.Warn($"Session for deposit: '{depositId}' was not found."); } return(null); } INdmPeer?provider = _providerService.GetPeer(session.ProviderAddress); if (provider is null) { if (_logger.IsWarn) { _logger.Warn($"Provider for address: '{session.ProviderAddress}' was not found."); } return(null); } DepositDetails?deposit = await _depositProvider.GetAsync(session.DepositId); if (deposit is null) { if (_logger.IsWarn) { _logger.Warn($"Cannot toggle data stream, deposit: '{session.DepositId}' was not found."); } return(null); } if (!_wallet.IsUnlocked(deposit.Consumer)) { if (_logger.IsWarn) { _logger.Warn($"Cannot toggle data stream for deposit: '{session.DepositId}', account: '{deposit.Consumer}' is locked."); } return(null); } Keccak dataAssetId = deposit.DataAsset.Id; DataAsset?dataAsset = _dataAssetService.GetDiscovered(dataAssetId); if (dataAsset is null) { if (_logger.IsWarn) { _logger.Warn($"Data asset: '{dataAssetId}' was not found."); } return(null); } if (!_dataAssetService.IsAvailable(dataAsset)) { if (_logger.IsWarn) { _logger.Warn($"Data asset: '{dataAssetId}' is unavailable, state: {dataAsset.State}."); } return(null); } if (!enable) { if (_logger.IsInfo) { _logger.Info($"Sending disable data stream for deposit: '{depositId}', client: '{client}'."); } provider.SendDisableDataStream(depositId, client); return(depositId); } switch (dataAsset.QueryType) { case QueryType.Stream: { if (session.GetClient(client)?.StreamEnabled == true) { if (_logger.IsInfo) { _logger.Info($"Disabling an existing data stream for deposit: '{depositId}', client: '{client}'."); } provider.SendDisableDataStream(depositId, client); } if (_logger.IsInfo) { _logger.Info($"Sending enable data stream for deposit: '{depositId}', client: '{client}'."); } break; } case QueryType.Query: { Metrics.SentQueries++; if (_logger.IsInfo) { _logger.Info($"Sending the data query for deposit: '{depositId}', client: '{client}'."); } break; } default: { throw new InvalidOperationException($"Not supported data asset type: {dataAsset.QueryType}."); } } provider.SendEnableDataStream(depositId, client, args ?? Array.Empty <string>()); return(depositId); }