• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

lightningnetwork / lnd / 13980275562

20 Mar 2025 10:06PM UTC coverage: 58.6% (-10.2%) from 68.789%
13980275562

Pull #9623

github

web-flow
Merge b9b960345 into 09b674508
Pull Request #9623: Size msg test msg

0 of 1518 new or added lines in 42 files covered. (0.0%)

26603 existing lines in 443 files now uncovered.

96807 of 165200 relevant lines covered (58.6%)

1.82 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

76.01
/invoices/invoices.go
1
package invoices
2

3
import (
4
        "errors"
5
        "fmt"
6
        "strings"
7
        "time"
8

9
        "github.com/lightningnetwork/lnd/feature"
10
        "github.com/lightningnetwork/lnd/lntypes"
11
        "github.com/lightningnetwork/lnd/lnwire"
12
        "github.com/lightningnetwork/lnd/record"
13
)
14

15
const (
16
        // MaxMemoSize is maximum size of the memo field within invoices stored
17
        // in the database.
18
        MaxMemoSize = 1024
19

20
        // MaxPaymentRequestSize is the max size of a payment request for
21
        // this invoice.
22
        // TODO(halseth): determine the max length payment request when field
23
        // lengths are final.
24
        MaxPaymentRequestSize = 4096
25
)
26

27
var (
28
        // unknownPreimage is an all-zeroes preimage that indicates that the
29
        // preimage for this invoice is not yet known.
30
        UnknownPreimage lntypes.Preimage
31

32
        // BlankPayAddr is a sentinel payment address for legacy invoices.
33
        // Invoices with this payment address are special-cased in the insertion
34
        // logic to prevent being indexed in the payment address index,
35
        // otherwise they would cause collisions after the first insertion.
36
        BlankPayAddr [32]byte
37
)
38

39
// RefModifier is a modification on top of a base invoice ref. It allows the
40
// caller to opt to skip out on HTLCs for a given payAddr, or only return the
41
// set of specified HTLCs for a given setID.
42
type RefModifier uint8
43

44
const (
45
        // DefaultModifier is the base modifier that doesn't change any
46
        // behavior.
47
        DefaultModifier RefModifier = iota
48

49
        // HtlcSetOnlyModifier can only be used with a setID based invoice ref,
50
        // and specifies that only the set of HTLCs related to that setID are
51
        // to be returned.
52
        HtlcSetOnlyModifier
53

54
        // HtlcSetOnlyModifier can only be used with a payAddr based invoice
55
        // ref, and specifies that the returned invoice shouldn't include any
56
        // HTLCs at all.
57
        HtlcSetBlankModifier
58
)
59

60
// InvoiceRef is a composite identifier for invoices. Invoices can be referenced
61
// by various combinations of payment hash and payment addr, in certain contexts
62
// only some of these are known. An InvoiceRef and its constructors thus
63
// encapsulate the valid combinations of query parameters that can be supplied
64
// to LookupInvoice and UpdateInvoice.
65
type InvoiceRef struct {
66
        // payHash is the payment hash of the target invoice. All invoices are
67
        // currently indexed by payment hash. This value will be used as a
68
        // fallback when no payment address is known.
69
        payHash *lntypes.Hash
70

71
        // payAddr is the payment addr of the target invoice. Newer invoices
72
        // (0.11 and up) are indexed by payment address in addition to payment
73
        // hash, but pre 0.8 invoices do not have one at all. When this value is
74
        // known it will be used as the primary identifier, falling back to
75
        // payHash if no value is known.
76
        payAddr *[32]byte
77

78
        // setID is the optional set id for an AMP payment. This can be used to
79
        // lookup or update the invoice knowing only this value. Queries by set
80
        // id are only used to facilitate user-facing requests, e.g. lookup,
81
        // settle or cancel an AMP invoice. The regular update flow from the
82
        // invoice registry will always query for the invoice by
83
        // payHash+payAddr.
84
        setID *[32]byte
85

86
        // refModifier allows an invoice ref to include or exclude specific
87
        // HTLC sets based on the payAddr or setId.
88
        refModifier RefModifier
89
}
90

91
// InvoiceRefByHash creates an InvoiceRef that queries for an invoice only by
92
// its payment hash.
93
func InvoiceRefByHash(payHash lntypes.Hash) InvoiceRef {
3✔
94
        return InvoiceRef{
3✔
95
                payHash: &payHash,
3✔
96
        }
3✔
97
}
3✔
98

99
// InvoiceRefByHashAndAddr creates an InvoiceRef that first queries for an
100
// invoice by the provided payment address, falling back to the payment hash if
101
// the payment address is unknown.
102
func InvoiceRefByHashAndAddr(payHash lntypes.Hash,
103
        payAddr [32]byte) InvoiceRef {
3✔
104

3✔
105
        return InvoiceRef{
3✔
106
                payHash: &payHash,
3✔
107
                payAddr: &payAddr,
3✔
108
        }
3✔
109
}
3✔
110

