channeldb/invoice: fail extra HTLC sets immeidately

This commit is contained in:
Conner Fromknecht 2021-05-06 09:17:19 -07:00
parent 70efaa5fe2
commit 8402e346f5
No known key found for this signature in database
GPG Key ID: E7D737B67FA592C7
3 changed files with 49 additions and 0 deletions

@ -494,6 +494,31 @@ func (i *Invoice) HTLCSet(setID *[32]byte, state HtlcState) map[CircuitKey]*Invo
return htlcSet
}
// HTLCSetCompliment returns the set of all HTLCs not belonging to setID that
// are in the target state. Passing a nil setID will return no invoices, since
// all MPP HTLCs are part of the same HTLC set.
func (i *Invoice) HTLCSetCompliment(setID *[32]byte,
state HtlcState) map[CircuitKey]*InvoiceHTLC {
htlcSet := make(map[CircuitKey]*InvoiceHTLC)
for key, htlc := range i.Htlcs {
// Only add HTLCs that are in the requested HtlcState.
if htlc.State != state {
continue
}
// We are constructing the compliment, so filter anything that
// matches this set id.
if htlc.IsInHTLCSet(setID) {
continue
}
htlcSet[key] = htlc
}
return htlcSet
}
// HtlcState defines the states an htlc paying to an invoice can be in.
type HtlcState uint8

@ -1063,6 +1063,23 @@ func (i *InvoiceRegistry) notifyExitHopHtlcLocked(
i.notifyHodlSubscribers(htlcSettleResolution)
}
// If concurrent payments were attempted to this invoice before
// the current one was ultimately settled, cancel back any of
// the HTLCs immediately. As a result of the settle, the HTLCs
// in other HTLC sets are automatically converted to a canceled
// state when updating the invoice.
canceledHtlcSet := invoice.HTLCSetCompliment(
setID, channeldb.HtlcStateCanceled,
)
for key, htlc := range canceledHtlcSet {
htlcFailResolution := NewFailResolution(
key, int32(htlc.AcceptHeight),
ResultInvoiceAlreadySettled,
)
i.notifyHodlSubscribers(htlcFailResolution)
}
// If we accepted the htlc, subscribe to the hodl invoice and return
// an accept resolution with the htlc's accept time on it.
case *htlcAcceptResolution:

@ -61,6 +61,10 @@ const (
// invoice that is already canceled.
ResultInvoiceAlreadyCanceled
// ResultInvoiceAlreadySettled is returned when trying to pay an invoice
// that is already settled.
ResultInvoiceAlreadySettled
// ResultAmountTooLow is returned when an invoice is underpaid.
ResultAmountTooLow
@ -133,6 +137,9 @@ func (f FailResolutionResult) FailureString() string {
case ResultInvoiceAlreadyCanceled:
return "invoice already canceled"
case ResultInvoiceAlreadySettled:
return "invoice alread settled"
case ResultAmountTooLow:
return "amount too low"