mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-09-22 15:57:49 +02:00
invoices: recognize AMP invoice settles during ntnf dispatch+catchup
In this commit, we add the setID to the invoiceEvent struct as it will be useful when we need to be able to distinguish a new open invoice, from an AMP invoice that's being settled for the first time. we then update the logic during notification dispatch to utilize the new field to allow it to detect the repeated settles of AMP invoices.
This commit is contained in:
@@ -236,7 +236,6 @@ func (i *InvoiceRegistry) Start() error {
|
|||||||
// Start InvoiceExpiryWatcher and prepopulate it with existing active
|
// Start InvoiceExpiryWatcher and prepopulate it with existing active
|
||||||
// invoices.
|
// invoices.
|
||||||
err := i.expiryWatcher.Start(i.cancelInvoiceImpl)
|
err := i.expiryWatcher.Start(i.cancelInvoiceImpl)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -273,6 +272,7 @@ func (i *InvoiceRegistry) Stop() error {
|
|||||||
type invoiceEvent struct {
|
type invoiceEvent struct {
|
||||||
hash lntypes.Hash
|
hash lntypes.Hash
|
||||||
invoice *channeldb.Invoice
|
invoice *channeldb.Invoice
|
||||||
|
setID *[32]byte
|
||||||
}
|
}
|
||||||
|
|
||||||
// tickAt returns a channel that ticks at the specified time. If the time has
|
// tickAt returns a channel that ticks at the specified time. If the time has
|
||||||
@@ -422,8 +422,10 @@ func (i *InvoiceRegistry) dispatchToClients(event *invoiceEvent) {
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
// Similarly, if we've already sent this add to
|
// Similarly, if we've already sent this add to
|
||||||
// the client then we can skip this one.
|
// the client then we can skip this one, but only if this isn't
|
||||||
case state == channeldb.ContractOpen &&
|
// an AMP invoice. AMP invoices always remain in the settle
|
||||||
|
// state as a base invoice.
|
||||||
|
case event.setID == nil && state == channeldb.ContractOpen &&
|
||||||
client.addIndex >= invoice.AddIndex:
|
client.addIndex >= invoice.AddIndex:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
@@ -450,6 +452,7 @@ func (i *InvoiceRegistry) dispatchToClients(event *invoiceEvent) {
|
|||||||
select {
|
select {
|
||||||
case client.ntfnQueue.ChanIn() <- &invoiceEvent{
|
case client.ntfnQueue.ChanIn() <- &invoiceEvent{
|
||||||
invoice: invoice,
|
invoice: invoice,
|
||||||
|
setID: event.setID,
|
||||||
}:
|
}:
|
||||||
case <-i.quit:
|
case <-i.quit:
|
||||||
return
|
return
|
||||||
@@ -459,11 +462,24 @@ func (i *InvoiceRegistry) dispatchToClients(event *invoiceEvent) {
|
|||||||
// the latest add/settle index it has. We'll use this to ensure
|
// the latest add/settle index it has. We'll use this to ensure
|
||||||
// we don't send a notification twice, which can happen if a new
|
// we don't send a notification twice, which can happen if a new
|
||||||
// event is added while we're catching up a new client.
|
// event is added while we're catching up a new client.
|
||||||
switch event.invoice.State {
|
invState := event.invoice.State
|
||||||
case channeldb.ContractSettled:
|
switch {
|
||||||
|
|
||||||
|
case invState == channeldb.ContractSettled:
|
||||||
client.settleIndex = invoice.SettleIndex
|
client.settleIndex = invoice.SettleIndex
|
||||||
case channeldb.ContractOpen:
|
|
||||||
|
case invState == channeldb.ContractOpen && event.setID == nil:
|
||||||
client.addIndex = invoice.AddIndex
|
client.addIndex = invoice.AddIndex
|
||||||
|
|
||||||
|
// If this is an AMP invoice, then we'll need to use the set ID
|
||||||
|
// to keep track of the settle index of the client. AMP
|
||||||
|
// invoices never go to the open state, but if a setID is
|
||||||
|
// passed, then we know it was just settled and will track the
|
||||||
|
// highest settle index so far.
|
||||||
|
case invState == channeldb.ContractOpen && event.setID != nil:
|
||||||
|
setID := *event.setID
|
||||||
|
client.settleIndex = invoice.AMPState[setID].SettleIndex
|
||||||
|
|
||||||
default:
|
default:
|
||||||
log.Errorf("unexpected invoice state: %v",
|
log.Errorf("unexpected invoice state: %v",
|
||||||
event.invoice.State)
|
event.invoice.State)
|
||||||
@@ -579,7 +595,7 @@ func (i *InvoiceRegistry) AddInvoice(invoice *channeldb.Invoice,
|
|||||||
|
|
||||||
// Now that we've added the invoice, we'll send dispatch a message to
|
// Now that we've added the invoice, we'll send dispatch a message to
|
||||||
// notify the clients of this new invoice.
|
// notify the clients of this new invoice.
|
||||||
i.notifyClients(paymentHash, invoice)
|
i.notifyClients(paymentHash, invoice, nil)
|
||||||
i.Unlock()
|
i.Unlock()
|
||||||
|
|
||||||
// InvoiceExpiryWatcher.AddInvoice must not be locked by InvoiceRegistry
|
// InvoiceExpiryWatcher.AddInvoice must not be locked by InvoiceRegistry
|
||||||
@@ -1088,6 +1104,8 @@ func (i *InvoiceRegistry) notifyExitHopHtlcLocked(
|
|||||||
// the HTLCs immediately. As a result of the settle, the HTLCs
|
// the HTLCs immediately. As a result of the settle, the HTLCs
|
||||||
// in other HTLC sets are automatically converted to a canceled
|
// in other HTLC sets are automatically converted to a canceled
|
||||||
// state when updating the invoice.
|
// state when updating the invoice.
|
||||||
|
//
|
||||||
|
// TODO(roasbeef): can remove now??
|
||||||
canceledHtlcSet := invoice.HTLCSetCompliment(
|
canceledHtlcSet := invoice.HTLCSetCompliment(
|
||||||
setID, channeldb.HtlcStateCanceled,
|
setID, channeldb.HtlcStateCanceled,
|
||||||
)
|
)
|
||||||
@@ -1126,7 +1144,6 @@ func (i *InvoiceRegistry) notifyExitHopHtlcLocked(
|
|||||||
if invoice.State == channeldb.ContractOpen {
|
if invoice.State == channeldb.ContractOpen {
|
||||||
res.acceptTime = invoiceHtlc.AcceptTime
|
res.acceptTime = invoiceHtlc.AcceptTime
|
||||||
res.autoRelease = true
|
res.autoRelease = true
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we have fully accepted the set of htlcs for this invoice,
|
// If we have fully accepted the set of htlcs for this invoice,
|
||||||
@@ -1149,7 +1166,14 @@ func (i *InvoiceRegistry) notifyExitHopHtlcLocked(
|
|||||||
// HTLCs, we'll go ahead and notify any clients wiaiting on the invoice
|
// HTLCs, we'll go ahead and notify any clients wiaiting on the invoice
|
||||||
// state changes.
|
// state changes.
|
||||||
if updateSubscribers {
|
if updateSubscribers {
|
||||||
i.notifyClients(ctx.hash, invoice)
|
// We'll add a setID onto the notification, but only if this is
|
||||||
|
// an AMP invoice being settled.
|
||||||
|
var setID *[32]byte
|
||||||
|
if _, ok := resolution.(*HtlcSettleResolution); ok {
|
||||||
|
setID = ctx.setID()
|
||||||
|
}
|
||||||
|
|
||||||
|
i.notifyClients(ctx.hash, invoice, setID)
|
||||||
}
|
}
|
||||||
|
|
||||||
return resolution, nil
|
return resolution, nil
|
||||||
@@ -1210,7 +1234,7 @@ func (i *InvoiceRegistry) SettleHodlInvoice(preimage lntypes.Preimage) error {
|
|||||||
|
|
||||||
i.notifyHodlSubscribers(resolution)
|
i.notifyHodlSubscribers(resolution)
|
||||||
}
|
}
|
||||||
i.notifyClients(hash, invoice)
|
i.notifyClients(hash, invoice, nil)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -1303,7 +1327,7 @@ func (i *InvoiceRegistry) cancelInvoiceImpl(payHash lntypes.Hash,
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
i.notifyClients(payHash, invoice)
|
i.notifyClients(payHash, invoice, nil)
|
||||||
|
|
||||||
// Attempt to also delete the invoice if requested through the registry
|
// Attempt to also delete the invoice if requested through the registry
|
||||||
// config.
|
// config.
|
||||||
@@ -1337,11 +1361,12 @@ func (i *InvoiceRegistry) cancelInvoiceImpl(payHash lntypes.Hash,
|
|||||||
// notifyClients notifies all currently registered invoice notification clients
|
// notifyClients notifies all currently registered invoice notification clients
|
||||||
// of a newly added/settled invoice.
|
// of a newly added/settled invoice.
|
||||||
func (i *InvoiceRegistry) notifyClients(hash lntypes.Hash,
|
func (i *InvoiceRegistry) notifyClients(hash lntypes.Hash,
|
||||||
invoice *channeldb.Invoice) {
|
invoice *channeldb.Invoice, setID *[32]byte) {
|
||||||
|
|
||||||
event := &invoiceEvent{
|
event := &invoiceEvent{
|
||||||
invoice: invoice,
|
invoice: invoice,
|
||||||
hash: hash,
|
hash: hash,
|
||||||
|
setID: setID,
|
||||||
}
|
}
|
||||||
|
|
||||||
select {
|
select {
|
||||||
@@ -1479,11 +1504,19 @@ func (i *InvoiceRegistry) SubscribeNotifications(
|
|||||||
|
|
||||||
var targetChan chan *channeldb.Invoice
|
var targetChan chan *channeldb.Invoice
|
||||||
state := invoiceEvent.invoice.State
|
state := invoiceEvent.invoice.State
|
||||||
switch state {
|
switch {
|
||||||
case channeldb.ContractOpen:
|
// AMP invoices never move to settled, but will
|
||||||
targetChan = client.NewInvoices
|
// be sent with a set ID if an HTLC set is
|
||||||
case channeldb.ContractSettled:
|
// being settled.
|
||||||
|
case state == channeldb.ContractOpen &&
|
||||||
|
invoiceEvent.setID != nil:
|
||||||
|
fallthrough
|
||||||
|
case state == channeldb.ContractSettled:
|
||||||
targetChan = client.SettledInvoices
|
targetChan = client.SettledInvoices
|
||||||
|
|
||||||
|
case state == channeldb.ContractOpen:
|
||||||
|
targetChan = client.NewInvoices
|
||||||
|
|
||||||
default:
|
default:
|
||||||
log.Errorf("unknown invoice "+
|
log.Errorf("unknown invoice "+
|
||||||
"state: %v", state)
|
"state: %v", state)
|
||||||
|
Reference in New Issue
Block a user