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

lightningnetwork / lnd / 12312390362

13 Dec 2024 08:44AM UTC coverage: 57.458% (+8.5%) from 48.92%
12312390362

Pull #9343

github

ellemouton
fn: rework the ContextGuard and add tests

In this commit, the ContextGuard struct is re-worked such that the
context that its new main WithCtx method provides is cancelled in sync
with a parent context being cancelled or with it's quit channel being
cancelled. Tests are added to assert the behaviour. In order for the
close of the quit channel to be consistent with the cancelling of the
derived context, the quit channel _must_ be contained internal to the
ContextGuard so that callers are only able to close the channel via the
exposed Quit method which will then take care to first cancel any
derived context that depend on the quit channel before returning.
Pull Request #9343: fn: expand the ContextGuard and add tests

101853 of 177264 relevant lines covered (57.46%)

24972.93 hits per line

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

74.25
/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 {
2,136✔
94
        return InvoiceRef{
2,136✔
95
                payHash: &payHash,
2,136✔
96
        }
2,136✔
97
}
2,136✔
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 {
1,606✔
104

1,606✔
105
        return InvoiceRef{
1,606✔
106
                payHash: &payHash,
1,606✔
107
                payAddr: &payAddr,
1,606✔
108
        }
1,606✔
109
}
1,606✔
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 {
70✔
114
        return InvoiceRef{
70✔
115
                payAddr: &addr,
70✔
116
        }
70✔
117
}
70✔
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 {
22✔
133
        return InvoiceRef{
22✔
134
                setID: &setID,
22✔
135
        }
22✔
136
}
22✔
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 {
12✔
142
        return InvoiceRef{
12✔
143
                setID:       &setID,
12✔
144
                refModifier: HtlcSetOnlyModifier,
12✔
145
        }
12✔
146
}
12✔
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 {
7,227✔
152
        if r.payHash != nil {
14,255✔
153
                hash := *r.payHash
7,028✔
154
                return &hash
7,028✔
155
        }
7,028✔
156

157
        return nil
199✔
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 {
4,541✔
164
        if r.payAddr != nil {
7,358✔
165
                addr := *r.payAddr
2,817✔
166
                return &addr
2,817✔
167
        }
2,817✔
168

169
        return nil
1,724✔
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,643✔
176
        if r.setID != nil {
3,967✔
177
                id := *r.setID
324✔
178
                return &id
324✔
179
        }
324✔
180

181
        return nil
3,319✔
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 {
1,742✔
187
        return r.refModifier
1,742✔
188
}
1,742✔
189

190
// String returns a human-readable representation of an InvoiceRef.
191
func (r InvoiceRef) String() string {
×
192
        var ids []string
×
193
        if r.payHash != nil {
×
194
                ids = append(ids, fmt.Sprintf("pay_hash=%v", *r.payHash))
×
195
        }
×
196
        if r.payAddr != nil {
×
197
                ids = append(ids, fmt.Sprintf("pay_addr=%x", *r.payAddr))
×
198
        }
×
199
        if r.setID != nil {
×
200
                ids = append(ids, fmt.Sprintf("set_id=%x", *r.setID))
×
201
        }
×
202

203
        return fmt.Sprintf("(%s)", strings.Join(ids, ", "))
×
204
}
205

206
// ContractState describes the state the invoice is in.
207
type ContractState uint8
208

209
const (
210
        // ContractOpen means the invoice has only been created.
211
        ContractOpen ContractState = 0
212

213
        // ContractSettled means the htlc is settled and the invoice has been
214
        // paid.
215
        ContractSettled ContractState = 1
216

217
        // ContractCanceled means the invoice has been canceled.
218
        ContractCanceled ContractState = 2
219

220
        // ContractAccepted means the HTLC has been accepted but not settled
221
        // yet.
222
        ContractAccepted ContractState = 3
223
)
224

225
// String returns a human readable identifier for the ContractState type.
226
func (c ContractState) String() string {
×
227
        switch c {
×
228
        case ContractOpen:
×
229
                return "Open"
×
230

231
        case ContractSettled:
×
232
                return "Settled"
×
233

234
        case ContractCanceled:
×
235
                return "Canceled"
×
236

237
        case ContractAccepted:
×
238
                return "Accepted"
×
239
        }
240

241
        return "Unknown"
×
242
}
243

244
// IsFinal returns a boolean indicating whether an invoice state is final.
245
func (c ContractState) IsFinal() bool {
×
246
        return c == ContractSettled || c == ContractCanceled
×
247
}
×
248

249
// ContractTerm is a companion struct to the Invoice struct. This struct houses
250
// the necessary conditions required before the invoice can be considered fully
251
// settled by the payee.
252
type ContractTerm struct {
253
        // FinalCltvDelta is the minimum required number of blocks before htlc
254
        // expiry when the invoice is accepted.
255
        FinalCltvDelta int32
256

257
        // Expiry defines how long after creation this invoice should expire.
258
        Expiry time.Duration
259

260
        // PaymentPreimage is the preimage which is to be revealed in the
261
        // occasion that an HTLC paying to the hash of this preimage is
262
        // extended. Set to nil if the preimage isn't known yet.
263
        PaymentPreimage *lntypes.Preimage
264

265
        // Value is the expected amount of milli-satoshis to be paid to an HTLC
266
        // which can be satisfied by the above preimage.
267
        Value lnwire.MilliSatoshi
268

269
        // PaymentAddr is a randomly generated value include in the MPP record
270
        // by the sender to prevent probing of the receiver.
271
        PaymentAddr [32]byte
272

273
        // Features is the feature vectors advertised on the payment request.
274
        Features *lnwire.FeatureVector
275
}
276

277
// String returns a human-readable description of the prominent contract terms.
278
func (c ContractTerm) String() string {
×
279
        return fmt.Sprintf("amt=%v, expiry=%v, final_cltv_delta=%v", c.Value,
×
280
                c.Expiry, c.FinalCltvDelta)
×
281
}
×
282

283
// SetID is the extra unique tuple item for AMP invoices. In addition to
284
// setting a payment address, each repeated payment to an AMP invoice will also
285
// contain a set ID as well.
286
type SetID [32]byte
287

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

297
        // SettleIndex indicates the location in the settle index that
298
        // references this instance of InvoiceStateAMP, but only if
299
        // this value is set (non-zero), and State is HtlcStateSettled.
300
        SettleIndex uint64
301

302
        // SettleDate is the date that the setID was settled.
303
        SettleDate time.Time
304

305
        // InvoiceKeys is the set of circuit keys that can be used to locate
306
        // the invoices for a given set ID.
307
        InvoiceKeys map[CircuitKey]struct{}
308

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

316
// copy makes a deep copy of the underlying InvoiceStateAMP.
317
func (i *InvoiceStateAMP) copy() (InvoiceStateAMP, error) {
76✔
318
        result := *i
76✔
319

76✔
320
        // Make a copy of the InvoiceKeys map.
76✔
321
        result.InvoiceKeys = make(map[CircuitKey]struct{})
76✔
322
        for k := range i.InvoiceKeys {
173✔
323
                result.InvoiceKeys[k] = struct{}{}
97✔
324
        }
97✔
325

326
        // As a safety measure, copy SettleDate. time.Time is concurrency safe
327
        // except when using any of the (un)marshalling methods.
328
        settleDateBytes, err := i.SettleDate.MarshalBinary()
76✔
329
        if err != nil {
76✔
330
                return InvoiceStateAMP{}, err
×
331
        }
×
332

333
        err = result.SettleDate.UnmarshalBinary(settleDateBytes)
76✔
334
        if err != nil {
76✔
335
                return InvoiceStateAMP{}, err
×
336
        }
×
337

338
        return result, nil
76✔
339
}
340

341
// AMPInvoiceState represents a type that stores metadata related to the set of
342
// settled AMP "sub-invoices".
343
type AMPInvoiceState map[SetID]InvoiceStateAMP
344

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

361
        // PaymentRequest is the encoded payment request for this invoice. For
362
        // spontaneous (keysend) payments, this field will be empty.
363
        PaymentRequest []byte
364

365
        // CreationDate is the exact time the invoice was created.
366
        CreationDate time.Time
367

368
        // SettleDate is the exact time the invoice was settled.
369
        SettleDate time.Time
370

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

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

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

397
        // State describes the state the invoice is in. This is the global
398
        // state of the invoice which may remain open even when a series of
399
        // sub-invoices for this invoice has been settled.
400
        State ContractState
401

402
        // AmtPaid is the final amount that we ultimately accepted for pay for
403
        // this invoice. We specify this value independently as it's possible
404
        // that the invoice originally didn't specify an amount, or the sender
405
        // overpaid.
406
        AmtPaid lnwire.MilliSatoshi
407

408
        // Htlcs records all htlcs that paid to this invoice. Some of these
409
        // htlcs may have been marked as canceled.
410
        Htlcs map[CircuitKey]*InvoiceHTLC
411

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

419
        // HodlInvoice indicates whether the invoice should be held in the
420
        // Accepted state or be settled right away.
421
        HodlInvoice bool
422
}
423

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

2,252✔
432
        htlcSet := make(map[CircuitKey]*InvoiceHTLC)
2,252✔
433
        for key, htlc := range i.Htlcs {
4,816✔
434
                // Only add HTLCs that are in the requested HtlcState.
2,564✔
435
                if htlc.State != state {
2,659✔
436
                        continue
95✔
437
                }
438

439
                if !htlc.IsInHTLCSet(setID) {
2,589✔
440
                        continue
120✔
441
                }
442

443
                htlcSet[key] = htlc
2,349✔
444
        }
445

446
        return htlcSet
2,252✔
447
}
448

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