111
// InvoiceRefByAddr creates an InvoiceRef that queries the payment addr index
112
// for an invoice with the provided payment address.
113
func InvoiceRefByAddr(addr [32]byte) InvoiceRef {
3✔
114
        return InvoiceRef{
3✔
115
                payAddr: &addr,
3✔
116
        }
3✔
117
}
3✔
118

119
// InvoiceRefByAddrBlankHtlc creates an InvoiceRef that queries the payment addr
120
// index for an invoice with the provided payment address, but excludes any of
121
// the core HTLC information.
122
func InvoiceRefByAddrBlankHtlc(addr [32]byte) InvoiceRef {
3✔
123
        return InvoiceRef{
3✔
124
                payAddr:     &addr,
3✔
125
                refModifier: HtlcSetBlankModifier,
3✔
126
        }
3✔
127
}
3✔
128

129
// InvoiceRefBySetID creates an InvoiceRef that queries the set id index for an
130
// invoice with the provided setID. If the invoice is not found, the query will
131
// not fallback to payHash or payAddr.
132
func InvoiceRefBySetID(setID [32]byte) InvoiceRef {
3✔
133
        return InvoiceRef{
3✔
134
                setID: &setID,
3✔
135
        }
3✔
136
}
3✔
137

138
// InvoiceRefBySetIDFiltered is similar to the InvoiceRefBySetID identifier,
139
// but it specifies that the returned set of HTLCs should be filtered to only
140
// include HTLCs that are part of that set.
141
func InvoiceRefBySetIDFiltered(setID [32]byte) InvoiceRef {
3✔
142
        return InvoiceRef{
3✔
143
                setID:       &setID,
3✔
144
                refModifier: HtlcSetOnlyModifier,
3✔
145
        }
3✔
146
}
3✔
147

148
// PayHash returns the optional payment hash of the target invoice.
149
//
150
// NOTE: This value may be nil.
151
func (r InvoiceRef) PayHash() *lntypes.Hash {
3✔
152
        if r.payHash != nil {
6✔
153
                hash := *r.payHash
3✔
154
                return &hash
3✔
155
        }
3✔
156

157
        return nil
3✔
158
}
159

160
// PayAddr returns the optional payment address of the target invoice.
161
//
162
// NOTE: This value may be nil.
163
func (r InvoiceRef) PayAddr() *[32]byte {
3✔
164
        if r.payAddr != nil {
6✔
165
                addr := *r.payAddr
3✔
166
                return &addr
3✔
167
        }
3✔
168

169
        return nil
3✔
170
}
171

172
// SetID returns the optional set id of the target invoice.
173
//
174
// NOTE: This value may be nil.
175
func (r InvoiceRef) SetID() *[32]byte {
3✔
176
        if r.setID != nil {
6✔
177
                id := *r.setID
3✔
178
                return &id
3✔
179
        }
3✔
180

181
        return nil
3✔
182
}
183

184
// Modifier defines the set of available modifications to the base invoice ref
185
// look up that are available.
186
func (r InvoiceRef) Modifier() RefModifier {
3✔
187
        return r.refModifier
3✔
188
}
3✔
189

190
// IsHashOnly returns true if the invoice ref only contains a payment hash.
UNCOV
191
func (r InvoiceRef) IsHashOnly() bool {
×
UNCOV
192
        return r.payHash != nil && r.payAddr == nil && r.setID == nil
×
UNCOV
193
}
×
194

195
// String returns a human-readable representation of an InvoiceRef.
196
func (r InvoiceRef) String() string {
3✔
197
        var ids []string
3✔
198
        if r.payHash != nil {
6✔
199
                ids = append(ids, fmt.Sprintf("pay_hash=%v", *r.payHash))
3✔
200
        }
3✔
201
        if r.payAddr != nil {
6✔
202
                ids = append(ids, fmt.Sprintf("pay_addr=%x", *r.payAddr))
3✔
203
        }
3✔
204
        if r.setID != nil {
6✔
205
                ids = append(ids, fmt.Sprintf("set_id=%x", *r.setID))
3✔
206
        }
3✔
207

208
        return fmt.Sprintf("(%s)", strings.Join(ids, ", "))
3✔
209
}
210

211
// ContractState describes the state the invoice is in.
212
type ContractState uint8
213

