Skip to content

aperture: add support for async invoice loading on start up #167

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
Roasbeef opened this issue Apr 2, 2025 · 1 comment · May be fixed by #168
Open

aperture: add support for async invoice loading on start up #167

Roasbeef opened this issue Apr 2, 2025 · 1 comment · May be fixed by #168
Labels
enhancement New feature or request optimizations

Comments

@Roasbeef
Copy link
Member

Roasbeef commented Apr 2, 2025

Today on start up, we'll block to read out all the invoices from the backing node (LndChallenger.Start):

aperture/challenger/lnd.go

Lines 81 to 109 in 9fd44c9

// These are the default values for the subscription. In case there are
// no invoices yet, this will instruct lnd to just send us all updates.
// If there are existing invoices, these indices will be updated to
// reflect the latest known invoices.
addIndex := uint64(0)
settleIndex := uint64(0)
log.Debugf("Starting LND challenger")
// Paginate through all existing invoices on startup and add them to our
// cache. We need to keep track of all invoices to ensure tokens are
// valid.
ctx := l.clientCtx()
indexOffset := uint64(0)
for {
log.Debugf("Querying invoices from index %d", indexOffset)
invoiceResp, err := l.client.ListInvoices(
ctx, &lnrpc.ListInvoiceRequest{
IndexOffset: indexOffset,
NumMaxInvoices: uint64(l.batchSize),
},
)
if err != nil {
return err
}
// If there are no more invoices, stop pagination.
if len(invoiceResp.Invoices) == 0 {
break
}

If the node is very old, or has a ton of invoices, this can take quite some time, potentially 10 minutes+.

We should modify this logic to allow the service to start up while we continue to load the invoices in the background using a goroutine.

Steps To Completion

Only when we need to actually access the produced invoiceStates map should we block until the map has been fully populated. We'll likely want to create a new concurrent safe wrapper map that's able to signal any waiters once new elements have been added (see the condition variable usage), with the added ability to block while the map is being populated.

With that in place, we'll LndChallenger.VerifyInvoiceStatus shouldn't need to change too much. It already uses the condition variable to be notified when an entry it added to the map. It just needs to be updated to use the new abstractions mentioned above.

As the start up might take some time, we'll want to update this section to account for a longer timeout:

aperture/challenger/lnd.go

Lines 319 to 337 in 9fd44c9

// First of all, spawn a goroutine that will signal us on timeout.
// Otherwise if a client subscribes to an update on an invoice that
// never arrives, and there is no other activity, it would block
// forever in the condition.
condWg.Add(1)
go func() {
defer condWg.Done()
select {
case <-doneChan:
case <-time.After(timeout):
case <-l.quit:
}
l.invoicesCond.L.Lock()
timeoutReached = true
l.invoicesCond.Broadcast()
l.invoicesCond.L.Unlock()
}()

@Roasbeef Roasbeef added enhancement New feature or request optimizations labels Apr 2, 2025
@Roasbeef
Copy link
Member Author

Roasbeef commented Apr 2, 2025

The current timeout is 3 seconds:

const (
// DefaultInvoiceLookupTimeout is the default maximum time we wait for
// an invoice update to arrive.
DefaultInvoiceLookupTimeout = 3 * time.Second
)

@Roasbeef Roasbeef changed the title aperture: aperture: add support for async invoice loading on start up Apr 2, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request optimizations
Projects
None yet
1 participant