473✔
455
        htlcSet := make(map[CircuitKey]*InvoiceHTLC)
473✔
456
        for key, htlc := range i.Htlcs {
1,261✔
457
                // Only add HTLCs that are in the requested HtlcState.
788✔
458
                if htlc.State != state {
1,573✔
459
                        continue
785✔
460
                }
461

462
                // We are constructing the compliment, so filter anything that
463
                // matches this set id.
464
                if htlc.IsInHTLCSet(setID) {
6✔
465
                        continue
3✔
466
                }
467

468
                htlcSet[key] = htlc
×
469
        }
470

471
        return htlcSet
473✔
472
}
473

474
// IsKeysend returns true if the invoice is a Keysend invoice.
475
func (i *Invoice) IsKeysend() bool {
586✔
476
        // TODO(positiveblue): look for a more reliable way to tests if
586✔
477
        // an invoice is keysend.
586✔
478
        return len(i.PaymentRequest) == 0 && !i.IsAMP()
586✔
479
}
586✔
480

481
// IsAMP returns true if the invoice is an AMP invoice.
482
func (i *Invoice) IsAMP() bool {
9,925✔
483
        if i.Terms.Features == nil {
9,925✔
484
                return false
×
485
        }
×
486

487
        return i.Terms.Features.HasFeature(
9,925✔
488
                lnwire.AMPRequired,
9,925✔
489
        )
9,925✔
490
}
491

