From 17e914778d17edb737033525bdf5c42489b853a6 Mon Sep 17 00:00:00 2001 From: "nicolas.dorier" Date: Thu, 21 Jun 2018 14:15:36 +0900 Subject: [PATCH] Make sure that lightning payments events are using the state of the invoice when they got issued (#205) --- .../Controllers/InvoiceController.UI.cs | 7 +++++-- BTCPayServer/Controllers/InvoiceController.cs | 2 +- BTCPayServer/Events/InvoiceEvent.cs | 12 ++++------- .../InvoiceNotificationManager.cs | 2 +- BTCPayServer/HostedServices/InvoiceWatcher.cs | 20 +++++++++---------- .../Payments/Bitcoin/NBXplorerListener.cs | 14 ++++++------- .../Payments/Lightning/LightningListener.cs | 10 +++++++--- 7 files changed, 35 insertions(+), 32 deletions(-) diff --git a/BTCPayServer/Controllers/InvoiceController.UI.cs b/BTCPayServer/Controllers/InvoiceController.UI.cs index 0b04d6a36..da4f32e20 100644 --- a/BTCPayServer/Controllers/InvoiceController.UI.cs +++ b/BTCPayServer/Controllers/InvoiceController.UI.cs @@ -356,7 +356,7 @@ namespace BTCPayServer.Controllers { leases.Add(_EventAggregator.Subscribe(async o => await NotifySocket(webSocket, o.InvoiceId, invoiceId))); leases.Add(_EventAggregator.Subscribe(async o => await NotifySocket(webSocket, o.InvoiceId, invoiceId))); - leases.Add(_EventAggregator.Subscribe(async o => await NotifySocket(webSocket, o.InvoiceId, invoiceId))); + leases.Add(_EventAggregator.Subscribe(async o => await NotifySocket(webSocket, o.Invoice.Id, invoiceId))); while (true) { var message = await webSocket.ReceiveAsync(DummyBuffer, default(CancellationToken)); @@ -535,8 +535,11 @@ namespace BTCPayServer.Controllers [BitpayAPIConstraint(false)] public async Task InvalidatePaidInvoice(string invoiceId) { + var invoice = await _InvoiceRepository.GetInvoice(null, invoiceId); + if (invoice == null) + return NotFound(); await _InvoiceRepository.UpdatePaidInvoiceToInvalid(invoiceId); - _EventAggregator.Publish(new InvoiceEvent(invoiceId, 1008, "invoice_markedInvalid")); + _EventAggregator.Publish(new InvoiceEvent(invoice.EntityToDTO(_NetworkProvider), 1008, "invoice_markedInvalid")); return RedirectToAction(nameof(ListInvoices)); } diff --git a/BTCPayServer/Controllers/InvoiceController.cs b/BTCPayServer/Controllers/InvoiceController.cs index d449aa173..d6dd4dcdd 100644 --- a/BTCPayServer/Controllers/InvoiceController.cs +++ b/BTCPayServer/Controllers/InvoiceController.cs @@ -209,7 +209,7 @@ namespace BTCPayServer.Controllers entity.PosData = invoice.PosData; entity = await _InvoiceRepository.CreateInvoiceAsync(store.Id, entity, paymentMethodErrors, _NetworkProvider); - _EventAggregator.Publish(new Events.InvoiceEvent(entity, 1001, "invoice_created")); + _EventAggregator.Publish(new Events.InvoiceEvent(entity.EntityToDTO(_NetworkProvider), 1001, "invoice_created")); var resp = entity.EntityToDTO(_NetworkProvider); return new DataWrapper(resp) { Facade = "pos/invoice" }; } diff --git a/BTCPayServer/Events/InvoiceEvent.cs b/BTCPayServer/Events/InvoiceEvent.cs index b21e15cc9..c3d0f60a3 100644 --- a/BTCPayServer/Events/InvoiceEvent.cs +++ b/BTCPayServer/Events/InvoiceEvent.cs @@ -8,24 +8,20 @@ namespace BTCPayServer.Events { public class InvoiceEvent { - public InvoiceEvent(InvoiceEntity invoice, int code, string name) : this(invoice.Id, code, name) + public InvoiceEvent(Models.InvoiceResponse invoice, int code, string name) { - - } - public InvoiceEvent(string invoiceId, int code, string name) - { - InvoiceId = invoiceId; + Invoice = invoice; EventCode = code; Name = name; } - public string InvoiceId { get; set; } + public Models.InvoiceResponse Invoice { get; set; } public int EventCode { get; set; } public string Name { get; set; } public override string ToString() { - return $"Invoice {InvoiceId} new event: {Name} ({EventCode})"; + return $"Invoice {Invoice.Id} new event: {Name} ({EventCode})"; } } } diff --git a/BTCPayServer/HostedServices/InvoiceNotificationManager.cs b/BTCPayServer/HostedServices/InvoiceNotificationManager.cs index 6605e11c8..85d50de9e 100644 --- a/BTCPayServer/HostedServices/InvoiceNotificationManager.cs +++ b/BTCPayServer/HostedServices/InvoiceNotificationManager.cs @@ -308,7 +308,7 @@ namespace BTCPayServer.HostedServices { leases.Add(_EventAggregator.Subscribe(async e => { - var invoice = await _InvoiceRepository.GetInvoice(null, e.InvoiceId); + var invoice = await _InvoiceRepository.GetInvoice(null, e.Invoice.Id); List tasks = new List(); // Awaiting this later help make sure invoices should arrive in order diff --git a/BTCPayServer/HostedServices/InvoiceWatcher.cs b/BTCPayServer/HostedServices/InvoiceWatcher.cs index a6a2be0d0..ddddd8698 100644 --- a/BTCPayServer/HostedServices/InvoiceWatcher.cs +++ b/BTCPayServer/HostedServices/InvoiceWatcher.cs @@ -66,10 +66,10 @@ namespace BTCPayServer.HostedServices context.MarkDirty(); await _InvoiceRepository.UnaffectAddress(invoice.Id); - context.Events.Add(new InvoiceEvent(invoice, 1004, "invoice_expired")); + context.Events.Add(new InvoiceEvent(invoice.EntityToDTO(_NetworkProvider), 1004, "invoice_expired")); invoice.Status = "expired"; if(invoice.ExceptionStatus == "paidPartial") - context.Events.Add(new InvoiceEvent(invoice, 2000, "invoice_expiredPaidPartial")); + context.Events.Add(new InvoiceEvent(invoice.EntityToDTO(_NetworkProvider), 2000, "invoice_expiredPaidPartial")); } var payments = invoice.GetPayments().Where(p => p.Accounted).ToArray(); @@ -84,7 +84,7 @@ namespace BTCPayServer.HostedServices { if (invoice.Status == "new") { - context.Events.Add(new InvoiceEvent(invoice, 1003, "invoice_paidInFull")); + context.Events.Add(new InvoiceEvent(invoice.EntityToDTO(_NetworkProvider), 1003, "invoice_paidInFull")); invoice.Status = "paid"; invoice.ExceptionStatus = accounting.Paid > accounting.TotalDue ? "paidOver" : null; await _InvoiceRepository.UnaffectAddress(invoice.Id); @@ -93,7 +93,7 @@ namespace BTCPayServer.HostedServices else if (invoice.Status == "expired" && invoice.ExceptionStatus != "paidLate") { invoice.ExceptionStatus = "paidLate"; - context.Events.Add(new InvoiceEvent(invoice, 1009, "invoice_paidAfterExpiration")); + context.Events.Add(new InvoiceEvent(invoice.EntityToDTO(_NetworkProvider), 1009, "invoice_paidAfterExpiration")); context.MarkDirty(); } } @@ -139,14 +139,14 @@ namespace BTCPayServer.HostedServices (confirmedAccounting.Paid < accounting.MinimumTotalDue)) { await _InvoiceRepository.UnaffectAddress(invoice.Id); - context.Events.Add(new InvoiceEvent(invoice, 1013, "invoice_failedToConfirm")); + context.Events.Add(new InvoiceEvent(invoice.EntityToDTO(_NetworkProvider), 1013, "invoice_failedToConfirm")); invoice.Status = "invalid"; context.MarkDirty(); } else if (confirmedAccounting.Paid >= accounting.MinimumTotalDue) { await _InvoiceRepository.UnaffectAddress(invoice.Id); - context.Events.Add(new InvoiceEvent(invoice, 1005, "invoice_confirmed")); + context.Events.Add(new InvoiceEvent(invoice.EntityToDTO(_NetworkProvider), 1005, "invoice_confirmed")); invoice.Status = "confirmed"; context.MarkDirty(); } @@ -157,7 +157,7 @@ namespace BTCPayServer.HostedServices var completedAccounting = paymentMethod.Calculate(p => p.GetCryptoPaymentData().PaymentCompleted(p, network)); if (completedAccounting.Paid >= accounting.MinimumTotalDue) { - context.Events.Add(new InvoiceEvent(invoice, 1006, "invoice_completed")); + context.Events.Add(new InvoiceEvent(invoice.EntityToDTO(_NetworkProvider), 1006, "invoice_completed")); invoice.Status = "complete"; context.MarkDirty(); } @@ -249,13 +249,13 @@ namespace BTCPayServer.HostedServices { if (b.Name == "invoice_created") { - Watch(b.InvoiceId); - await Wait(b.InvoiceId); + Watch(b.Invoice.Id); + await Wait(b.Invoice.Id); } if (b.Name == "invoice_receivedPayment") { - Watch(b.InvoiceId); + Watch(b.Invoice.Id); } })); return Task.CompletedTask; diff --git a/BTCPayServer/Payments/Bitcoin/NBXplorerListener.cs b/BTCPayServer/Payments/Bitcoin/NBXplorerListener.cs index 4b0e6129d..3cf3a2eee 100644 --- a/BTCPayServer/Payments/Bitcoin/NBXplorerListener.cs +++ b/BTCPayServer/Payments/Bitcoin/NBXplorerListener.cs @@ -161,7 +161,7 @@ namespace BTCPayServer.Payments.Bitcoin { var payment = await _InvoiceRepository.AddPayment(invoice.Id, DateTimeOffset.UtcNow, paymentData, network.CryptoCode); if(payment != null) - await ReceivedPayment(wallet, invoice.Id, payment, evt.DerivationStrategy); + await ReceivedPayment(wallet, invoice, payment, evt.DerivationStrategy); } else { @@ -332,7 +332,7 @@ namespace BTCPayServer.Payments.Bitcoin var payment = await _InvoiceRepository.AddPayment(invoice.Id, coin.Timestamp, paymentData, network.CryptoCode).ConfigureAwait(false); alreadyAccounted.Add(coin.Coin.Outpoint); if (payment != null) - invoice = await ReceivedPayment(wallet, invoice.Id, payment, strategy); + invoice = await ReceivedPayment(wallet, invoice, payment, strategy); totalPayment++; } } @@ -346,10 +346,10 @@ namespace BTCPayServer.Payments.Bitcoin .FirstOrDefault(); } - private async Task ReceivedPayment(BTCPayWallet wallet, string invoiceId, PaymentEntity payment, DerivationStrategyBase strategy) + private async Task ReceivedPayment(BTCPayWallet wallet, InvoiceEntity invoice, PaymentEntity payment, DerivationStrategyBase strategy) { var paymentData = (BitcoinLikePaymentData)payment.GetCryptoPaymentData(); - var invoice = (await UpdatePaymentStates(wallet, invoiceId)); + invoice = (await UpdatePaymentStates(wallet, invoice.Id)); var paymentMethod = invoice.GetPaymentMethod(wallet.Network, PaymentTypes.BTCLike, _ExplorerClients.NetworkProviders); if (paymentMethod != null && paymentMethod.GetPaymentMethodDetails() is BitcoinLikeOnChainPaymentMethod btc && @@ -358,13 +358,13 @@ namespace BTCPayServer.Payments.Bitcoin { var address = await wallet.ReserveAddressAsync(strategy); btc.DepositAddress = address.ToString(); - await _InvoiceRepository.NewAddress(invoiceId, btc, wallet.Network); - _Aggregator.Publish(new InvoiceNewAddressEvent(invoiceId, address.ToString(), wallet.Network)); + await _InvoiceRepository.NewAddress(invoice.Id, btc, wallet.Network); + _Aggregator.Publish(new InvoiceNewAddressEvent(invoice.Id, address.ToString(), wallet.Network)); paymentMethod.SetPaymentMethodDetails(btc); invoice.SetPaymentMethod(paymentMethod); } wallet.InvalidateCache(strategy); - _Aggregator.Publish(new InvoiceEvent(invoiceId, 1002, "invoice_receivedPayment")); + _Aggregator.Publish(new InvoiceEvent(invoice.EntityToDTO(_NetworkProvider), 1002, "invoice_receivedPayment")); return invoice; } public Task StopAsync(CancellationToken cancellationToken) diff --git a/BTCPayServer/Payments/Lightning/LightningListener.cs b/BTCPayServer/Payments/Lightning/LightningListener.cs index 3db1e90f6..928f85721 100644 --- a/BTCPayServer/Payments/Lightning/LightningListener.cs +++ b/BTCPayServer/Payments/Lightning/LightningListener.cs @@ -46,7 +46,7 @@ namespace BTCPayServer.Payments.Lightning { if (inv.Name == "invoice_created") { - await EnsureListening(inv.InvoiceId, false); + await EnsureListening(inv.Invoice.Id, false); } })); @@ -189,8 +189,12 @@ namespace BTCPayServer.Payments.Lightning BOLT11 = notification.BOLT11, Amount = notification.Amount }, network.CryptoCode, accounted: true); - if(payment != null) - _Aggregator.Publish(new InvoiceEvent(listenedInvoice.InvoiceId, 1002, "invoice_receivedPayment")); + if (payment != null) + { + var invoice = await _InvoiceRepository.GetInvoice(null, listenedInvoice.InvoiceId); + if(invoice != null) + _Aggregator.Publish(new InvoiceEvent(invoice.EntityToDTO(_NetworkProvider), 1002, "invoice_receivedPayment")); + } } List _ListeningLightning = new List();