mirror of
https://github.com/lightningnetwork/lnd.git
synced 2024-11-19 09:53:54 +01:00
84387992ec
Make the kind of update explicit in the `InvoiceUpdateDesc` struct.
870 lines
27 KiB
Go
870 lines
27 KiB
Go
package invoices
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/lightningnetwork/lnd/feature"
|
|
"github.com/lightningnetwork/lnd/lntypes"
|
|
"github.com/lightningnetwork/lnd/lnwire"
|
|
"github.com/lightningnetwork/lnd/record"
|
|
)
|
|
|
|
const (
|
|
// MaxMemoSize is maximum size of the memo field within invoices stored
|
|
// in the database.
|
|
MaxMemoSize = 1024
|
|
|
|
// MaxPaymentRequestSize is the max size of a payment request for
|
|
// this invoice.
|
|
// TODO(halseth): determine the max length payment request when field
|
|
// lengths are final.
|
|
MaxPaymentRequestSize = 4096
|
|
)
|
|
|
|
var (
|
|
// unknownPreimage is an all-zeroes preimage that indicates that the
|
|
// preimage for this invoice is not yet known.
|
|
UnknownPreimage lntypes.Preimage
|
|
|
|
// BlankPayAddr is a sentinel payment address for legacy invoices.
|
|
// Invoices with this payment address are special-cased in the insertion
|
|
// logic to prevent being indexed in the payment address index,
|
|
// otherwise they would cause collisions after the first insertion.
|
|
BlankPayAddr [32]byte
|
|
)
|
|
|
|
// RefModifier is a modification on top of a base invoice ref. It allows the
|
|
// caller to opt to skip out on HTLCs for a given payAddr, or only return the
|
|
// set of specified HTLCs for a given setID.
|
|
type RefModifier uint8
|
|
|
|
const (
|
|
// DefaultModifier is the base modifier that doesn't change any
|
|
// behavior.
|
|
DefaultModifier RefModifier = iota
|
|
|
|
// HtlcSetOnlyModifier can only be used with a setID based invoice ref,
|
|
// and specifies that only the set of HTLCs related to that setID are
|
|
// to be returned.
|
|
HtlcSetOnlyModifier
|
|
|
|
// HtlcSetOnlyModifier can only be used with a payAddr based invoice
|
|
// ref, and specifies that the returned invoice shouldn't include any
|
|
// HTLCs at all.
|
|
HtlcSetBlankModifier
|
|
)
|
|
|
|
// InvoiceRef is a composite identifier for invoices. Invoices can be referenced
|
|
// by various combinations of payment hash and payment addr, in certain contexts
|
|
// only some of these are known. An InvoiceRef and its constructors thus
|
|
// encapsulate the valid combinations of query parameters that can be supplied
|
|
// to LookupInvoice and UpdateInvoice.
|
|
type InvoiceRef struct {
|
|
// payHash is the payment hash of the target invoice. All invoices are
|
|
// currently indexed by payment hash. This value will be used as a
|
|
// fallback when no payment address is known.
|
|
payHash *lntypes.Hash
|
|
|
|
// payAddr is the payment addr of the target invoice. Newer invoices
|
|
// (0.11 and up) are indexed by payment address in addition to payment
|
|
// hash, but pre 0.8 invoices do not have one at all. When this value is
|
|
// known it will be used as the primary identifier, falling back to
|
|
// payHash if no value is known.
|
|
payAddr *[32]byte
|
|
|
|
// setID is the optional set id for an AMP payment. This can be used to
|
|
// lookup or update the invoice knowing only this value. Queries by set
|
|
// id are only used to facilitate user-facing requests, e.g. lookup,
|
|
// settle or cancel an AMP invoice. The regular update flow from the
|
|
// invoice registry will always query for the invoice by
|
|
// payHash+payAddr.
|
|
setID *[32]byte
|
|
|
|
// refModifier allows an invoice ref to include or exclude specific
|
|
// HTLC sets based on the payAddr or setId.
|
|
refModifier RefModifier
|
|
}
|
|
|
|
// InvoiceRefByHash creates an InvoiceRef that queries for an invoice only by
|
|
// its payment hash.
|
|
func InvoiceRefByHash(payHash lntypes.Hash) InvoiceRef {
|
|
return InvoiceRef{
|
|
payHash: &payHash,
|
|
}
|
|
}
|
|
|
|
// InvoiceRefByHashAndAddr creates an InvoiceRef that first queries for an
|
|
// invoice by the provided payment address, falling back to the payment hash if
|
|
// the payment address is unknown.
|
|
func InvoiceRefByHashAndAddr(payHash lntypes.Hash,
|
|
payAddr [32]byte) InvoiceRef {
|
|
|
|
return InvoiceRef{
|
|
payHash: &payHash,
|
|
payAddr: &payAddr,
|
|
}
|
|
}
|
|
|
|
// InvoiceRefByAddr creates an InvoiceRef that queries the payment addr index
|
|
// for an invoice with the provided payment address.
|
|
func InvoiceRefByAddr(addr [32]byte) InvoiceRef {
|
|
return InvoiceRef{
|
|
payAddr: &addr,
|
|
}
|
|
}
|
|
|
|
// InvoiceRefByAddrBlankHtlc creates an InvoiceRef that queries the payment addr
|
|
// index for an invoice with the provided payment address, but excludes any of
|
|
// the core HTLC information.
|
|
func InvoiceRefByAddrBlankHtlc(addr [32]byte) InvoiceRef {
|
|
return InvoiceRef{
|
|
payAddr: &addr,
|
|
refModifier: HtlcSetBlankModifier,
|
|
}
|
|
}
|
|
|
|
// InvoiceRefBySetID creates an InvoiceRef that queries the set id index for an
|
|
// invoice with the provided setID. If the invoice is not found, the query will
|
|
// not fallback to payHash or payAddr.
|
|
func InvoiceRefBySetID(setID [32]byte) InvoiceRef {
|
|
return InvoiceRef{
|
|
setID: &setID,
|
|
}
|
|
}
|
|
|
|
// InvoiceRefBySetIDFiltered is similar to the InvoiceRefBySetID identifier,
|
|
// but it specifies that the returned set of HTLCs should be filtered to only
|
|
// include HTLCs that are part of that set.
|
|
func InvoiceRefBySetIDFiltered(setID [32]byte) InvoiceRef {
|
|
return InvoiceRef{
|
|
setID: &setID,
|
|
refModifier: HtlcSetOnlyModifier,
|
|
}
|
|
}
|
|
|
|
// PayHash returns the optional payment hash of the target invoice.
|
|
//
|
|
// NOTE: This value may be nil.
|
|
func (r InvoiceRef) PayHash() *lntypes.Hash {
|
|
if r.payHash != nil {
|
|
hash := *r.payHash
|
|
return &hash
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// PayAddr returns the optional payment address of the target invoice.
|
|
//
|
|
// NOTE: This value may be nil.
|
|
func (r InvoiceRef) PayAddr() *[32]byte {
|
|
if r.payAddr != nil {
|
|
addr := *r.payAddr
|
|
return &addr
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// SetID returns the optional set id of the target invoice.
|
|
//
|
|
// NOTE: This value may be nil.
|
|
func (r InvoiceRef) SetID() *[32]byte {
|
|
if r.setID != nil {
|
|
id := *r.setID
|
|
return &id
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// Modifier defines the set of available modifications to the base invoice ref
|
|
// look up that are available.
|
|
func (r InvoiceRef) Modifier() RefModifier {
|
|
return r.refModifier
|
|
}
|
|
|
|
// String returns a human-readable representation of an InvoiceRef.
|
|
func (r InvoiceRef) String() string {
|
|
var ids []string
|
|
if r.payHash != nil {
|
|
ids = append(ids, fmt.Sprintf("pay_hash=%v", *r.payHash))
|
|
}
|
|
if r.payAddr != nil {
|
|
ids = append(ids, fmt.Sprintf("pay_addr=%x", *r.payAddr))
|
|
}
|
|
if r.setID != nil {
|
|
ids = append(ids, fmt.Sprintf("set_id=%x", *r.setID))
|
|
}
|
|
|
|
return fmt.Sprintf("(%s)", strings.Join(ids, ", "))
|
|
}
|
|
|
|
// ContractState describes the state the invoice is in.
|
|
type ContractState uint8
|
|
|
|
const (
|
|
// ContractOpen means the invoice has only been created.
|
|
ContractOpen ContractState = 0
|
|
|
|
// ContractSettled means the htlc is settled and the invoice has been
|
|
// paid.
|
|
ContractSettled ContractState = 1
|
|
|
|
// ContractCanceled means the invoice has been canceled.
|
|
ContractCanceled ContractState = 2
|
|
|
|
// ContractAccepted means the HTLC has been accepted but not settled
|
|
// yet.
|
|
ContractAccepted ContractState = 3
|
|
)
|
|
|
|
// String returns a human readable identifier for the ContractState type.
|
|
func (c ContractState) String() string {
|
|
switch c {
|
|
case ContractOpen:
|
|
return "Open"
|
|
|
|
case ContractSettled:
|
|
return "Settled"
|
|
|
|
case ContractCanceled:
|
|
return "Canceled"
|
|
|
|
case ContractAccepted:
|
|
return "Accepted"
|
|
}
|
|
|
|
return "Unknown"
|
|
}
|
|
|
|
// IsFinal returns a boolean indicating whether an invoice state is final.
|
|
func (c ContractState) IsFinal() bool {
|
|
return c == ContractSettled || c == ContractCanceled
|
|
}
|
|
|
|
// ContractTerm is a companion struct to the Invoice struct. This struct houses
|
|
// the necessary conditions required before the invoice can be considered fully
|
|
// settled by the payee.
|
|
type ContractTerm struct {
|
|
// FinalCltvDelta is the minimum required number of blocks before htlc
|
|
// expiry when the invoice is accepted.
|
|
FinalCltvDelta int32
|
|
|
|
// Expiry defines how long after creation this invoice should expire.
|
|
Expiry time.Duration
|
|
|
|
// PaymentPreimage is the preimage which is to be revealed in the
|
|
// occasion that an HTLC paying to the hash of this preimage is
|
|
// extended. Set to nil if the preimage isn't known yet.
|
|
PaymentPreimage *lntypes.Preimage
|
|
|
|
// Value is the expected amount of milli-satoshis to be paid to an HTLC
|
|
// which can be satisfied by the above preimage.
|
|
Value lnwire.MilliSatoshi
|
|
|
|
// PaymentAddr is a randomly generated value include in the MPP record
|
|
// by the sender to prevent probing of the receiver.
|
|
PaymentAddr [32]byte
|
|
|
|
// Features is the feature vectors advertised on the payment request.
|
|
Features *lnwire.FeatureVector
|
|
}
|
|
|
|
// String returns a human-readable description of the prominent contract terms.
|
|
func (c ContractTerm) String() string {
|
|
return fmt.Sprintf("amt=%v, expiry=%v, final_cltv_delta=%v", c.Value,
|
|
c.Expiry, c.FinalCltvDelta)
|
|
}
|
|
|
|
// SetID is the extra unique tuple item for AMP invoices. In addition to
|
|
// setting a payment address, each repeated payment to an AMP invoice will also
|
|
// contain a set ID as well.
|
|
type SetID [32]byte
|
|
|
|
// InvoiceStateAMP is a struct that associates the current state of an AMP
|
|
// invoice identified by its set ID along with the set of invoices identified
|
|
// by the circuit key. This allows callers to easily look up the latest state
|
|
// of an AMP "sub-invoice" and also look up the invoice HLTCs themselves in the
|
|
// greater HTLC map index.
|
|
type InvoiceStateAMP struct {
|
|
// State is the state of this sub-AMP invoice.
|
|
State HtlcState
|
|
|
|
// SettleIndex indicates the location in the settle index that
|
|
// references this instance of InvoiceStateAMP, but only if
|
|
// this value is set (non-zero), and State is HtlcStateSettled.
|
|
SettleIndex uint64
|
|
|
|
// SettleDate is the date that the setID was settled.
|
|
SettleDate time.Time
|
|
|
|
// InvoiceKeys is the set of circuit keys that can be used to locate
|
|
// the invoices for a given set ID.
|
|
InvoiceKeys map[CircuitKey]struct{}
|
|
|
|
// AmtPaid is the total amount that was paid in the AMP sub-invoice.
|
|
// Fetching the full HTLC/invoice state allows one to extract the
|
|
// custom records as well as the break down of the payment splits used
|
|
// when paying.
|
|
AmtPaid lnwire.MilliSatoshi
|
|
}
|
|
|
|
// copy makes a deep copy of the underlying InvoiceStateAMP.
|
|
func (i *InvoiceStateAMP) copy() (InvoiceStateAMP, error) {
|
|
result := *i
|
|
|
|
// Make a copy of the InvoiceKeys map.
|
|
result.InvoiceKeys = make(map[CircuitKey]struct{})
|
|
for k := range i.InvoiceKeys {
|
|
result.InvoiceKeys[k] = struct{}{}
|
|
}
|
|
|
|
// As a safety measure, copy SettleDate. time.Time is concurrency safe
|
|
// except when using any of the (un)marshalling methods.
|
|
settleDateBytes, err := i.SettleDate.MarshalBinary()
|
|
if err != nil {
|
|
return InvoiceStateAMP{}, err
|
|
}
|
|
|
|
err = result.SettleDate.UnmarshalBinary(settleDateBytes)
|
|
if err != nil {
|
|
return InvoiceStateAMP{}, err
|
|
}
|
|
|
|
return result, nil
|
|
}
|
|
|
|
// AMPInvoiceState represents a type that stores metadata related to the set of
|
|
// settled AMP "sub-invoices".
|
|
type AMPInvoiceState map[SetID]InvoiceStateAMP
|
|
|
|
// Invoice is a payment invoice generated by a payee in order to request
|
|
// payment for some good or service. The inclusion of invoices within Lightning
|
|
// creates a payment work flow for merchants very similar to that of the
|
|
// existing financial system within PayPal, etc. Invoices are added to the
|
|
// database when a payment is requested, then can be settled manually once the
|
|
// payment is received at the upper layer. For record keeping purposes,
|
|
// invoices are never deleted from the database, instead a bit is toggled
|
|
// denoting the invoice has been fully settled. Within the database, all
|
|
// invoices must have a unique payment hash which is generated by taking the
|
|
// sha256 of the payment preimage.
|
|
type Invoice struct {
|
|
// Memo is an optional memo to be stored along side an invoice. The
|
|
// memo may contain further details pertaining to the invoice itself,
|
|
// or any other message which fits within the size constraints.
|
|
Memo []byte
|
|
|
|
// PaymentRequest is the encoded payment request for this invoice. For
|
|
// spontaneous (keysend) payments, this field will be empty.
|
|
PaymentRequest []byte
|
|
|
|
// CreationDate is the exact time the invoice was created.
|
|
CreationDate time.Time
|
|
|
|
// SettleDate is the exact time the invoice was settled.
|
|
SettleDate time.Time
|
|
|
|
// Terms are the contractual payment terms of the invoice. Once all the
|
|
// terms have been satisfied by the payer, then the invoice can be
|
|
// considered fully fulfilled.
|
|
//
|
|
// TODO(roasbeef): later allow for multiple terms to fulfill the final
|
|
// invoice: payment fragmentation, etc.
|
|
Terms ContractTerm
|
|
|
|
// AddIndex is an auto-incrementing integer that acts as a
|
|
// monotonically increasing sequence number for all invoices created.
|
|
// Clients can then use this field as a "checkpoint" of sorts when
|
|
// implementing a streaming RPC to notify consumers of instances where
|
|
// an invoice has been added before they re-connected.
|
|
//
|
|
// NOTE: This index starts at 1.
|
|
AddIndex uint64
|
|
|
|
// SettleIndex is an auto-incrementing integer that acts as a
|
|
// monotonically increasing sequence number for all settled invoices.
|
|
// Clients can then use this field as a "checkpoint" of sorts when
|
|
// implementing a streaming RPC to notify consumers of instances where
|
|
// an invoice has been settled before they re-connected.
|
|
//
|
|
// NOTE: This index starts at 1.
|
|
SettleIndex uint64
|
|
|
|
// State describes the state the invoice is in. This is the global
|
|
// state of the invoice which may remain open even when a series of
|
|
// sub-invoices for this invoice has been settled.
|
|
State ContractState
|
|
|
|
// AmtPaid is the final amount that we ultimately accepted for pay for
|
|
// this invoice. We specify this value independently as it's possible
|
|
// that the invoice originally didn't specify an amount, or the sender
|
|
// overpaid.
|
|
AmtPaid lnwire.MilliSatoshi
|
|
|
|
// Htlcs records all htlcs that paid to this invoice. Some of these
|
|
// htlcs may have been marked as canceled.
|
|
Htlcs map[CircuitKey]*InvoiceHTLC
|
|
|
|
// AMPState describes the state of any related sub-invoices AMP to this
|
|
// greater invoice. A sub-invoice is defined by a set of HTLCs with the
|
|
// same set ID that attempt to make one time or recurring payments to
|
|
// this greater invoice. It's possible for a sub-invoice to be canceled
|
|
// or settled, but the greater invoice still open.
|
|
AMPState AMPInvoiceState
|
|
|
|
// HodlInvoice indicates whether the invoice should be held in the
|
|
// Accepted state or be settled right away.
|
|
HodlInvoice bool
|
|
}
|
|
|
|
// HTLCSet returns the set of HTLCs belonging to setID and in the provided
|
|
// state. Passing a nil setID will return all HTLCs in the provided state in the
|
|
// case of legacy or MPP, and no HTLCs in the case of AMP. Otherwise, the
|
|
// returned set will be filtered by the populated setID which is used to
|
|
// retrieve AMP HTLC sets.
|
|
func (i *Invoice) HTLCSet(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
|
|
}
|
|
|
|
if !htlc.IsInHTLCSet(setID) {
|
|
continue
|
|
}
|
|
|
|
htlcSet[key] = htlc
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
// 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.
|
|
type HtlcState uint8
|
|
|
|
const (
|
|
// HtlcStateAccepted indicates the htlc is locked-in, but not resolved.
|
|
HtlcStateAccepted HtlcState = iota
|
|
|
|
// HtlcStateCanceled indicates the htlc is canceled back to the
|
|
// sender.
|
|
HtlcStateCanceled
|
|
|
|
// HtlcStateSettled indicates the htlc is settled.
|
|
HtlcStateSettled
|
|
)
|
|
|
|
// InvoiceHTLC contains details about an htlc paying to this invoice.
|
|
type InvoiceHTLC struct {
|
|
// Amt is the amount that is carried by this htlc.
|
|
Amt lnwire.MilliSatoshi
|
|
|
|
// MppTotalAmt is a field for mpp that indicates the expected total
|
|
// amount.
|
|
MppTotalAmt lnwire.MilliSatoshi
|
|
|
|
// AcceptHeight is the block height at which the invoice registry
|
|
// decided to accept this htlc as a payment to the invoice. At this
|
|
// height, the invoice cltv delay must have been met.
|
|
AcceptHeight uint32
|
|
|
|
// AcceptTime is the wall clock time at which the invoice registry
|
|
// decided to accept the htlc.
|
|
AcceptTime time.Time
|
|
|
|
// ResolveTime is the wall clock time at which the invoice registry
|
|
// decided to settle the htlc.
|
|
ResolveTime time.Time
|
|
|
|
// Expiry is the expiry height of this htlc.
|
|
Expiry uint32
|
|
|
|
// State indicates the state the invoice htlc is currently in. A
|
|
// canceled htlc isn't just removed from the invoice htlcs map, because
|
|
// we need AcceptHeight to properly cancel the htlc back.
|
|
State HtlcState
|
|
|
|
// CustomRecords contains the custom key/value pairs that accompanied
|
|
// the htlc.
|
|
CustomRecords record.CustomSet
|
|
|
|
// AMP encapsulates additional data relevant to AMP HTLCs. This includes
|
|
// the AMP onion record, in addition to the HTLC's payment hash and
|
|
// preimage since these are unique to each AMP HTLC, and not the invoice
|
|
// as a whole.
|
|
//
|
|
// NOTE: This value will only be set for AMP HTLCs.
|
|
AMP *InvoiceHtlcAMPData
|
|
}
|
|
|
|
// Copy makes a deep copy of the target InvoiceHTLC.
|
|
func (h *InvoiceHTLC) Copy() *InvoiceHTLC {
|
|
result := *h
|
|
|
|
// Make a copy of the CustomSet map.
|
|
result.CustomRecords = make(record.CustomSet)
|
|
for k, v := range h.CustomRecords {
|
|
result.CustomRecords[k] = v
|
|
}
|
|
|
|
result.AMP = h.AMP.Copy()
|
|
|
|
return &result
|
|
}
|
|
|
|
// IsInHTLCSet returns true if this HTLC is part an HTLC set. If nil is passed,
|
|
// this method returns true if this is an MPP HTLC. Otherwise, it only returns
|
|
// true if the AMP HTLC's set id matches the populated setID.
|
|
func (h *InvoiceHTLC) IsInHTLCSet(setID *[32]byte) bool {
|
|
wantAMPSet := setID != nil
|
|
isAMPHtlc := h.AMP != nil
|
|
|
|
// Non-AMP HTLCs cannot be part of AMP HTLC sets, and vice versa.
|
|
if wantAMPSet != isAMPHtlc {
|
|
return false
|
|
}
|
|
|
|
// Skip AMP HTLCs that have differing set ids.
|
|
if isAMPHtlc && *setID != h.AMP.Record.SetID() {
|
|
return false
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
// InvoiceHtlcAMPData is a struct hodling the additional metadata stored for
|
|
// each received AMP HTLC. This includes the AMP onion record, in addition to
|
|
// the HTLC's payment hash and preimage.
|
|
type InvoiceHtlcAMPData struct {
|
|
// AMP is a copy of the AMP record presented in the onion payload
|
|
// containing the information necessary to correlate and settle a
|
|
// spontaneous HTLC set. Newly accepted legacy keysend payments will
|
|
// also have this field set as we automatically promote them into an AMP
|
|
// payment for internal processing.
|
|
Record record.AMP
|
|
|
|
// Hash is an HTLC-level payment hash that is stored only for AMP
|
|
// payments. This is done because an AMP HTLC will carry a different
|
|
// payment hash from the invoice it might be satisfying, so we track the
|
|
// payment hashes individually to able to compute whether or not the
|
|
// reconstructed preimage correctly matches the HTLC's hash.
|
|
Hash lntypes.Hash
|
|
|
|
// Preimage is an HTLC-level preimage that satisfies the AMP HTLC's
|
|
// Hash. The preimage will be derived either from secret share
|
|
// reconstruction of the shares in the AMP payload.
|
|
//
|
|
// NOTE: Preimage will only be present once the HTLC is in
|
|
// HtlcStateSettled.
|
|
Preimage *lntypes.Preimage
|
|
}
|
|
|
|
// Copy returns a deep copy of the InvoiceHtlcAMPData.
|
|
func (d *InvoiceHtlcAMPData) Copy() *InvoiceHtlcAMPData {
|
|
if d == nil {
|
|
return nil
|
|
}
|
|
|
|
var preimage *lntypes.Preimage
|
|
if d.Preimage != nil {
|
|
pimg := *d.Preimage
|
|
preimage = &pimg
|
|
}
|
|
|
|
return &InvoiceHtlcAMPData{
|
|
Record: d.Record,
|
|
Hash: d.Hash,
|
|
Preimage: preimage,
|
|
}
|
|
}
|
|
|
|
// HtlcAcceptDesc describes the details of a newly accepted htlc.
|
|
type HtlcAcceptDesc struct {
|
|
// AcceptHeight is the block height at which this htlc was accepted.
|
|
AcceptHeight int32
|
|
|
|
// Amt is the amount that is carried by this htlc.
|
|
Amt lnwire.MilliSatoshi
|
|
|
|
// MppTotalAmt is a field for mpp that indicates the expected total
|
|
// amount.
|
|
MppTotalAmt lnwire.MilliSatoshi
|
|
|
|
// Expiry is the expiry height of this htlc.
|
|
Expiry uint32
|
|
|
|
// CustomRecords contains the custom key/value pairs that accompanied
|
|
// the htlc.
|
|
CustomRecords record.CustomSet
|
|
|
|
// AMP encapsulates additional data relevant to AMP HTLCs. This includes
|
|
// the AMP onion record, in addition to the HTLC's payment hash and
|
|
// preimage since these are unique to each AMP HTLC, and not the invoice
|
|
// as a whole.
|
|
//
|
|
// NOTE: This value will only be set for AMP HTLCs.
|
|
AMP *InvoiceHtlcAMPData
|
|
}
|
|
|
|
// UpdateType is an enum that describes the type of update that was applied to
|
|
// an invoice.
|
|
type UpdateType uint8
|
|
|
|
const (
|
|
// UnknownUpdate indicates that the UpdateType has not been set for a
|
|
// given udpate. This kind of updates are not allowed.
|
|
UnknownUpdate UpdateType = iota
|
|
|
|
// CancelHTLCsUpdate indicates that this update cancels one or more
|
|
// HTLCs.
|
|
CancelHTLCsUpdate
|
|
|
|
// AddHTLCsUpdate indicates that this update adds one or more HTLCs.
|
|
AddHTLCsUpdate
|
|
|
|
// SettleHodlInvoiceUpdate indicates that this update settles one or
|
|
// more HTLCs from a hodl invoice.
|
|
SettleHodlInvoiceUpdate
|
|
|
|
// CancelInvoiceUpdate indicates that this update is trying to cancel
|
|
// an invoice.
|
|
CancelInvoiceUpdate
|
|
)
|
|
|
|
// String returns a human readable string for the UpdateType.
|
|
func (u UpdateType) String() string {
|
|
switch u {
|
|
case CancelHTLCsUpdate:
|
|
return "CancelHTLCsUpdate"
|
|
|
|
case AddHTLCsUpdate:
|
|
return "AddHTLCsUpdate"
|
|
|
|
case SettleHodlInvoiceUpdate:
|
|
return "SettleHodlInvoiceUpdate"
|
|
|
|
case CancelInvoiceUpdate:
|
|
return "CancelInvoiceUpdate"
|
|
|
|
default:
|
|
return fmt.Sprintf("unknown invoice update type: %d", u)
|
|
}
|
|
}
|
|
|
|
// InvoiceUpdateDesc describes the changes that should be applied to the
|
|
// invoice.
|
|
type InvoiceUpdateDesc struct {
|
|
// State is the new state that this invoice should progress to. If nil,
|
|
// the state is left unchanged.
|
|
State *InvoiceStateUpdateDesc
|
|
|
|
// CancelHtlcs describes the htlcs that need to be canceled.
|
|
CancelHtlcs map[CircuitKey]struct{}
|
|
|
|
// AddHtlcs describes the newly accepted htlcs that need to be added to
|
|
// the invoice.
|
|
AddHtlcs map[CircuitKey]*HtlcAcceptDesc
|
|
|
|
// SetID is an optional set ID for AMP invoices that allows operations
|
|
// to be more efficient by ensuring we don't need to read out the
|
|
// entire HTLC set each timee an HTLC is to be cancelled.
|
|
SetID *SetID
|
|
|
|
// UpdateType indicates what type of update is being applied.
|
|
UpdateType UpdateType
|
|
}
|
|
|
|
// InvoiceStateUpdateDesc describes an invoice-level state transition.
|
|
type InvoiceStateUpdateDesc struct {
|
|
// NewState is the new state that this invoice should progress to.
|
|
NewState ContractState
|
|
|
|
// Preimage must be set to the preimage when NewState is settled.
|
|
Preimage *lntypes.Preimage
|
|
|
|
// HTLCPreimages set the HTLC-level preimages stored for AMP HTLCs.
|
|
// These are only learned when settling the invoice as a whole. Must be
|
|
// set when settling an invoice with non-nil SetID.
|
|
HTLCPreimages map[CircuitKey]lntypes.Preimage
|
|
|
|
// SetID identifies a specific set of HTLCs destined for the same
|
|
// invoice as part of a larger AMP payment. This value will be nil for
|
|
// legacy or MPP payments.
|
|
SetID *[32]byte
|
|
}
|
|
|
|
// InvoiceUpdateCallback is a callback used in the db transaction to update the
|
|
// invoice.
|
|
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 {
|
|
// Avoid conflicts with all-zeroes magic value in the database.
|
|
if paymentHash == UnknownPreimage.Hash() {
|
|
return fmt.Errorf("cannot use hash of all-zeroes preimage")
|
|
}
|
|
|
|
if len(i.Memo) > MaxMemoSize {
|
|
return fmt.Errorf("max length a memo is %v, and invoice "+
|
|
"of length %v was provided", MaxMemoSize, len(i.Memo))
|
|
}
|
|
if len(i.PaymentRequest) > MaxPaymentRequestSize {
|
|
return fmt.Errorf("max length of payment request is %v, "+
|
|
"length provided was %v", MaxPaymentRequestSize,
|
|
len(i.PaymentRequest))
|
|
}
|
|
if i.Terms.Features == nil {
|
|
return errors.New("invoice must have a feature vector")
|
|
}
|
|
|
|
err := feature.ValidateDeps(i.Terms.Features)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if i.requiresPreimage() && i.Terms.PaymentPreimage == nil {
|
|
return errors.New("this invoice must have a preimage")
|
|
}
|
|
|
|
if len(i.Htlcs) > 0 {
|
|
return ErrInvoiceHasHtlcs
|
|
}
|
|
|
|
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.
|
|
func (i *Invoice) IsPending() bool {
|
|
return i.State == ContractOpen || i.State == ContractAccepted
|
|
}
|
|
|
|
// copySlice allocates a new slice and copies the source into it.
|
|
func copySlice(src []byte) []byte {
|
|
dest := make([]byte, len(src))
|
|
copy(dest, src)
|
|
return dest
|
|
}
|
|
|
|
// CopyInvoice makes a deep copy of the supplied invoice.
|
|
func CopyInvoice(src *Invoice) (*Invoice, error) {
|
|
dest := Invoice{
|
|
Memo: copySlice(src.Memo),
|
|
PaymentRequest: copySlice(src.PaymentRequest),
|
|
CreationDate: src.CreationDate,
|
|
SettleDate: src.SettleDate,
|
|
Terms: src.Terms,
|
|
AddIndex: src.AddIndex,
|
|
SettleIndex: src.SettleIndex,
|
|
State: src.State,
|
|
AmtPaid: src.AmtPaid,
|
|
Htlcs: make(
|
|
map[CircuitKey]*InvoiceHTLC, len(src.Htlcs),
|
|
),
|
|
AMPState: make(map[SetID]InvoiceStateAMP),
|
|
HodlInvoice: src.HodlInvoice,
|
|
}
|
|
|
|
dest.Terms.Features = src.Terms.Features.Clone()
|
|
|
|
if src.Terms.PaymentPreimage != nil {
|
|
preimage := *src.Terms.PaymentPreimage
|
|
dest.Terms.PaymentPreimage = &preimage
|
|
}
|
|
|
|
for k, v := range src.Htlcs {
|
|
dest.Htlcs[k] = v.Copy()
|
|
}
|
|
|
|
// Lastly, copy the amp invoice state.
|
|
for k, v := range src.AMPState {
|
|
ampInvState, err := v.copy()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
dest.AMPState[k] = ampInvState
|
|
}
|
|
|
|
return &dest, nil
|
|
}
|
|
|
|
// InvoiceDeleteRef holds a reference to an invoice to be deleted.
|
|
type InvoiceDeleteRef struct {
|
|
// PayHash is the payment hash of the target invoice. All invoices are
|
|
// currently indexed by payment hash.
|
|
PayHash lntypes.Hash
|
|
|
|
// PayAddr is the payment addr of the target invoice. Newer invoices
|
|
// (0.11 and up) are indexed by payment address in addition to payment
|
|
// hash, but pre 0.8 invoices do not have one at all.
|
|
PayAddr *[32]byte
|
|
|
|
// AddIndex is the add index of the invoice.
|
|
AddIndex uint64
|
|
|
|
// SettleIndex is the settle index of the invoice.
|
|
SettleIndex uint64
|
|
}
|