From 0e72c2bf92dca3d8cf94278292405f613c933a4a Mon Sep 17 00:00:00 2001 From: carla Date: Mon, 7 Jun 2021 10:56:36 +0200 Subject: [PATCH] loopin: handle EOF case for SubscribeSingleInvoice From lnd 0.13.0, the SubscribeSingleInvoice rpc will return an EOF once it has served a final state to the stream. This is handled in our lndclient wrapper by closing the channels that we send updates/ errors on. When we are exclusively consuming updates from these streams, we don't need to handle this case because we will receive our final update and exit. However, in the case where we continue to listen on the update channels after consuming the final update, we need to handle this EOF/closed channels case. This is done by setting the channels to nil after they're closed so that we no longer select on them but can continue waiting for our other cases to complete. We have similar handling in loopout's waitForHtlcSpendConfirmed. --- loopin.go | 22 ++++++++++++++++++++-- loopin_testcontext_test.go | 9 +++++++++ 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/loopin.go b/loopin.go index e2bbe6c..7a76593 100644 --- a/loopin.go +++ b/loopin.go @@ -779,12 +779,30 @@ func (s *loopInSwap) waitForSwapComplete(ctx context.Context, htlcSpend = true // Swap invoice ntfn error. - case err := <-swapInvoiceErr: + case err, ok := <-swapInvoiceErr: + // If the channel has been closed, the server has + // finished sending updates, so we set the channel to + // nil because we don't want to constantly select this + // case. + if !ok { + swapInvoiceErr = nil + continue + } + return err // An update to the swap invoice occurred. Check the new state // and update the swap state accordingly. - case update := <-swapInvoiceChan: + case update, ok := <-swapInvoiceChan: + // If the channel has been closed, the server has + // finished sending updates, so we set the channel to + // nil because we don't want to constantly select this + // case. + if !ok { + swapInvoiceChan = nil + continue + } + s.log.Infof("Received swap invoice update: %v", update.State) diff --git a/loopin_testcontext_test.go b/loopin_testcontext_test.go index 7f0c0a8..e029c15 100644 --- a/loopin_testcontext_test.go +++ b/loopin_testcontext_test.go @@ -84,4 +84,13 @@ func (c *loopInTestContext) updateInvoiceState(amount btcutil.Amount, AmtPaid: amount, State: state, } + + // If we're in a final state, close our update channels as lndclient + // would. + if state == channeldb.ContractCanceled || + state == channeldb.ContractSettled { + + close(c.swapInvoiceSubscription.Update) + close(c.swapInvoiceSubscription.Err) + } }