private async Task <IEnumerable <AccountedPaymentEntity> > GetPaymentsWithTransaction(BTCPayNetwork network, InvoiceEntity invoice) { var transactions = await _Wallet.GetTransactions(network, invoice.Payments.Select(t => t.Outpoint.Hash).ToArray()); var spentTxIn = new Dictionary <OutPoint, AccountedPaymentEntity>(); var result = invoice.Payments.Select(p => p.Outpoint).ToHashSet(); List <AccountedPaymentEntity> payments = new List <AccountedPaymentEntity>(); foreach (var payment in invoice.Payments) { TransactionResult tx; if (!transactions.TryGetValue(payment.Outpoint.Hash, out tx)) { result.Remove(payment.Outpoint); continue; } AccountedPaymentEntity accountedPayment = new AccountedPaymentEntity() { Confirmations = tx.Confirmations, Transaction = tx.Transaction, Payment = payment }; payments.Add(accountedPayment); foreach (var txin in tx.Transaction.Inputs) { if (!spentTxIn.TryAdd(txin.PrevOut, accountedPayment)) { //We get a double spend var existing = spentTxIn[txin.PrevOut]; //Take the most recent, the full node is already comparing fees correctly so we have the most likely to be confirmed if (accountedPayment.Confirmations > 1 || existing.Payment.ReceivedTime < accountedPayment.Payment.ReceivedTime) { spentTxIn[txin.PrevOut] = accountedPayment; result.Remove(existing.Payment.Outpoint); } } } } List <PaymentEntity> updated = new List <PaymentEntity>(); var accountedPayments = payments.Where(p => { var accounted = result.Contains(p.Payment.Outpoint); if (p.Payment.Accounted != accounted) { p.Payment.Accounted = accounted; updated.Add(p.Payment); } return(accounted); }).ToArray(); await _InvoiceRepository.UpdatePayments(payments); return(accountedPayments); }
private async Task <IEnumerable <AccountedPaymentEntity> > GetPaymentsWithTransaction(DerivationStrategy[] derivations, InvoiceEntity invoice) { List <PaymentEntity> updatedPaymentEntities = new List <PaymentEntity>(); List <AccountedPaymentEntity> accountedPayments = new List <AccountedPaymentEntity>(); foreach (var network in derivations.Select(d => d.Network)) { var wallet = _WalletProvider.GetWallet(network); if (wallet == null) { continue; } var transactions = await wallet.GetTransactions(invoice.GetPayments(wallet.Network) .Select(t => t.Outpoint.Hash) .ToArray()); var conflicts = GetConflicts(transactions.Select(t => t.Value)); foreach (var payment in invoice.GetPayments(network)) { if (!transactions.TryGetValue(payment.Outpoint.Hash, out TransactionResult tx)) { continue; } AccountedPaymentEntity accountedPayment = new AccountedPaymentEntity() { Confirmations = tx.Confirmations, Transaction = tx.Transaction, Payment = payment }; var txId = accountedPayment.Transaction.GetHash(); var txConflict = conflicts.GetConflict(txId); var accounted = txConflict == null || txConflict.IsWinner(txId); if (accounted != payment.Accounted) { updatedPaymentEntities.Add(payment); payment.Accounted = accounted; } if (accounted) { accountedPayments.Add(accountedPayment); } } } await _InvoiceRepository.UpdatePayments(updatedPaymentEntities); return(accountedPayments); }