214
const (
215
        // ContractOpen means the invoice has only been created.
216
        ContractOpen ContractState = 0
217

218
        // ContractSettled means the htlc is settled and the invoice has been
219
        // paid.
220
        ContractSettled ContractState = 1
221

222
        // ContractCanceled means the invoice has been canceled.
223
        ContractCanceled ContractState = 2
224

225
        // ContractAccepted means the HTLC has been accepted but not settled
226
        // yet.
227
        ContractAccepted ContractState = 3
228
)
229

230
// String returns a human readable identifier for the ContractState type.
UNCOV
231
func (c ContractState) String() string {
×
UNCOV
232
        switch c {
×
UNCOV
233
        case ContractOpen:
×
UNCOV
234
                return "Open"
×
235

236
        case ContractSettled:
×
237
                return "Settled"
×
238

239
        case ContractCanceled:
×
240
                return "Canceled"
×
241

242
        case ContractAccepted:
×
243
                return "Accepted"
×
244
        }
245

246
        return "Unknown"
×
247
}
248

249
// IsFinal returns a boolean indicating whether an invoice state is final.
250
func (c ContractState) IsFinal() bool {
3✔
251
        return c == ContractSettled || c == ContractCanceled
3✔
252
}
3✔
253

254
// ContractTerm is a companion struct to the Invoice struct. This struct houses
255
// the necessary conditions required before the invoice can be considered fully
256
// settled by the payee.
257
type ContractTerm struct {
258
        // FinalCltvDelta is the minimum required number of blocks before htlc
259
        // expiry when the invoice is accepted.
260
        FinalCltvDelta int32
261

262
        // Expiry defines how long after creation this invoice should expire.
263
        Expiry time.Duration
264

265
        // PaymentPreimage is the preimage which is to be revealed in the
266
        // occasion that an HTLC paying to the hash of this preimage is
267
        // extended. Set to nil if the preimage isn't known yet.
268
        PaymentPreimage *lntypes.Preimage
269

270
        // Value is the expected amount of milli-satoshis to be paid to an HTLC
271
        // which can be satisfied by the above preimage.
272
        Value lnwire.MilliSatoshi
273

274
        // PaymentAddr is a randomly generated value include in the MPP record
275
        // by the sender to prevent probing of the receiver.
276
        PaymentAddr [32]byte
277

278
        // Features is the feature vectors advertised on the payment request.
279
        Features *lnwire.FeatureVector
280
}
281

282
// String returns a human-readable description of the prominent contract terms.
283
func (c ContractTerm) String() string {
3✔
284
        return fmt.Sprintf("amt=%v, expiry=%v, final_cltv_delta=%v", c.Value,
3✔
285
                c.Expiry, c.FinalCltvDelta)
3✔
286
}
3✔
287

288
// SetID is the extra unique tuple item for AMP invoices. In addition to
289
// setting a payment address, each repeated payment to an AMP invoice will also
290
// contain a set ID as well.
291
type SetID [32]byte
292

293
// InvoiceStateAMP is a struct that associates the current state of an AMP
294
// invoice identified by its set ID along with the set of invoices identified
295
// by the circuit key. This allows callers to easily look up the latest state
296
// of an AMP "sub-invoice" and also look up the invoice HLTCs themselves in the
297
// greater HTLC map index.
298
type InvoiceStateAMP struct {
299
        // State is the state of this sub-AMP invoice.
300
        State HtlcState
301

302
        // SettleIndex indicates the location in the settle index that
303
        // references this instance of InvoiceStateAMP, but only if
304
        // this value is set (non-zero), and State is HtlcStateSettled.
305
        SettleIndex uint64
306

307
        // SettleDate is the date that the setID was settled.
308
        SettleDate time.Time
309

310
        // InvoiceKeys is the set of circuit keys that can be used to locate
311
        // the invoices for a given set ID.
312
        InvoiceKeys map[CircuitKey]struct{}
313

314
        // AmtPaid is the total amount that was paid in the AMP sub-invoice.
315
        // Fetching the full HTLC/invoice state allows one to extract the
316
        // custom records as well as the break down of the payment splits used
317
        // when paying.
318
        AmtPaid lnwire.MilliSatoshi
319
}
320

321
// copy makes a deep copy of the underlying InvoiceStateAMP.
322
func (i *InvoiceStateAMP) copy() (InvoiceStateAMP, error) {
3✔
323
        result := *i
3✔
324

3✔
325
        // Make a copy of the InvoiceKeys map.
3✔
326
        result.InvoiceKeys = make(map[CircuitKey]struct{})
3✔
327
        for k := range i.InvoiceKeys {
6✔
328
                result.InvoiceKeys[k] = struct{}{}
3✔
329
        }
3✔
330

331
        // As a safety measure, copy SettleDate. time.Time is concurrency safe
332
        // except when using any of the (un)marshalling methods.
333
        settleDateBytes, err := i.SettleDate.MarshalBinary()
3✔
334
        if err != nil {
3✔
335
                return InvoiceStateAMP{}, err
×
336
        }
×
337

338
        err = result.SettleDate.UnmarshalBinary(settleDateBytes)
3✔
339
        if err != nil {
3✔
340
                return InvoiceStateAMP{}, err
×
341
        }
×
342

343
        return result, nil
3✔
344
}
345

