mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-06-29 18:10:48 +02:00
Merge pull request #7334 from positiveblue/invoice-type-helper
channeldb/invoices: add `IsAMP` and `IsKeysend` helpers
This commit is contained in:
@ -907,10 +907,7 @@ func serializeInvoice(w io.Writer, i *invpkg.Invoice) error {
|
|||||||
|
|
||||||
// Only if this is a _non_ AMP invoice do we serialize the HTLCs
|
// Only if this is a _non_ AMP invoice do we serialize the HTLCs
|
||||||
// in-line with the rest of the invoice.
|
// in-line with the rest of the invoice.
|
||||||
ampInvoice := i.Terms.Features.HasFeature(
|
if i.IsAMP() {
|
||||||
lnwire.AMPOptional,
|
|
||||||
)
|
|
||||||
if ampInvoice {
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1148,40 +1145,51 @@ func fetchInvoice(invoiceNum []byte, invoices kvdb.RBucket,
|
|||||||
return invpkg.Invoice{}, err
|
return invpkg.Invoice{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// If this is an AMP invoice, then we'll also attempt to read out the
|
// If this is an AMP invoice we'll also attempt to read out the set of
|
||||||
// set of HTLCs that were paid to prior set IDs. However, we'll only do
|
// HTLCs that were paid to prior set IDs, if needed.
|
||||||
// this is the invoice didn't already have HTLCs stored in-line.
|
if !invoice.IsAMP() {
|
||||||
invoiceIsAMP := invoice.Terms.Features.HasFeature(
|
|
||||||
lnwire.AMPOptional,
|
|
||||||
)
|
|
||||||
switch {
|
|
||||||
case !invoiceIsAMP:
|
|
||||||
return invoice, nil
|
|
||||||
|
|
||||||
// For AMP invoice that already have HTLCs populated (created before
|
|
||||||
// recurring invoices), then we don't need to read from the prefix
|
|
||||||
// keyed section of the bucket.
|
|
||||||
case invoiceIsAMP && len(invoice.Htlcs) != 0:
|
|
||||||
return invoice, nil
|
|
||||||
|
|
||||||
// If the "zero" setID was specified, then this means that no HTLC data
|
|
||||||
// should be returned alongside of it.
|
|
||||||
case invoiceIsAMP && len(setIDs) != 0 && setIDs[0] != nil &&
|
|
||||||
*setIDs[0] == invpkg.BlankPayAddr:
|
|
||||||
|
|
||||||
return invoice, nil
|
return invoice, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
invoice.Htlcs, err = fetchAmpSubInvoices(
|
if shouldFetchAMPHTLCs(invoice, setIDs) {
|
||||||
invoices, invoiceNum, setIDs...,
|
invoice.Htlcs, err = fetchAmpSubInvoices(
|
||||||
)
|
invoices, invoiceNum, setIDs...,
|
||||||
if err != nil {
|
)
|
||||||
return invoice, nil
|
// TODO(positiveblue): we should fail when we are not able to
|
||||||
|
// fetch all the HTLCs for an AMP invoice. Multiple tests in
|
||||||
|
// the invoice and channeldb package break if we return this
|
||||||
|
// error. We need to update them when we migrate this logic to
|
||||||
|
// the sql implementation.
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("unable to fetch amp htlcs for inv "+
|
||||||
|
"%v and setIDs %v: %w", invoiceNum, setIDs, err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return invoice, nil
|
return invoice, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// shouldFetchAMPHTLCs returns true if we need to fetch the set of HTLCs that
|
||||||
|
// were paid to the relevant set IDs.
|
||||||
|
func shouldFetchAMPHTLCs(invoice invpkg.Invoice, setIDs []*invpkg.SetID) bool {
|
||||||
|
// For AMP invoice that already have HTLCs populated (created before
|
||||||
|
// recurring invoices), then we don't need to read from the prefix
|
||||||
|
// keyed section of the bucket.
|
||||||
|
if len(invoice.Htlcs) != 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the "zero" setID was specified, then this means that no HTLC data
|
||||||
|
// should be returned alongside of it.
|
||||||
|
if len(setIDs) != 0 && setIDs[0] != nil &&
|
||||||
|
*setIDs[0] == invpkg.BlankPayAddr {
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
// fetchInvoiceStateAMP retrieves the state of all the relevant sub-invoice for
|
// fetchInvoiceStateAMP retrieves the state of all the relevant sub-invoice for
|
||||||
// an AMP invoice. This methods only decode the relevant state vs the entire
|
// an AMP invoice. This methods only decode the relevant state vs the entire
|
||||||
// invoice.
|
// invoice.
|
||||||
@ -1905,9 +1913,7 @@ func (d *DB) updateInvoice(hash *lntypes.Hash, refSetID *invpkg.SetID, invoices,
|
|||||||
|
|
||||||
now := d.clock.Now()
|
now := d.clock.Now()
|
||||||
|
|
||||||
invoiceIsAMP := invoiceCopy.Terms.Features.HasFeature(
|
invoiceIsAMP := invoiceCopy.IsAMP()
|
||||||
lnwire.AMPOptional,
|
|
||||||
)
|
|
||||||
|
|
||||||
// Process add actions from update descriptor.
|
// Process add actions from update descriptor.
|
||||||
htlcsAmpUpdate := make(map[invpkg.SetID]map[models.CircuitKey]*invpkg.InvoiceHTLC) //nolint:lll
|
htlcsAmpUpdate := make(map[invpkg.SetID]map[models.CircuitKey]*invpkg.InvoiceHTLC) //nolint:lll
|
||||||
|
@ -306,6 +306,9 @@ data.
|
|||||||
|
|
||||||
* [Fixed a test closure](https://github.com/lightningnetwork/lnd/pull/7337)
|
* [Fixed a test closure](https://github.com/lightningnetwork/lnd/pull/7337)
|
||||||
issue found in `bitcoindnotify/bitcoind_test.go`.
|
issue found in `bitcoindnotify/bitcoind_test.go`.
|
||||||
|
|
||||||
|
* Add methods to easily check if an invoice [is AMP or
|
||||||
|
Keysend](https://github.com/lightningnetwork/lnd/pull/7334).
|
||||||
|
|
||||||
## Watchtowers
|
## Watchtowers
|
||||||
|
|
||||||
|
@ -471,6 +471,24 @@ func (i *Invoice) HTLCSetCompliment(setID *[32]byte,
|
|||||||
return htlcSet
|
return htlcSet
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsKeysend returns true if the invoice is a Keysend invoice.
|
||||||
|
func (i *Invoice) IsKeysend() bool {
|
||||||
|
// TODO(positiveblue): look for a more reliable way to tests if
|
||||||
|
// an invoice is keysend.
|
||||||
|
return len(i.PaymentRequest) == 0 && !i.IsAMP()
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsAMP returns true if the invoice is an AMP invoice.
|
||||||
|
func (i *Invoice) IsAMP() bool {
|
||||||
|
if i.Terms.Features == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return i.Terms.Features.HasFeature(
|
||||||
|
lnwire.AMPRequired,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// HtlcState defines the states an htlc paying to an invoice can be in.
|
// HtlcState defines the states an htlc paying to an invoice can be in.
|
||||||
type HtlcState uint8
|
type HtlcState uint8
|
||||||
|
|
||||||
@ -681,6 +699,8 @@ type InvoiceStateUpdateDesc struct {
|
|||||||
// invoice.
|
// invoice.
|
||||||
type InvoiceUpdateCallback = func(invoice *Invoice) (*InvoiceUpdateDesc, error)
|
type InvoiceUpdateCallback = func(invoice *Invoice) (*InvoiceUpdateDesc, error)
|
||||||
|
|
||||||
|
// ValidateInvoice assures the invoice passes the checks for all the relevant
|
||||||
|
// constraints.
|
||||||
func ValidateInvoice(i *Invoice, paymentHash lntypes.Hash) error {
|
func ValidateInvoice(i *Invoice, paymentHash lntypes.Hash) error {
|
||||||
// Avoid conflicts with all-zeroes magic value in the database.
|
// Avoid conflicts with all-zeroes magic value in the database.
|
||||||
if paymentHash == UnknownPreimage.Hash() {
|
if paymentHash == UnknownPreimage.Hash() {
|
||||||
@ -705,13 +725,8 @@ func ValidateInvoice(i *Invoice, paymentHash lntypes.Hash) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// AMP invoices and hodl invoices are allowed to have no preimage
|
if i.requiresPreimage() && i.Terms.PaymentPreimage == nil {
|
||||||
// specified.
|
return errors.New("this invoice must have a preimage")
|
||||||
isAMP := i.Terms.Features.HasFeature(
|
|
||||||
lnwire.AMPOptional,
|
|
||||||
)
|
|
||||||
if i.Terms.PaymentPreimage == nil && !(i.HodlInvoice || isAMP) {
|
|
||||||
return errors.New("non-hodl invoices must have a preimage")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(i.Htlcs) > 0 {
|
if len(i.Htlcs) > 0 {
|
||||||
@ -721,6 +736,17 @@ func ValidateInvoice(i *Invoice, paymentHash lntypes.Hash) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// requiresPreimage returns true if the invoice requires a preimage to be valid.
|
||||||
|
func (i *Invoice) requiresPreimage() bool {
|
||||||
|
// AMP invoices and hodl invoices are allowed to have no preimage
|
||||||
|
// specified.
|
||||||
|
if i.HodlInvoice || i.IsAMP() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
// IsPending returns true if the invoice is in ContractOpen state.
|
// IsPending returns true if the invoice is in ContractOpen state.
|
||||||
func (i *Invoice) IsPending() bool {
|
func (i *Invoice) IsPending() bool {
|
||||||
return i.State == ContractOpen || i.State == ContractAccepted
|
return i.State == ContractOpen || i.State == ContractAccepted
|
||||||
|
@ -150,8 +150,6 @@ func CreateRPCInvoice(invoice *invoices.Invoice,
|
|||||||
rpcHtlcs = append(rpcHtlcs, &rpcHtlc)
|
rpcHtlcs = append(rpcHtlcs, &rpcHtlc)
|
||||||
}
|
}
|
||||||
|
|
||||||
isAmp := invoice.Terms.Features.HasFeature(lnwire.AMPOptional)
|
|
||||||
|
|
||||||
rpcInvoice := &lnrpc.Invoice{
|
rpcInvoice := &lnrpc.Invoice{
|
||||||
Memo: string(invoice.Memo),
|
Memo: string(invoice.Memo),
|
||||||
RHash: rHash,
|
RHash: rHash,
|
||||||
@ -175,9 +173,9 @@ func CreateRPCInvoice(invoice *invoices.Invoice,
|
|||||||
State: state,
|
State: state,
|
||||||
Htlcs: rpcHtlcs,
|
Htlcs: rpcHtlcs,
|
||||||
Features: CreateRPCFeatures(invoice.Terms.Features),
|
Features: CreateRPCFeatures(invoice.Terms.Features),
|
||||||
IsKeysend: len(invoice.PaymentRequest) == 0 && !isAmp,
|
IsKeysend: invoice.IsKeysend(),
|
||||||
PaymentAddr: invoice.Terms.PaymentAddr[:],
|
PaymentAddr: invoice.Terms.PaymentAddr[:],
|
||||||
IsAmp: isAmp,
|
IsAmp: invoice.IsAMP(),
|
||||||
}
|
}
|
||||||
|
|
||||||
rpcInvoice.AmpInvoiceState = make(map[string]*lnrpc.AMPInvoiceState)
|
rpcInvoice.AmpInvoiceState = make(map[string]*lnrpc.AMPInvoiceState)
|
||||||
|
Reference in New Issue
Block a user