mirror of
https://github.com/btcpayserver/btcpayserver.git
synced 2025-02-22 06:21:44 +01:00
Merge pull request #861 from rockstardev/extendconfcount
Extending invoice monitoring time if we haven't reached MaxTrackedConfirmation
This commit is contained in:
commit
a2251d245f
3 changed files with 80 additions and 23 deletions
|
@ -288,31 +288,18 @@ namespace BTCPayServer.HostedServices
|
|||
if (invoice.Status == InvoiceStatus.Complete ||
|
||||
((invoice.Status == InvoiceStatus.Invalid || invoice.Status == InvoiceStatus.Expired) && invoice.MonitoringExpiration < DateTimeOffset.UtcNow))
|
||||
{
|
||||
var updateConfirmationCountIfNeeded = invoice
|
||||
.GetPayments()
|
||||
.Select<PaymentEntity, Task>(async payment =>
|
||||
{
|
||||
var paymentNetwork = _NetworkProvider.GetNetwork(payment.GetCryptoCode());
|
||||
var paymentData = payment.GetCryptoPaymentData();
|
||||
if (paymentData is Payments.Bitcoin.BitcoinLikePaymentData onChainPaymentData)
|
||||
{
|
||||
// Do update if confirmation count in the paymentData is not up to date
|
||||
if ((onChainPaymentData.ConfirmationCount < paymentNetwork.MaxTrackedConfirmation && payment.Accounted)
|
||||
&& (onChainPaymentData.Legacy || invoice.MonitoringExpiration < DateTimeOffset.UtcNow))
|
||||
{
|
||||
var transactionResult = await _ExplorerClientProvider.GetExplorerClient(payment.GetCryptoCode())?.GetTransactionAsync(onChainPaymentData.Outpoint.Hash);
|
||||
var confirmationCount = transactionResult?.Confirmations ?? 0;
|
||||
onChainPaymentData.ConfirmationCount = confirmationCount;
|
||||
payment.SetCryptoPaymentData(onChainPaymentData);
|
||||
await _InvoiceRepository.UpdatePayments(new List<PaymentEntity> { payment });
|
||||
}
|
||||
}
|
||||
})
|
||||
.ToArray();
|
||||
await Task.WhenAll(updateConfirmationCountIfNeeded);
|
||||
var extendInvoiceMonitoring = await UpdateConfirmationCount(invoice);
|
||||
|
||||
if (await _InvoiceRepository.RemovePendingInvoice(invoice.Id))
|
||||
// we extend monitor time if we haven't reached max confirmation count
|
||||
// say user used low fee and we only got 3 confirmations right before it's time to remove
|
||||
if (extendInvoiceMonitoring)
|
||||
{
|
||||
await _InvoiceRepository.ExtendInvoiceMonitor(invoice.Id);
|
||||
}
|
||||
else if (await _InvoiceRepository.RemovePendingInvoice(invoice.Id))
|
||||
{
|
||||
_EventAggregator.Publish(new InvoiceStopWatchedEvent(invoice.Id));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -330,6 +317,46 @@ namespace BTCPayServer.HostedServices
|
|||
}
|
||||
}
|
||||
|
||||
private async Task<bool> UpdateConfirmationCount(InvoiceEntity invoice)
|
||||
{
|
||||
bool extendInvoiceMonitoring = false;
|
||||
var updateConfirmationCountIfNeeded = invoice
|
||||
.GetPayments()
|
||||
.Select<PaymentEntity, Task<PaymentEntity>>(async payment =>
|
||||
{
|
||||
var paymentNetwork = _NetworkProvider.GetNetwork(payment.GetCryptoCode());
|
||||
var paymentData = payment.GetCryptoPaymentData();
|
||||
if (paymentData is Payments.Bitcoin.BitcoinLikePaymentData onChainPaymentData)
|
||||
{
|
||||
// Do update if confirmation count in the paymentData is not up to date
|
||||
if ((onChainPaymentData.ConfirmationCount < paymentNetwork.MaxTrackedConfirmation && payment.Accounted)
|
||||
&& (onChainPaymentData.Legacy || invoice.MonitoringExpiration < DateTimeOffset.UtcNow))
|
||||
{
|
||||
var transactionResult = await _ExplorerClientProvider.GetExplorerClient(payment.GetCryptoCode())?.GetTransactionAsync(onChainPaymentData.Outpoint.Hash);
|
||||
var confirmationCount = transactionResult?.Confirmations ?? 0;
|
||||
onChainPaymentData.ConfirmationCount = confirmationCount;
|
||||
payment.SetCryptoPaymentData(onChainPaymentData);
|
||||
|
||||
// we want to extend invoice monitoring until we reach max confirmations on all onchain payment methods
|
||||
if (confirmationCount < paymentNetwork.MaxTrackedConfirmation)
|
||||
extendInvoiceMonitoring = true;
|
||||
|
||||
return payment;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
})
|
||||
.ToArray();
|
||||
await Task.WhenAll(updateConfirmationCountIfNeeded);
|
||||
var updatedPaymentData = updateConfirmationCountIfNeeded.Where(a => a.Result != null).Select(a => a.Result).ToList();
|
||||
if (updatedPaymentData.Count > 0)
|
||||
{
|
||||
await _InvoiceRepository.UpdatePayments(updatedPaymentData);
|
||||
}
|
||||
|
||||
return extendInvoiceMonitoring;
|
||||
}
|
||||
|
||||
public async Task StopAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
if (_Cts == null)
|
||||
|
|
|
@ -238,6 +238,10 @@ namespace BTCPayServer.Payments.Bitcoin
|
|||
}
|
||||
}
|
||||
|
||||
// if needed add invoice back to pending to track number of confirmations
|
||||
if (paymentData.ConfirmationCount < wallet.Network.MaxTrackedConfirmation)
|
||||
await _InvoiceRepository.AddPendingInvoiceIfNotPresent(invoice.Id);
|
||||
|
||||
if (updated)
|
||||
updatedPaymentEntities.Add(payment);
|
||||
}
|
||||
|
|
|
@ -120,6 +120,20 @@ retry:
|
|||
}
|
||||
}
|
||||
|
||||
public async Task ExtendInvoiceMonitor(string invoiceId)
|
||||
{
|
||||
using (var ctx = _ContextFactory.CreateContext())
|
||||
{
|
||||
var invoiceData = await ctx.Invoices.FindAsync(invoiceId);
|
||||
|
||||
var invoice = ToObject(invoiceData.Blob);
|
||||
invoice.MonitoringExpiration = invoice.MonitoringExpiration.AddHours(1);
|
||||
invoiceData.Blob = ToBytes(invoice, null);
|
||||
|
||||
await ctx.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<InvoiceEntity> CreateInvoiceAsync(string storeId, InvoiceEntity invoice)
|
||||
{
|
||||
List<string> textSearch = new List<string>();
|
||||
|
@ -260,6 +274,18 @@ retry:
|
|||
}
|
||||
}
|
||||
|
||||
public async Task AddPendingInvoiceIfNotPresent(string invoiceId)
|
||||
{
|
||||
using (var context = _ContextFactory.CreateContext())
|
||||
{
|
||||
if (!context.PendingInvoices.Any(a => a.Id == invoiceId))
|
||||
{
|
||||
context.PendingInvoices.Add(new PendingInvoiceData() { Id = invoiceId });
|
||||
await context.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async Task AddInvoiceEvent(string invoiceId, object evt)
|
||||
{
|
||||
using (var context = _ContextFactory.CreateContext())
|
||||
|
|
Loading…
Add table
Reference in a new issue