346
// AMPInvoiceState represents a type that stores metadata related to the set of
347
// settled AMP "sub-invoices".
348
type AMPInvoiceState map[SetID]InvoiceStateAMP
349

350
// Invoice is a payment invoice generated by a payee in order to request
351
// payment for some good or service. The inclusion of invoices within Lightning
352
// creates a payment work flow for merchants very similar to that of the
353
// existing financial system within PayPal, etc.  Invoices are added to the
354
// database when a payment is requested, then can be settled manually once the
355
// payment is received at the upper layer. For record keeping purposes,
356
// invoices are never deleted from the database, instead a bit is toggled
357
// denoting the invoice has been fully settled. Within the database, all
358
// invoices must have a unique payment hash which is generated by taking the
359
// sha256 of the payment preimage.
360
type Invoice struct {
361
        // Memo is an optional memo to be stored along side an invoice.  The
362
        // memo may contain further details pertaining to the invoice itself,
363
        // or any other message which fits within the size constraints.
364
        Memo []byte
365

366
        // PaymentRequest is the encoded payment request for this invoice. For
367
        // spontaneous (keysend) payments, this field will be empty.
368
        PaymentRequest []byte
369

370
        // CreationDate is the exact time the invoice was created.
371
        CreationDate time.Time
372

373
        // SettleDate is the exact time the invoice was settled.
374
        SettleDate time.Time
375

376
        // Terms are the contractual payment terms of the invoice. Once all the
377
        // terms have been satisfied by the payer, then the invoice can be
378
        // considered fully fulfilled.
379
        //
380
        // TODO(roasbeef): later allow for multiple terms to fulfill the final
381
        // invoice: payment fragmentation, etc.
382
        Terms ContractTerm
383

384
        // AddIndex is an auto-incrementing integer that acts as a
385
        // monotonically increasing sequence number for all invoices created.
386
        // Clients can then use this field as a "checkpoint" of sorts when
387
        // implementing a streaming RPC to notify consumers of instances where
388
        // an invoice has been added before they re-connected.
389
        //
390
        // NOTE: This index starts at 1.
391
        AddIndex uint64
392

393
        // SettleIndex is an auto-incrementing integer that acts as a
394
        // monotonically increasing sequence number for all settled invoices.
395
        // Clients can then use this field as a "checkpoint" of sorts when
396
        // implementing a streaming RPC to notify consumers of instances where
397
        // an invoice has been settled before they re-connected.
398
        //
399
        // NOTE: This index starts at 1.
400
        SettleIndex uint64
401

402
        // State describes the state the invoice is in. This is the global
403
        // state of the invoice which may remain open even when a series of
404
        // sub-invoices for this invoice has been settled.
405
        State ContractState
406

407
        // AmtPaid is the final amount that we ultimately accepted for pay for
408
        // this invoice. We specify this value independently as it's possible
409
        // that the invoice originally didn't specify an amount, or the sender
410
        // overpaid.
411
        AmtPaid lnwire.MilliSatoshi
412

413
        // Htlcs records all htlcs that paid to this invoice. Some of these
414
        // htlcs may have been marked as canceled.
415
        Htlcs map[CircuitKey]*InvoiceHTLC
416

417
        // AMPState describes the state of any related sub-invoices AMP to this
418
        // greater invoice. A sub-invoice is defined by a set of HTLCs with the
419
        // same set ID that attempt to make one time or recurring payments to
420
        // this greater invoice. It's possible for a sub-invoice to be canceled
421
        // or settled, but the greater invoice still open.
422
        AMPState AMPInvoiceState
423

424
        // HodlInvoice indicates whether the invoice should be held in the
425
        // Accepted state or be settled right away.
426
        HodlInvoice bool
427
}
428

429
// HTLCSet returns the set of HTLCs belonging to setID and in the provided
430
// state. Passing a nil setID will return all HTLCs in the provided state in the
431
// case of legacy or MPP, and no HTLCs in the case of AMP.  Otherwise, the
432
// returned set will be filtered by the populated setID which is used to
433
// retrieve AMP HTLC sets.
434
func (i *Invoice) HTLCSet(setID *[32]byte,
435
        state HtlcState) map[CircuitKey]*InvoiceHTLC {
3✔
436

3✔
437
        htlcSet := make(map[CircuitKey]*InvoiceHTLC)
3✔
438
        for key, htlc := range i.Htlcs {
6✔
439
                // Only add HTLCs that are in the requested HtlcState.
3✔
440
                if htlc.State != state {
3✔
UNCOV
441
                        continue
×
442
                }
443

444
                if !htlc.IsInHTLCSet(setID) {
3✔
UNCOV
445
                        continue
×
446
                }
447

448
                htlcSet[key] = htlc
3✔
449
        }
450

451
        return htlcSet
3✔
452
}
453

