From c548a70e0d57d48d14a5f9a7c3d21e474986f7ff Mon Sep 17 00:00:00 2001 From: Andras Banki-Horvath Date: Fri, 11 Mar 2022 19:51:13 +0100 Subject: [PATCH 1/2] invoices: fix deadlock in invoice registry --- invoices/invoiceregistry.go | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/invoices/invoiceregistry.go b/invoices/invoiceregistry.go index 11eca9dd35..aaee2a775f 100644 --- a/invoices/invoiceregistry.go +++ b/invoices/invoiceregistry.go @@ -939,12 +939,18 @@ func (i *InvoiceRegistry) NotifyExitHopHtlc(rHash lntypes.Hash, // Execute locked notify exit hop logic. i.Lock() - resolution, err := i.notifyExitHopHtlcLocked(&ctx, hodlChan) + resolution, invoiceToExpire, err := i.notifyExitHopHtlcLocked( + &ctx, hodlChan, + ) i.Unlock() if err != nil { return nil, err } + if invoiceToExpire != nil { + i.expiryWatcher.AddInvoices(invoiceToExpire) + } + switch r := resolution.(type) { // The htlc is held. Start a timer outside the lock if the htlc should // be auto-released, because otherwise a deadlock may happen with the @@ -975,10 +981,11 @@ func (i *InvoiceRegistry) NotifyExitHopHtlc(rHash lntypes.Hash, } // notifyExitHopHtlcLocked is the internal implementation of NotifyExitHopHtlc -// that should be executed inside the registry lock. +// that should be executed inside the registry lock. The returned invoiceExpiry +// (if not nil) needs to be added to the expiry watcher outside of the lock. func (i *InvoiceRegistry) notifyExitHopHtlcLocked( ctx *invoiceUpdateCtx, hodlChan chan<- interface{}) ( - HtlcResolution, error) { + HtlcResolution, invoiceExpiry, error) { // We'll attempt to settle an invoice matching this rHash on disk (if // one exists). The callback will update the invoice state and/or htlcs. @@ -1014,15 +1021,17 @@ func (i *InvoiceRegistry) notifyExitHopHtlcLocked( return NewFailResolution( ctx.circuitKey, ctx.currentHeight, ResultInvoiceNotFound, - ), nil + ), nil, nil case nil: default: ctx.log(err.Error()) - return nil, err + return nil, nil, err } + var invoiceToExpire invoiceExpiry + switch res := resolution.(type) { case *HtlcFailResolution: // Inspect latest htlc state on the invoice. If it is found, @@ -1116,7 +1125,7 @@ func (i *InvoiceRegistry) notifyExitHopHtlcLocked( case *htlcAcceptResolution: invoiceHtlc, ok := invoice.Htlcs[ctx.circuitKey] if !ok { - return nil, fmt.Errorf("accepted htlc: %v not"+ + return nil, nil, fmt.Errorf("accepted htlc: %v not"+ " present on invoice: %x", ctx.circuitKey, ctx.hash[:]) } @@ -1145,8 +1154,7 @@ func (i *InvoiceRegistry) notifyExitHopHtlcLocked( // possible that we MppTimeout the htlcs, and then our relevant // expiry height could change. if res.outcome == resultAccepted { - expiry := makeInvoiceExpiry(ctx.hash, invoice) - i.expiryWatcher.AddInvoices(expiry) + invoiceToExpire = makeInvoiceExpiry(ctx.hash, invoice) } i.hodlSubscribe(hodlChan, ctx.circuitKey) @@ -1169,7 +1177,7 @@ func (i *InvoiceRegistry) notifyExitHopHtlcLocked( i.notifyClients(ctx.hash, invoice, setID) } - return resolution, nil + return resolution, invoiceToExpire, nil } // SettleHodlInvoice sets the preimage of a hodl invoice. From 95d8fd8007903622be8c70b37d5de8b8446e020d Mon Sep 17 00:00:00 2001 From: Andras Banki-Horvath Date: Mon, 14 Mar 2022 10:18:52 +0100 Subject: [PATCH 2/2] docs: update release notes 0.15.0 --- docs/release-notes/release-notes-0.15.0.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/release-notes/release-notes-0.15.0.md b/docs/release-notes/release-notes-0.15.0.md index 2358cc8e92..735c3a3bc2 100644 --- a/docs/release-notes/release-notes-0.15.0.md +++ b/docs/release-notes/release-notes-0.15.0.md @@ -48,6 +48,9 @@ validation](https://github.com/lightningnetwork/lnd/pull/6314) when calling `NewSigFromRawSignature`. +* [Fixed deadlock in invoice + registry](https://github.com/lightningnetwork/lnd/pull/6332). + ## Misc @@ -177,4 +180,4 @@ gRPC performance metrics (latency to process `GetInfo`, etc)](https://github.com * Thebora Kompanioni * Torkel Rogstad * Vsevolod Kaganovych -* Yong Yu \ No newline at end of file +* Yong Yu