44 "context"
55 "fmt"
66 "io"
7- "math"
87 "strings"
98 "sync"
109 "time"
@@ -13,6 +12,12 @@ import (
1312 "github.com/lightningnetwork/lnd/lntypes"
1413)
1514
15+ const (
16+ // invoiceQueryPageSize is the maximum number of invoices that will be
17+ // queried in a single request.
18+ invoiceQueryPageSize = 1000
19+ )
20+
1621// LndChallenger is a challenger that uses an lnd backend to create new L402
1722// payment challenges.
1823type LndChallenger struct {
@@ -74,7 +79,7 @@ func NewLndChallenger(client InvoiceClient,
7479
7580// Start starts the challenger's main work which is to keep track of all
7681// invoices and their states. For that the backing lnd node is queried for all
77- // invoices on startup and the a subscription to all subsequent invoice updates
82+ // invoices on startup and a subscription to all subsequent invoice updates
7883// is created.
7984func (l * LndChallenger ) Start () error {
8085 // These are the default values for the subscription. In case there are
@@ -84,49 +89,64 @@ func (l *LndChallenger) Start() error {
8489 addIndex := uint64 (0 )
8590 settleIndex := uint64 (0 )
8691
87- // Get a list of all existing invoices on startup and add them to our
88- // cache. We need to keep track of all invoices, even quite old ones to
89- // make sure tokens are valid. But to save space we only keep track of
90- // an invoice's state .
92+ log . Debugf ( "Starting LND challenger" )
93+ // Paginate through all existing invoices on startup and add them to our
94+ // cache. We need to keep track of all invoices to ensure tokens are
95+ // valid .
9196 ctx := l .clientCtx ()
92- invoiceResp , err := l .client .ListInvoices (
93- ctx , & lnrpc.ListInvoiceRequest {
94- NumMaxInvoices : math .MaxUint64 ,
95- },
96- )
97- if err != nil {
98- return err
99- }
100-
101- // Advance our indices to the latest known one so we'll only receive
102- // updates for new invoices and/or newly settled invoices.
103- l .invoicesMtx .Lock ()
104- for _ , invoice := range invoiceResp .Invoices {
105- // Some invoices like AMP invoices may not have a payment hash
106- // populated.
107- if invoice .RHash == nil {
108- continue
97+ indexOffset := uint64 (0 )
98+ for {
99+ log .Debugf ("Querying invoices from index %d" , indexOffset )
100+ invoiceResp , err := l .client .ListInvoices (
101+ ctx , & lnrpc.ListInvoiceRequest {
102+ IndexOffset : indexOffset ,
103+ NumMaxInvoices : invoiceQueryPageSize ,
104+ },
105+ )
106+ if err != nil {
107+ return err
109108 }
110109
111- if invoice .AddIndex > addIndex {
112- addIndex = invoice .AddIndex
113- }
114- if invoice .SettleIndex > settleIndex {
115- settleIndex = invoice .SettleIndex
116- }
117- hash , err := lntypes .MakeHash (invoice .RHash )
118- if err != nil {
119- l .invoicesMtx .Unlock ()
120- return fmt .Errorf ("error parsing invoice hash: %v" , err )
110+ // If there are no more invoices, stop pagination.
111+ if len (invoiceResp .Invoices ) == 0 {
112+ break
121113 }
122114
123- // Don't track the state of canceled or expired invoices.
124- if invoiceIrrelevant (invoice ) {
125- continue
115+ // Lock the mutex to safely update the invoice states.
116+ l .invoicesMtx .Lock ()
117+ for _ , invoice := range invoiceResp .Invoices {
118+ // Skip invoices that do not have a payment hash
119+ // populated.
120+ if invoice .RHash == nil {
121+ continue
122+ }
123+
124+ if invoice .AddIndex > addIndex {
125+ addIndex = invoice .AddIndex
126+ }
127+ if invoice .SettleIndex > settleIndex {
128+ settleIndex = invoice .SettleIndex
129+ }
130+ hash , err := lntypes .MakeHash (invoice .RHash )
131+ if err != nil {
132+ l .invoicesMtx .Unlock ()
133+ return fmt .Errorf ("error parsing invoice " +
134+ "hash: %v" , err )
135+ }
136+
137+ // Skip tracking the state of canceled or expired
138+ // invoices.
139+ if invoiceIrrelevant (invoice ) {
140+ continue
141+ }
142+ l .invoiceStates [hash ] = invoice .State
126143 }
127- l .invoiceStates [hash ] = invoice .State
144+ l .invoicesMtx .Unlock ()
145+
146+ // Update the index offset for the next batch.
147+ indexOffset = invoiceResp .LastIndexOffset
128148 }
129- l . invoicesMtx . Unlock ( )
149+ log . Debugf ( "Finished querying invoices" )
130150
131151 // We need to be able to cancel any subscription we make.
132152 ctxc , cancel := context .WithCancel (l .clientCtx ())
0 commit comments