454
// HTLCSetCompliment returns the set of all HTLCs not belonging to setID that
455
// are in the target state. Passing a nil setID will return no invoices, since
456
// all MPP HTLCs are part of the same HTLC set.
457
func (i *Invoice) HTLCSetCompliment(setID *[32]byte,
458
        state HtlcState) map[CircuitKey]*InvoiceHTLC {
3✔
459

3✔
460
        htlcSet := make(map[CircuitKey]*InvoiceHTLC)
3✔
461
        for key, htlc := range i.Htlcs {
6✔
462
                // Only add HTLCs that are in the requested HtlcState.
3✔
463
                if htlc.State != state {
6✔
464
                        continue
3✔
465
                }
466

467
                // We are constructing the compliment, so filter anything that
468
                // matches this set id.
UNCOV
469
                if htlc.IsInHTLCSet(setID) {
×
UNCOV
470
                        continue
×
471
                }
472

473
                htlcSet[key] = htlc
×
474
        }
475

476
        return htlcSet
3✔
477
}
478

479
// IsKeysend returns true if the invoice is a Keysend invoice.
480
func (i *Invoice) IsKeysend() bool {
3✔
481
        // TODO(positiveblue): look for a more reliable way to tests if
3✔
482
        // an invoice is keysend.
3✔
483
        return len(i.PaymentRequest) == 0 && !i.IsAMP()
3✔
484
}
3✔
485

486
// IsAMP returns true if the invoice is an AMP invoice.
487
func (i *Invoice) IsAMP() bool {
3✔
488
        if i.Terms.Features == nil {
3✔
489
                return false
×
490
        }
×
491

492
        return i.Terms.Features.HasFeature(
3✔
493
                lnwire.AMPRequired,
3✔
494
        )
3✔
495
}
496

497
// IsBlinded returns true if the invoice contains blinded paths.
498
func (i *Invoice) IsBlinded() bool {
3✔
499
        if i.Terms.Features == nil {
3✔
500
                return false
×
501
        }
×
502

503
        return i.Terms.Features.IsSet(lnwire.Bolt11BlindedPathsRequired)
3✔
504
}
505

506
// HtlcState defines the states an htlc paying to an invoice can be in.
507
type HtlcState uint8
508

509
const (
510
        // HtlcStateAccepted indicates the htlc is locked-in, but not resolved.
511
        HtlcStateAccepted HtlcState = iota
512

513
        // HtlcStateCanceled indicates the htlc is canceled back to the
514
        // sender.
515
        HtlcStateCanceled
516

517
        // HtlcStateSettled indicates the htlc is settled.
518
        HtlcStateSettled
519
)
520

521
// InvoiceHTLC contains details about an htlc paying to this invoice.
522
type InvoiceHTLC struct {
523
        // Amt is the amount that is carried by this htlc.
524
        Amt lnwire.MilliSatoshi
525

526
        // MppTotalAmt is a field for mpp that indicates the expected total
527
        // amount.
528
        MppTotalAmt lnwire.MilliSatoshi
529

530
        // AcceptHeight is the block height at which the invoice registry
531
        // decided to accept this htlc as a payment to the invoice. At this
532
        // height, the invoice cltv delay must have been met.
533
        AcceptHeight uint32
534

535
        // AcceptTime is the wall clock time at which the invoice registry
536
        // decided to accept the htlc.
537
        AcceptTime time.Time
538

539
        // ResolveTime is the wall clock time at which the invoice registry
540
        // decided to settle the htlc.
541
        ResolveTime time.Time
542

543
        // Expiry is the expiry height of this htlc.
544
        Expiry uint32
545

546
        // State indicates the state the invoice htlc is currently in. A
547
        // canceled htlc isn't just removed from the invoice htlcs map, because
548
        // we need AcceptHeight to properly cancel the htlc back.
549
        State HtlcState
550

551
        // CustomRecords contains the custom key/value pairs that accompanied
552
        // the htlc.
553
        CustomRecords record.CustomSet
554

555
        // WireCustomRecords contains the custom key/value pairs that were only
556
        // included in p2p wire message of the HTLC and not in the onion
557
        // payload.
558
        WireCustomRecords lnwire.CustomRecords
559

560
        // AMP encapsulates additional data relevant to AMP HTLCs. This includes
561
        // the AMP onion record, in addition to the HTLC's payment hash and
562
        // preimage since these are unique to each AMP HTLC, and not the invoice
563
        // as a whole.
564
        //
565
        // NOTE: This value will only be set for AMP HTLCs.
566
        AMP *InvoiceHtlcAMPData
567
}
568