492
// IsBlinded returns true if the invoice contains blinded paths.
493
func (i *Invoice) IsBlinded() bool {
×
494
        if i.Terms.Features == nil {
×
495
                return false
×
496
        }
×
497

498
        return i.Terms.Features.IsSet(lnwire.Bolt11BlindedPathsRequired)
×
499
}
500

501
// HtlcState defines the states an htlc paying to an invoice can be in.
502
type HtlcState uint8
503

504
const (
505
        // HtlcStateAccepted indicates the htlc is locked-in, but not resolved.
506
        HtlcStateAccepted HtlcState = iota
507

508
        // HtlcStateCanceled indicates the htlc is canceled back to the
509
        // sender.
510
        HtlcStateCanceled
511

512
        // HtlcStateSettled indicates the htlc is settled.
513
        HtlcStateSettled
514
)
515

516
// InvoiceHTLC contains details about an htlc paying to this invoice.
517
type InvoiceHTLC struct {
518
        // Amt is the amount that is carried by this htlc.
519
        Amt lnwire.MilliSatoshi
520

521
        // MppTotalAmt is a field for mpp that indicates the expected total
522
        // amount.
523
        MppTotalAmt lnwire.MilliSatoshi
524

525
        // AcceptHeight is the block height at which the invoice registry
526
        // decided to accept this htlc as a payment to the invoice. At this
527
        // height, the invoice cltv delay must have been met.
528
        AcceptHeight uint32
529

530
        // AcceptTime is the wall clock time at which the invoice registry
531
        // decided to accept the htlc.
532
        AcceptTime time.Time
533

534
        // ResolveTime is the wall clock time at which the invoice registry
535
        // decided to settle the htlc.
536
        ResolveTime time.Time
537

538
        // Expiry is the expiry height of this htlc.
539
        Expiry uint32
540

541
        // State indicates the state the invoice htlc is currently in. A
542
        // canceled htlc isn't just removed from the invoice htlcs map, because
543
        // we need AcceptHeight to properly cancel the htlc back.
544
        State HtlcState
545

546
        // CustomRecords contains the custom key/value pairs that accompanied
547
        // the htlc.
548
        CustomRecords record.CustomSet
549

550
        // WireCustomRecords contains the custom key/value pairs that were only
551
        // included in p2p wire message of the HTLC and not in the onion
552
        // payload.
553
        WireCustomRecords lnwire.CustomRecords
554

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

564
// Copy makes a deep copy of the target InvoiceHTLC.
565
func (h *InvoiceHTLC) Copy() *InvoiceHTLC {
599✔
566
        result := *h
599✔
567

599✔
568
        // Make a copy of the CustomSet map.
599✔
569
        result.CustomRecords = make(record.CustomSet)
599✔
570
        for k, v := range h.CustomRecords {
610✔
571
                result.CustomRecords[k] = v
11✔
572
        }
11✔
573

574
        result.WireCustomRecords = h.WireCustomRecords.Copy()
599✔
575
        result.AMP = h.AMP.Copy()
599✔
576

599✔
577
        return &result
599✔
578
}
579

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

3,587✔
587
        // Non-AMP HTLCs cannot be part of AMP HTLC sets, and vice versa.
3,587✔
588
        if wantAMPSet != isAMPHtlc {
3,667✔
589
                return false
80✔
590
        }
80✔
591

592
        // Skip AMP HTLCs that have differing set ids.
593
        if isAMPHtlc && *setID != h.AMP.Record.SetID() {
3,549✔
594
                return false
42✔
595
        }
42✔
596

597
        return true
3,465✔
598
}
599

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

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

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

