From 20c1315c50cc4172884528a91aa5d688cc543264 Mon Sep 17 00:00:00 2001 From: positiveblue Date: Wed, 5 Jul 2023 16:19:01 -0700 Subject: [PATCH] multi: allow LNC reconnects without restarting the proxy LNC will automatically try to reconnect to the LND node whenever there is an error. Until now, losing the connection with the LND node made the proxy shut down. When using LNC, we can simply log that we received an error and let the library handle the reconnection. Because we do not want to overheat the server when the backend lnd node is down, we need to make sure that we add a timeout to the client calls. --- aperture.go | 12 +++++++++++- challenger/lnd.go | 22 ++++++++++++++++++++-- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/aperture.go b/aperture.go index 5fbb4dd..632d776 100644 --- a/aperture.go +++ b/aperture.go @@ -335,8 +335,18 @@ func (a *Aperture) Start(errChan chan error) error { "session: %w", err) } + // An LNC session will automatically try to reconnect to + // the node whenever an error occurs. Instead of + // shutting the proxy down we will just log the error. + lncErrChan := make(chan error) + go func() { + for err := range lncErrChan { + log.Errorf("lnc session error: %v", err) + } + }() + a.challenger, err = challenger.NewLNCChallenger( - session, lncStore, genInvoiceReq, errChan, + session, lncStore, genInvoiceReq, lncErrChan, ) if err != nil { return fmt.Errorf("unable to start lnc "+ diff --git a/challenger/lnd.go b/challenger/lnd.go index 00bd53e..5814ccf 100644 --- a/challenger/lnd.go +++ b/challenger/lnd.go @@ -13,6 +13,12 @@ import ( "github.com/lightningnetwork/lnd/lntypes" ) +const ( + // defaultLNDCallTimeout is the default timeout used for calls to the + // LND client. + defaultLNDCallTimeout = time.Second * 10 +) + // LndChallenger is a challenger that uses an lnd backend to create new LSAT // payment challenges. type LndChallenger struct { @@ -199,12 +205,20 @@ func (l *LndChallenger) readInvoiceStream( log.Errorf("Received error from invoice subscription: "+ "%v", err) + // If the challenger was shutting down, we will receive the + // "client connection is closing" error for LNC connections + // but there is no need to signal the error to the main goroutine. + select { + case <-l.quit: + return + default: + } + // The connection is faulty, we can't continue to // function properly. Signal the error to the main // goroutine to force a shutdown/restart. select { case l.errChan <- err: - case <-l.quit: default: } @@ -244,6 +258,7 @@ func (l *LndChallenger) readInvoiceStream( func (l *LndChallenger) Stop() { l.invoicesCancel() close(l.quit) + close(l.errChan) l.wg.Wait() } @@ -263,7 +278,10 @@ func (l *LndChallenger) NewChallenge(price int64) (string, lntypes.Hash, } ctx := l.clientCtx() - response, err := l.client.AddInvoice(ctx, invoice) + ctxt, cancel := context.WithTimeout(ctx, defaultLNDCallTimeout) + defer cancel() + + response, err := l.client.AddInvoice(ctxt, invoice) if err != nil { log.Errorf("Error adding invoice: %v", err) return "", lntypes.ZeroHash, err