569
// Copy makes a deep copy of the target InvoiceHTLC.
570
func (h *InvoiceHTLC) Copy() *InvoiceHTLC {
3✔
571
        result := *h
3✔
572

3✔
573
        // Make a copy of the CustomSet map.
3✔
574
        result.CustomRecords = make(record.CustomSet)
3✔
575
        for k, v := range h.CustomRecords {
6✔
576
                result.CustomRecords[k] = v
3✔
577
        }
3✔
578

579
        result.WireCustomRecords = h.WireCustomRecords.Copy()
3✔
580
        result.AMP = h.AMP.Copy()
3✔
581

3✔
582
        return &result
3✔
583
}
584

585
// IsInHTLCSet returns true if this HTLC is part an HTLC set. If nil is passed,
586
// this method returns true if this is an MPP HTLC. Otherwise, it only returns
587
// true if the AMP HTLC's set id matches the populated setID.
588
func (h *InvoiceHTLC) IsInHTLCSet(setID *[32]byte) bool {
3✔
589
        wantAMPSet := setID != nil
3✔
590
        isAMPHtlc := h.AMP != nil
3✔
591

3✔
592
        // Non-AMP HTLCs cannot be part of AMP HTLC sets, and vice versa.
3✔
593
        if wantAMPSet != isAMPHtlc {
3✔
UNCOV
594
                return false
×
UNCOV
595
        }
×
596

597
        // Skip AMP HTLCs that have differing set ids.
598
        if isAMPHtlc && *setID != h.AMP.Record.SetID() {
3✔
UNCOV
599
                return false
×
UNCOV
600
        }
×
601

602
        return true
3✔
603
}
604

605
// InvoiceHtlcAMPData is a struct hodling the additional metadata stored for
606
// each received AMP HTLC. This includes the AMP onion record, in addition to
607
// the HTLC's payment hash and preimage.
608
type InvoiceHtlcAMPData struct {
609
        // AMP is a copy of the AMP record presented in the onion payload
610
        // containing the information necessary to correlate and settle a
611
        // spontaneous HTLC set. Newly accepted legacy keysend payments will
612
        // also have this field set as we automatically promote them into an AMP
613
        // payment for internal processing.
614
        Record record.AMP
615

616
        // Hash is an HTLC-level payment hash that is stored only for AMP
617
        // payments. This is done because an AMP HTLC will carry a different
618
        // payment hash from the invoice it might be satisfying, so we track the
619
        // payment hashes individually to able to compute whether or not the
620
        // reconstructed preimage correctly matches the HTLC's hash.
621
        Hash lntypes.Hash
622

623
        // Preimage is an HTLC-level preimage that satisfies the AMP HTLC's
624
        // Hash. The preimage will be derived either from secret share
625
        // reconstruction of the shares in the AMP payload.
626
        //
627
        // NOTE: Preimage will only be present once the HTLC is in
628
        // HtlcStateSettled.
629
        Preimage *lntypes.Preimage
630
}
631

632
// Copy returns a deep copy of the InvoiceHtlcAMPData.
633
func (d *InvoiceHtlcAMPData) Copy() *InvoiceHtlcAMPData {
3✔
634
        if d == nil {
6✔
635
                return nil
3✔
636
        }
3✔
637

638
        var preimage *lntypes.Preimage
3✔
639
        if d.Preimage != nil {
3✔
UNCOV
640
                pimg := *d.Preimage
×
UNCOV
641
                preimage = &pimg
×
UNCOV
642
        }
×
643

644
        return &InvoiceHtlcAMPData{
3✔
645
                Record:   d.Record,
3✔
646
                Hash:     d.Hash,
3✔
647
                Preimage: preimage,
3✔
648
        }
3✔
649
}
650

651
// HtlcAcceptDesc describes the details of a newly accepted htlc.
652
type HtlcAcceptDesc struct {
653
        // AcceptHeight is the block height at which this htlc was accepted.
654
        AcceptHeight int32
655

656
        // Amt is the amount that is carried by this htlc.
657
        Amt lnwire.MilliSatoshi
658

659
        // MppTotalAmt is a field for mpp that indicates the expected total
660
        // amount.
661
        MppTotalAmt lnwire.MilliSatoshi
662

663
        // Expiry is the expiry height of this htlc.
664
        Expiry uint32
665

666
        // CustomRecords contains the custom key/value pairs that accompanied
667
        // the htlc.
668
        CustomRecords record.CustomSet
669

670
        // AMP encapsulates additional data relevant to AMP HTLCs. This includes
671
        // the AMP onion record, in addition to the HTLC's payment hash and
672
        // preimage since these are unique to each AMP HTLC, and not the invoice
673
        // as a whole.
674
        //
675
        // NOTE: This value will only be set for AMP HTLCs.
676
        AMP *InvoiceHtlcAMPData
677
}
678