627
// Copy returns a deep copy of the InvoiceHtlcAMPData.
628
func (d *InvoiceHtlcAMPData) Copy() *InvoiceHtlcAMPData {
656✔
629
        if d == nil {
1,168✔
630
                return nil
512✔
631
        }
512✔
632

633
        var preimage *lntypes.Preimage
144✔
634
        if d.Preimage != nil {
231✔
635
                pimg := *d.Preimage
87✔
636
                preimage = &pimg
87✔
637
        }
87✔
638

639
        return &InvoiceHtlcAMPData{
144✔
640
                Record:   d.Record,
144✔
641
                Hash:     d.Hash,
144✔
642
                Preimage: preimage,
144✔
643
        }
144✔
644
}
645

646
// HtlcAcceptDesc describes the details of a newly accepted htlc.
647
type HtlcAcceptDesc struct {
648
        // AcceptHeight is the block height at which this htlc was accepted.
649
        AcceptHeight int32
650

651
        // Amt is the amount that is carried by this htlc.
652
        Amt lnwire.MilliSatoshi
653

654
        // MppTotalAmt is a field for mpp that indicates the expected total
655
        // amount.
656
        MppTotalAmt lnwire.MilliSatoshi
657

658
        // Expiry is the expiry height of this htlc.
659
        Expiry uint32
660

661
        // CustomRecords contains the custom key/value pairs that accompanied
662
        // the htlc.
663
        CustomRecords record.CustomSet
664

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

674
// UpdateType is an enum that describes the type of update that was applied to
675
// an invoice.
676
type UpdateType uint8
677

678
const (
679
        // UnknownUpdate indicates that the UpdateType has not been set for a
680
        // given udpate. This kind of updates are not allowed.
681
        UnknownUpdate UpdateType = iota
682

683
        // CancelHTLCsUpdate indicates that this update cancels one or more
684
        // HTLCs.
685
        CancelHTLCsUpdate
686

687
        // AddHTLCsUpdate indicates that this update adds one or more HTLCs.
688
        AddHTLCsUpdate
689

690
        // SettleHodlInvoiceUpdate indicates that this update settles one or
691
        // more HTLCs from a hodl invoice.
692
        SettleHodlInvoiceUpdate
693

694
        // CancelInvoiceUpdate indicates that this update is trying to cancel
695
        // an invoice.
696
        CancelInvoiceUpdate
697
)
698

699
// String returns a human readable string for the UpdateType.
700
func (u UpdateType) String() string {
×
701
        switch u {
×
702
        case CancelHTLCsUpdate:
×
703
                return "CancelHTLCsUpdate"
×
704

705
        case AddHTLCsUpdate:
×
706
                return "AddHTLCsUpdate"
×
707

708
        case SettleHodlInvoiceUpdate:
×
709
                return "SettleHodlInvoiceUpdate"
×
710

711
        case CancelInvoiceUpdate:
×
712
                return "CancelInvoiceUpdate"
×
713

714
        default:
×
715
                return fmt.Sprintf("unknown invoice update type: %d", u)
×
716
        }
717
}
718

719
// InvoiceUpdateDesc describes the changes that should be applied to the
720
// invoice.
721
type InvoiceUpdateDesc struct {
722
        // State is the new state that this invoice should progress to. If nil,
723
        // the state is left unchanged.
724
        State *InvoiceStateUpdateDesc
725

726
        // CancelHtlcs describes the htlcs that need to be canceled.
727
        CancelHtlcs map[CircuitKey]struct{}
728

729
        // AddHtlcs describes the newly accepted htlcs that need to be added to
730
        // the invoice.
731
        AddHtlcs map[CircuitKey]*HtlcAcceptDesc
732

733
        // SetID is an optional set ID for AMP invoices that allows operations
734
        // to be more efficient by ensuring we don't need to read out the
735
        // entire HTLC set each timee an HTLC is to be cancelled.
736
        SetID *SetID
737

738
        // UpdateType indicates what type of update is being applied.
739
        UpdateType UpdateType
740
}
741

742
// InvoiceStateUpdateDesc describes an invoice-level state transition.
743
type InvoiceStateUpdateDesc struct {
744
        // NewState is the new state that this invoice should progress to.
745
        NewState ContractState
746

747
        // Preimage must be set to the preimage when NewState is settled.
748
        Preimage *lntypes.Preimage
749

750
        // HTLCPreimages set the HTLC-level preimages stored for AMP HTLCs.
751
        // These are only learned when settling the invoice as a whole. Must be
752
        // set when settling an invoice with non-nil SetID.
753
        HTLCPreimages map[CircuitKey]lntypes.Preimage
754

755
        // SetID identifies a specific set of HTLCs destined for the same
756
        // invoice as part of a larger AMP payment. This value will be nil for
757
        // legacy or MPP payments.
758
        SetID *[32]byte
759
}
760

761
// InvoiceUpdateCallback is a callback used in the db transaction to update the
762
// invoice.
763
type InvoiceUpdateCallback = func(invoice *Invoice) (*InvoiceUpdateDesc, error)
764

765
// ValidateInvoice assures the invoice passes the checks for all the relevant
766
// constraints.
767
func ValidateInvoice(i *Invoice, paymentHash lntypes.Hash) error {
1,212✔
768
        // Avoid conflicts with all-zeroes magic value in the database.
1,212✔
769
        if paymentHash == UnknownPreimage.Hash() {
1,212✔
770
                return fmt.Errorf("cannot use hash of all-zeroes preimage")
×
771
        }
×
772

773
        if len(i.Memo) > MaxMemoSize {
1,212✔
774
                return fmt.Errorf("max length a memo is %v, and invoice "+
×
775
                        "of length %v was provided", MaxMemoSize, len(i.Memo))
×
776
        }
×
777
        if len(i.PaymentRequest) > MaxPaymentRequestSize {
1,212✔
778
                return fmt.Errorf("max length of payment request is %v, "+
×
779
                        "length provided was %v", MaxPaymentRequestSize,
×
780
                        len(i.PaymentRequest))
×
781
        }
×
782
        if i.Terms.Features == nil {
1,212✔
783
                return errors.New("invoice must have a feature vector")
×
784
        }
×
785

786
        err := feature.ValidateDeps(i.Terms.Features)
1,212✔
787
        if err != nil {
1,215✔
788
                return err
3✔
789
        }
3✔
790

791
        if i.requiresPreimage() && i.Terms.PaymentPreimage == nil {
1,209✔
792
                return errors.New("this invoice must have a preimage")
×
793
        }
×
794

795
        if len(i.Htlcs) > 0 {
1,212✔
796
                return ErrInvoiceHasHtlcs
3✔
797
        }
3✔
798

799
        return nil
1,206✔
800
}
801

802
// requiresPreimage returns true if the invoice requires a preimage to be valid.
803
func (i *Invoice) requiresPreimage() bool {
1,209✔
804
        // AMP invoices and hodl invoices are allowed to have no preimage
1,209✔
805
        // specified.
1,209✔
806
        if i.HodlInvoice || i.IsAMP() {
1,336✔
807
                return false
127✔
808
        }
127✔
809

810
        return true
1,082✔
811
}
812

813
// IsPending returns true if the invoice is in ContractOpen state.
814
func (i *Invoice) IsPending() bool {
351✔
815
        return i.State == ContractOpen || i.State == ContractAccepted
351✔
816
}
351✔
817

818
// copySlice allocates a new slice and copies the source into it.
819
func copySlice(src []byte) []byte {
2,696✔
820
        dest := make([]byte, len(src))
2,696✔
821
        copy(dest, src)
2,696✔
822
        return dest
2,696✔
823
}
2,696✔
824

825
// CopyInvoice makes a deep copy of the supplied invoice.
826
func CopyInvoice(src *Invoice) (*Invoice, error) {
1,348✔
827
        dest := Invoice{
1,348✔
828
                Memo:           copySlice(src.Memo),
1,348✔
829
                PaymentRequest: copySlice(src.PaymentRequest),
1,348✔
830
                CreationDate:   src.CreationDate,
1,348✔
831
                SettleDate:     src.SettleDate,
1,348✔
832
                Terms:          src.Terms,
1,348✔
833
                AddIndex:       src.AddIndex,
1,348✔
834
                SettleIndex:    src.SettleIndex,
1,348✔
835
                State:          src.State,
1,348✔
836
                AmtPaid:        src.AmtPaid,
1,348✔
837
                Htlcs: make(
1,348✔
838
                        map[CircuitKey]*InvoiceHTLC, len(src.Htlcs),
1,348✔
839
                ),
1,348✔
840
                AMPState:    make(map[SetID]InvoiceStateAMP),
1,348✔
841
                HodlInvoice: src.HodlInvoice,
1,348✔
842
        }
1,348✔
843

1,348✔
844
        dest.Terms.Features = src.Terms.Features.Clone()
1,348✔
845

1,348✔
846
        if src.Terms.PaymentPreimage != nil {
2,522✔
847
                preimage := *src.Terms.PaymentPreimage
1,174✔
848
                dest.Terms.PaymentPreimage = &preimage
1,174✔
849
        }
1,174✔
850

851
        for k, v := range src.Htlcs {
1,928✔
852
                dest.Htlcs[k] = v.Copy()
580✔
853
        }
580✔
854

855
        // Lastly, copy the amp invoice state.
856
        for k, v := range src.AMPState {
1,424✔
857
                ampInvState, err := v.copy()
76✔
858
                if err != nil {
76✔
859
                        return nil, err
×
860
                }
×
861

862
                dest.AMPState[k] = ampInvState
76✔
863
        }
864

865
        return &dest, nil
1,348✔
866
}
867

868
// InvoiceDeleteRef holds a reference to an invoice to be deleted.
869
type InvoiceDeleteRef struct {
870
        // PayHash is the payment hash of the target invoice. All invoices are
871
        // currently indexed by payment hash.
872
        PayHash lntypes.Hash
873

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

879
        // AddIndex is the add index of the invoice.
880
        AddIndex uint64
881

882
        // SettleIndex is the settle index of the invoice.
883
        SettleIndex uint64
884
}
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