public async Task <IActionResult> GetTransactionsCacheState() { try { return(Ok(await _transactionStateCacheManager.GetAsync())); } catch (Exception ex) { _log.Error(ex); } return(StatusCode((int)HttpStatusCode.InternalServerError)); }
public async Task ExecuteAsync() { IEnumerable <TransactionState> cacheState = await _cacheMaintainer.GetAsync(); foreach (TransactionState cacheTxState in cacheState) { BcnTransaction cacheTx = cacheTxState.Transaction; if (cacheTx.Blockchain != BlockchainType.Bitcoin) { continue; } GetTransactionResponse bcnTransactionState; try { bcnTransactionState = await _qBitNinjaClient.GetTransaction(new uint256(cacheTx.Id)); } catch (Exception ex) { _log.Error(ex, "Getting transaction from ninja", cacheTxState.ToDetails()); continue; } // if transaction has not been indexed by ninja yet if (bcnTransactionState == null) { continue; } BcnTransaction bcnTx = bcnTransactionState.ToDomain(); DiffResult <BcnTransaction> diffResult = _diffService.Diff(cacheTx, bcnTx); if (diffResult != null) { var tx = diffResult.Object; switch (diffResult.CompareState) { case DiffState.New: _log.Warning("New transactions are not supported by watcher", context: tx.ToDetails()); break; case DiffState.Updated: UpdateTransactionRequest updateRequest = null; try { updateRequest = tx.ToUpdateRequest(bcnTransactionState.FirstSeen.DateTime); await _log.LogPayInternalExceptionIfAny(() => _payInternalClient.UpdateTransactionAsync(updateRequest)); } catch (Exception ex) { _log.Error(ex, context: updateRequest.ToDetails()); } break; default: throw new Exception("Unknown transactions diff state"); } cacheTxState.Transaction = bcnTx; try { await _cacheMaintainer.SetItemAsync(cacheTxState); } catch (Exception ex) { _log.Error(ex, "Updating transaction cache", cacheTxState.ToDetails()); continue; } } } }
public async Task ExecuteAsync() { IEnumerable <WalletState> cacheState = await _cacheMaintainer.GetAsync(); foreach (var walletState in cacheState) { if (walletState.Blockchain != BlockchainType.Bitcoin) { continue; } BalanceModel balance; try { balance = await _qBitNinjaClient.GetBalance(BitcoinAddress.Create(walletState.Address)); } catch (Exception ex) { _log.Error(ex, "Getting balance from ninja", walletState.ToDetails()); continue; } IEnumerable <PaymentBcnTransaction> bcnTransactions = GetIncomingPaymentOperations(balance, walletState.Address)?.ToList() ?? new List <PaymentBcnTransaction>(); IEnumerable <PaymentBcnTransaction> cacheTransactions = walletState.Transactions; IEnumerable <DiffResult <PaymentBcnTransaction> > diff = _diffService.Diff(cacheTransactions, bcnTransactions); // catching case when ninja returns no transactions but should if (cacheTransactions.Any() && !bcnTransactions.Any()) { _log.Info("There are no transactions from ninja, but there are transactions in cache", $"wallet: {walletState.Address}, walletState: {walletState.ToJson()}"); } // catching case when there are any differences between ninja state and local cache state if (diff.Any()) { _log.Info("The difference between cache state and ninja detected", $"wallet: {walletState.Address}, old txs: {walletState.Transactions.ToJson()}, new txs: {bcnTransactions.ToJson()}"); } // approach to exit loop with switch statement inside bool isSyncError = false; foreach (var diffResult in diff) { var tx = diffResult.Object; switch (diffResult.CompareState) { case DiffState.New: CreateTransactionRequest createRequest = null; try { var txDetails = await _qBitNinjaClient.GetTransaction(new uint256(tx.Id)); createRequest = tx.ToCreateRequest(txDetails, _bitcoinNetwork); _log.Info("New transaction detected", $"wallet: {walletState.Address}, Hash: {tx.Id}, FirstSeen: {txDetails.FirstSeen}"); await _log.LogPayInternalExceptionIfAny(() => _payInternalClient.CreatePaymentTransactionAsync(createRequest)); } catch (Exception ex) { _log.Error(ex, context: createRequest.ToDetails()); isSyncError = true; } break; case DiffState.Updated: UpdateTransactionRequest updateRequest = null; try { updateRequest = tx.ToUpdateRequest(); _log.Info("Transaction update detected", $"wallet: {walletState.Address}, new tx state: {tx.ToJson()}"); await _log.LogPayInternalExceptionIfAny(() => _payInternalClient.UpdateTransactionAsync(updateRequest)); } catch (Exception ex) { _log.Error(ex, context: updateRequest.ToDetails()); isSyncError = true; } break; default: throw new Exception("Unknown transactions diff state"); } // stop changes processing in case there is PayInternal sync error if (isSyncError) { break; } } if (bcnTransactions.Any()) { walletState.Transactions = bcnTransactions; } // will sync internal cache with blockchain only if there were no errors while processing changes // otherwise the changes will be processed again in the next job cycle // WARNING: the approach will work only for single transactions update if (!isSyncError) { try { await _cacheMaintainer.SetItemAsync(walletState); } catch (Exception ex) { _log.Error(ex, "Updating wallets cache", walletState.ToDetails()); continue; } } } }