679
// UpdateType is an enum that describes the type of update that was applied to
680
// an invoice.
681
type UpdateType uint8
682

683
const (
684
        // UnknownUpdate indicates that the UpdateType has not been set for a
685
        // given udpate. This kind of updates are not allowed.
686
        UnknownUpdate UpdateType = iota
687

688
        // CancelHTLCsUpdate indicates that this update cancels one or more
689
        // HTLCs.
690
        CancelHTLCsUpdate
691

692
        // AddHTLCsUpdate indicates that this update adds one or more HTLCs.
693
        AddHTLCsUpdate
694

695
        // SettleHodlInvoiceUpdate indicates that this update settles one or
696
        // more HTLCs from a hodl invoice.
697
        SettleHodlInvoiceUpdate
698

699
        // CancelInvoiceUpdate indicates that this update is trying to cancel
700
        // an invoice.
701
        CancelInvoiceUpdate
702
)
703

704
// String returns a human readable string for the UpdateType.
705
func (u UpdateType) String() string {
×
706
        switch u {
×
707
        case CancelHTLCsUpdate:
×
708
                return "CancelHTLCsUpdate"
×
709

710
        case AddHTLCsUpdate:
×
711
                return "AddHTLCsUpdate"
×
712

713
        case SettleHodlInvoiceUpdate:
×
714
                return "SettleHodlInvoiceUpdate"
×
715

716
        case CancelInvoiceUpdate:
×
717
                return "CancelInvoiceUpdate"
×
718

719
        default:
×
720
                return fmt.Sprintf("unknown invoice update type: %d", u)
×
721
        }
722
}
723

724
// InvoiceUpdateDesc describes the changes that should be applied to the
725
// invoice.
726
type InvoiceUpdateDesc struct {
727
        // State is the new state that this invoice should progress to. If nil,
728
        // the state is left unchanged.
729
        State *InvoiceStateUpdateDesc
730

731
        // CancelHtlcs describes the htlcs that need to be canceled.
732
        CancelHtlcs map[CircuitKey]struct{}
733

734
        // AddHtlcs describes the newly accepted htlcs that need to be added to
735
        // the invoice.
736
        AddHtlcs map[CircuitKey]*HtlcAcceptDesc
737

738
        // SetID is an optional set ID for AMP invoices that allows operations
739
        // to be more efficient by ensuring we don't need to read out the
740
        // entire HTLC set each timee an HTLC is to be cancelled.
741
        SetID *SetID
742

743
        // UpdateType indicates what type of update is being applied.
744
        UpdateType UpdateType
745
}
746

747
// InvoiceStateUpdateDesc describes an invoice-level state transition.
748
type InvoiceStateUpdateDesc struct {
749
        // NewState is the new state that this invoice should progress to.
750
        NewState ContractState
751

752
        // Preimage must be set to the preimage when NewState is settled.
753
        Preimage *lntypes.Preimage
754

755
        // HTLCPreimages set the HTLC-level preimages stored for AMP HTLCs.
756
        // These are only learned when settling the invoice as a whole. Must be
757
        // set when settling an invoice with non-nil SetID.
758
        HTLCPreimages map[CircuitKey]lntypes.Preimage
759

760
        // SetID identifies a specific set of HTLCs destined for the same
761
        // invoice as part of a larger AMP payment. This value will be nil for
762
        // legacy or MPP payments.
763
        SetID *[32]byte
764
}
765

766
// InvoiceUpdateCallback is a callback used in the db transaction to update the
767
// invoice.
768
// TODO(ziggie): Add the option of additional return values to the callback
769
// for example the resolution which is currently assigned via an outer scope
770
// variable.
771
type InvoiceUpdateCallback = func(invoice *Invoice) (*InvoiceUpdateDesc, error)
772

773
// ValidateInvoice assures the invoice passes the checks for all the relevant
774
// constraints.
775
func ValidateInvoice(i *Invoice, paymentHash lntypes.Hash) error {
3✔
776
        // Avoid conflicts with all-zeroes magic value in the database.
3✔
777
        if paymentHash == UnknownPreimage.Hash() {
3✔
778
                return fmt.Errorf("cannot use hash of all-zeroes preimage")
×
779
        }
×
780

781
        if len(i.Memo) > MaxMemoSize {
3✔
782
                return fmt.Errorf("max length a memo is %v, and invoice "+
×
783
                        "of length %v was provided", MaxMemoSize, len(i.Memo))
×
784
        }
×
785
        if len(i.PaymentRequest) > MaxPaymentRequestSize {
3✔
786
                return fmt.Errorf("max length of payment request is %v, "+
×
787
                        "length provided was %v", MaxPaymentRequestSize,
×
788
                        len(i.PaymentRequest))
×
789
        }
×
790
        if i.Terms.Features == nil {
3✔
791
                return errors.New("invoice must have a feature vector")
×
792
        }
×
793

794
        err := feature.ValidateDeps(i.Terms.Features)
3✔
795
        if err != nil {
3✔
UNCOV
796
                return err
×
UNCOV
797
        }
×
798

799
        if i.requiresPreimage() && i.Terms.PaymentPreimage == nil {
3✔
800
                return errors.New("this invoice must have a preimage")
×
801
        }
×
802

803
        if len(i.Htlcs) > 0 {
3✔
UNCOV
804
                return ErrInvoiceHasHtlcs
×
UNCOV
805
        }
×
806

807
        return nil
3✔
808
}
809

810
// requiresPreimage returns true if the invoice requires a preimage to be valid.
811
func (i *Invoice) requiresPreimage() bool {
3✔
812
        // AMP invoices and hodl invoices are allowed to have no preimage
3✔
813
        // specified.
3✔
814
        if i.HodlInvoice || i.IsAMP() {
6✔
815
                return false
3✔
816
        }
3✔
817

818
        return true
3✔
819
}
820

821
// IsPending returns true if the invoice is in ContractOpen state.
822
func (i *Invoice) IsPending() bool {
3✔
823
        return i.State == ContractOpen || i.State == ContractAccepted
3✔
824
}
3✔
825

826
// copySlice allocates a new slice and copies the source into it.
827
func copySlice(src []byte) []byte {
3✔
828
        dest := make([]byte, len(src))
3✔
829
        copy(dest, src)
3✔
830
        return dest
3✔
831
}
3✔
832

833
// CopyInvoice makes a deep copy of the supplied invoice.
834
func CopyInvoice(src *Invoice) (*Invoice, error) {
3✔
835
        dest := Invoice{
3✔
836
                Memo:           copySlice(src.Memo),
3✔
837
                PaymentRequest: copySlice(src.PaymentRequest),
3✔
838
                CreationDate:   src.CreationDate,
3✔
839
                SettleDate:     src.SettleDate,
3✔
840
                Terms:          src.Terms,
3✔
841
                AddIndex:       src.AddIndex,
3✔
842
                SettleIndex:    src.SettleIndex,
3✔
843
                State:          src.State,
3✔
844
                AmtPaid:        src.AmtPaid,
3✔
845
                Htlcs: make(
3✔
846
                        map[CircuitKey]*InvoiceHTLC, len(src.Htlcs),
3✔
847
                ),
3✔
848
                AMPState:    make(map[SetID]InvoiceStateAMP),
3✔
849
                HodlInvoice: src.HodlInvoice,
3✔
850
        }
3✔
851

3✔
852
        dest.Terms.Features = src.Terms.Features.Clone()
3✔
853

3✔
854
        if src.Terms.PaymentPreimage != nil {
6✔
855
                preimage := *src.Terms.PaymentPreimage
3✔
856
                dest.Terms.PaymentPreimage = &preimage
3✔
857
        }
3✔
858

859
        for k, v := range src.Htlcs {
6✔
860
                dest.Htlcs[k] = v.Copy()
3✔
861
        }
3✔
862

863
        // Lastly, copy the amp invoice state.
864
        for k, v := range src.AMPState {
6✔
865
                ampInvState, err := v.copy()
3✔
866
                if err != nil {
3✔
867
                        return nil, err
×
868
                }
×
869

870
                dest.AMPState[k] = ampInvState
3✔
871
        }
872

873
        return &dest, nil
3✔
874
}
875

876
// InvoiceDeleteRef holds a reference to an invoice to be deleted.
877
type InvoiceDeleteRef struct {
878
        // PayHash is the payment hash of the target invoice. All invoices are
879
        // currently indexed by payment hash.
880
        PayHash lntypes.Hash
881

882
        // PayAddr is the payment addr of the target invoice. Newer invoices
883
        // (0.11 and up) are indexed by payment address in addition to payment
884
        // hash, but pre 0.8 invoices do not have one at all.
885
        PayAddr *[32]byte
886

887
        // AddIndex is the add index of the invoice.
888
        AddIndex uint64
889

890
        // SettleIndex is the settle index of the invoice.
891
        SettleIndex uint64
892
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc