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

lightningnetwork / lnd / 13035292482

29 Jan 2025 03:59PM UTC coverage: 49.3% (-9.5%) from 58.777%
13035292482

Pull #9456

github

mohamedawnallah
docs: update release-notes-0.19.0.md

In this commit, we warn users about the removal
of RPCs `SendToRoute`, `SendToRouteSync`, `SendPayment`,
and `SendPaymentSync` in the next release 0.20.
Pull Request #9456: lnrpc+docs: deprecate warning `SendToRoute`, `SendToRouteSync`, `SendPayment`, and `SendPaymentSync` in Release 0.19

100634 of 204126 relevant lines covered (49.3%)

1.54 hits per line

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

0.0
/channeldb/migration_01_to_11/invoices.go
1
package migration_01_to_11
2

3
import (
4
        "bytes"
5
        "encoding/binary"
6
        "fmt"
7
        "io"
8
        "time"
9

10
        "github.com/btcsuite/btcd/wire"
11
        lnwire "github.com/lightningnetwork/lnd/channeldb/migration/lnwire21"
12
        "github.com/lightningnetwork/lnd/kvdb"
13
        "github.com/lightningnetwork/lnd/lntypes"
14
        "github.com/lightningnetwork/lnd/tlv"
15
)
16

17
var (
18

19
        // invoiceBucket is the name of the bucket within the database that
20
        // stores all data related to invoices no matter their final state.
21
        // Within the invoice bucket, each invoice is keyed by its invoice ID
22
        // which is a monotonically increasing uint32.
23
        invoiceBucket = []byte("invoices")
24

25
        // addIndexBucket is an index bucket that we'll use to create a
26
        // monotonically increasing set of add indexes. Each time we add a new
27
        // invoice, this sequence number will be incremented and then populated
28
        // within the new invoice.
29
        //
30
        // In addition to this sequence number, we map:
31
        //
32
        //   addIndexNo => invoiceKey
33
        addIndexBucket = []byte("invoice-add-index")
34

35
        // settleIndexBucket is an index bucket that we'll use to create a
36
        // monotonically increasing integer for tracking a "settle index". Each
37
        // time an invoice is settled, this sequence number will be incremented
38
        // as populate within the newly settled invoice.
39
        //
40
        // In addition to this sequence number, we map:
41
        //
42
        //   settleIndexNo => invoiceKey
43
        settleIndexBucket = []byte("invoice-settle-index")
44
)
45

46
const (
47
        // MaxMemoSize is maximum size of the memo field within invoices stored
48
        // in the database.
49
        MaxMemoSize = 1024
50

51
        // MaxReceiptSize is the maximum size of the payment receipt stored
52
        // within the database along side incoming/outgoing invoices.
53
        MaxReceiptSize = 1024
54

55
        // MaxPaymentRequestSize is the max size of a payment request for
56
        // this invoice.
57
        // TODO(halseth): determine the max length payment request when field
58
        // lengths are final.
59
        MaxPaymentRequestSize = 4096
60

61
        // A set of tlv type definitions used to serialize invoice htlcs to the
62
        // database.
63
        chanIDType       tlv.Type = 1
64
        htlcIDType       tlv.Type = 3
65
        amtType          tlv.Type = 5
66
        acceptHeightType tlv.Type = 7
67
        acceptTimeType   tlv.Type = 9
68
        resolveTimeType  tlv.Type = 11
69
        expiryHeightType tlv.Type = 13
70
        stateType        tlv.Type = 15
71
)
72

73
// ContractState describes the state the invoice is in.
74
type ContractState uint8
75

76
const (
77
        // ContractOpen means the invoice has only been created.
78
        ContractOpen ContractState = 0
79

80
        // ContractSettled means the htlc is settled and the invoice has been
81
        // paid.
82
        ContractSettled ContractState = 1
83

84
        // ContractCanceled means the invoice has been canceled.
85
        ContractCanceled ContractState = 2
86

87
        // ContractAccepted means the HTLC has been accepted but not settled
88
        // yet.
89
        ContractAccepted ContractState = 3
90
)
91

92
// String returns a human readable identifier for the ContractState type.
93
func (c ContractState) String() string {
×
94
        switch c {
×
95
        case ContractOpen:
×
96
                return "Open"
×
97
        case ContractSettled:
×
98
                return "Settled"
×
99
        case ContractCanceled:
×
100
                return "Canceled"
×
101
        case ContractAccepted:
×
102
                return "Accepted"
×
103
        }
104

105
        return "Unknown"
×
106
}
107

108
// ContractTerm is a companion struct to the Invoice struct. This struct houses
109
// the necessary conditions required before the invoice can be considered fully
110
// settled by the payee.
111
type ContractTerm struct {
112
        // PaymentPreimage is the preimage which is to be revealed in the
113
        // occasion that an HTLC paying to the hash of this preimage is
114
        // extended.
115
        PaymentPreimage lntypes.Preimage
116

117
        // Value is the expected amount of milli-satoshis to be paid to an HTLC
118
        // which can be satisfied by the above preimage.
119
        Value lnwire.MilliSatoshi
120

121
        // State describes the state the invoice is in.
122
        State ContractState
123
}
124

125
// Invoice is a payment invoice generated by a payee in order to request
126
// payment for some good or service. The inclusion of invoices within Lightning
127
// creates a payment work flow for merchants very similar to that of the
128
// existing financial system within PayPal, etc.  Invoices are added to the
129
// database when a payment is requested, then can be settled manually once the
130
// payment is received at the upper layer. For record keeping purposes,
131
// invoices are never deleted from the database, instead a bit is toggled
132
// denoting the invoice has been fully settled. Within the database, all
133
// invoices must have a unique payment hash which is generated by taking the
134
// sha256 of the payment preimage.
135
type Invoice struct {
136
        // Memo is an optional memo to be stored along side an invoice.  The
137
        // memo may contain further details pertaining to the invoice itself,
138
        // or any other message which fits within the size constraints.
139
        Memo []byte
140

141
        // Receipt is an optional field dedicated for storing a
142
        // cryptographically binding receipt of payment.
143
        //
144
        // TODO(roasbeef): document scheme.
145
        Receipt []byte
146

147
        // PaymentRequest is an optional field where a payment request created
148
        // for this invoice can be stored.
149
        PaymentRequest []byte
150

151
        // FinalCltvDelta is the minimum required number of blocks before htlc
152
        // expiry when the invoice is accepted.
153
        FinalCltvDelta int32
154

155
        // Expiry defines how long after creation this invoice should expire.
156
        Expiry time.Duration
157

158
        // CreationDate is the exact time the invoice was created.
159
        CreationDate time.Time
160

161
        // SettleDate is the exact time the invoice was settled.
162
        SettleDate time.Time
163

164
        // Terms are the contractual payment terms of the invoice. Once all the
165
        // terms have been satisfied by the payer, then the invoice can be
166
        // considered fully fulfilled.
167
        //
168
        // TODO(roasbeef): later allow for multiple terms to fulfill the final
169
        // invoice: payment fragmentation, etc.
170
        Terms ContractTerm
171

172
        // AddIndex is an auto-incrementing integer that acts as a
173
        // monotonically increasing sequence number for all invoices created.
174
        // Clients can then use this field as a "checkpoint" of sorts when
175
        // implementing a streaming RPC to notify consumers of instances where
176
        // an invoice has been added before they re-connected.
177
        //
178
        // NOTE: This index starts at 1.
179
        AddIndex uint64
180

181
        // SettleIndex is an auto-incrementing integer that acts as a
182
        // monotonically increasing sequence number for all settled invoices.
183
        // Clients can then use this field as a "checkpoint" of sorts when
184
        // implementing a streaming RPC to notify consumers of instances where
185
        // an invoice has been settled before they re-connected.
186
        //
187
        // NOTE: This index starts at 1.
188
        SettleIndex uint64
189

190
        // AmtPaid is the final amount that we ultimately accepted for pay for
191
        // this invoice. We specify this value independently as it's possible
192
        // that the invoice originally didn't specify an amount, or the sender
193
        // overpaid.
194
        AmtPaid lnwire.MilliSatoshi
195

196
        // Htlcs records all htlcs that paid to this invoice. Some of these
197
        // htlcs may have been marked as canceled.
198
        Htlcs map[CircuitKey]*InvoiceHTLC
199
}
200

201
// HtlcState defines the states an htlc paying to an invoice can be in.
202
type HtlcState uint8
203

204
// InvoiceHTLC contains details about an htlc paying to this invoice.
205
type InvoiceHTLC struct {
206
        // Amt is the amount that is carried by this htlc.
207
        Amt lnwire.MilliSatoshi
208

209
        // AcceptHeight is the block height at which the invoice registry
210
        // decided to accept this htlc as a payment to the invoice. At this
211
        // height, the invoice cltv delay must have been met.
212
        AcceptHeight uint32
213

214
        // AcceptTime is the wall clock time at which the invoice registry
215
        // decided to accept the htlc.
216
        AcceptTime time.Time
217

218
        // ResolveTime is the wall clock time at which the invoice registry
219
        // decided to settle the htlc.
220
        ResolveTime time.Time
221

222
        // Expiry is the expiry height of this htlc.
223
        Expiry uint32
224

225
        // State indicates the state the invoice htlc is currently in. A
226
        // canceled htlc isn't just removed from the invoice htlcs map, because
227
        // we need AcceptHeight to properly cancel the htlc back.
228
        State HtlcState
229
}
230

231
func validateInvoice(i *Invoice) error {
×
232
        if len(i.Memo) > MaxMemoSize {
×
233
                return fmt.Errorf("max length a memo is %v, and invoice "+
×
234
                        "of length %v was provided", MaxMemoSize, len(i.Memo))
×
235
        }
×
236
        if len(i.Receipt) > MaxReceiptSize {
×
237
                return fmt.Errorf("max length a receipt is %v, and invoice "+
×
238
                        "of length %v was provided", MaxReceiptSize,
×
239
                        len(i.Receipt))
×
240
        }
×
241
        if len(i.PaymentRequest) > MaxPaymentRequestSize {
×
242
                return fmt.Errorf("max length of payment request is %v, length "+
×
243
                        "provided was %v", MaxPaymentRequestSize,
×
244
                        len(i.PaymentRequest))
×
245
        }
×
246
        return nil
×
247
}
248

249
// FetchAllInvoices returns all invoices currently stored within the database.
250
// If the pendingOnly param is true, then only unsettled invoices will be
251
// returned, skipping all invoices that are fully settled.
252
func (d *DB) FetchAllInvoices(pendingOnly bool) ([]Invoice, error) {
×
253
        var invoices []Invoice
×
254

×
255
        err := kvdb.View(d, func(tx kvdb.RTx) error {
×
256
                invoiceB := tx.ReadBucket(invoiceBucket)
×
257
                if invoiceB == nil {
×
258
                        return ErrNoInvoicesCreated
×
259
                }
×
260

261
                // Iterate through the entire key space of the top-level
262
                // invoice bucket. If key with a non-nil value stores the next
263
                // invoice ID which maps to the corresponding invoice.
264
                return invoiceB.ForEach(func(k, v []byte) error {
×
265
                        if v == nil {
×
266
                                return nil
×
267
                        }
×
268

269
                        invoiceReader := bytes.NewReader(v)
×
270
                        invoice, err := deserializeInvoice(invoiceReader)
×
271
                        if err != nil {
×
272
                                return err
×
273
                        }
×
274

275
                        if pendingOnly &&
×
276
                                invoice.Terms.State == ContractSettled {
×
277

×
278
                                return nil
×
279
                        }
×
280

281
                        invoices = append(invoices, invoice)
×
282

×
283
                        return nil
×
284
                })
285
        }, func() {
×
286
                invoices = nil
×
287
        })
×
288
        if err != nil {
×
289
                return nil, err
×
290
        }
×
291

292
        return invoices, nil
×
293
}
294

295
// serializeInvoice serializes an invoice to a writer.
296
//
297
// Note: this function is in use for a migration. Before making changes that
298
// would modify the on disk format, make a copy of the original code and store
299
// it with the migration.
300
func serializeInvoice(w io.Writer, i *Invoice) error {
×
301
        if err := wire.WriteVarBytes(w, 0, i.Memo[:]); err != nil {
×
302
                return err
×
303
        }
×
304
        if err := wire.WriteVarBytes(w, 0, i.Receipt[:]); err != nil {
×
305
                return err
×
306
        }
×
307
        if err := wire.WriteVarBytes(w, 0, i.PaymentRequest[:]); err != nil {
×
308
                return err
×
309
        }
×
310

311
        if err := binary.Write(w, byteOrder, i.FinalCltvDelta); err != nil {
×
312
                return err
×
313
        }
×
314

315
        if err := binary.Write(w, byteOrder, int64(i.Expiry)); err != nil {
×
316
                return err
×
317
        }
×
318

319
        birthBytes, err := i.CreationDate.MarshalBinary()
×
320
        if err != nil {
×
321
                return err
×
322
        }
×
323

324
        if err := wire.WriteVarBytes(w, 0, birthBytes); err != nil {
×
325
                return err
×
326
        }
×
327

328
        settleBytes, err := i.SettleDate.MarshalBinary()
×
329
        if err != nil {
×
330
                return err
×
331
        }
×
332

333
        if err := wire.WriteVarBytes(w, 0, settleBytes); err != nil {
×
334
                return err
×
335
        }
×
336

337
        if _, err := w.Write(i.Terms.PaymentPreimage[:]); err != nil {
×
338
                return err
×
339
        }
×
340

341
        var scratch [8]byte
×
342
        byteOrder.PutUint64(scratch[:], uint64(i.Terms.Value))
×
343
        if _, err := w.Write(scratch[:]); err != nil {
×
344
                return err
×
345
        }
×
346

347
        if err := binary.Write(w, byteOrder, i.Terms.State); err != nil {
×
348
                return err
×
349
        }
×
350

351
        if err := binary.Write(w, byteOrder, i.AddIndex); err != nil {
×
352
                return err
×
353
        }
×
354
        if err := binary.Write(w, byteOrder, i.SettleIndex); err != nil {
×
355
                return err
×
356
        }
×
357
        if err := binary.Write(w, byteOrder, int64(i.AmtPaid)); err != nil {
×
358
                return err
×
359
        }
×
360

361
        if err := serializeHtlcs(w, i.Htlcs); err != nil {
×
362
                return err
×
363
        }
×
364

365
        return nil
×
366
}
367

368
// serializeHtlcs serializes a map containing circuit keys and invoice htlcs to
369
// a writer.
370
func serializeHtlcs(w io.Writer, htlcs map[CircuitKey]*InvoiceHTLC) error {
×
371
        for key, htlc := range htlcs {
×
372
                // Encode the htlc in a tlv stream.
×
373
                chanID := key.ChanID.ToUint64()
×
374
                amt := uint64(htlc.Amt)
×
375
                acceptTime := uint64(htlc.AcceptTime.UnixNano())
×
376
                resolveTime := uint64(htlc.ResolveTime.UnixNano())
×
377
                state := uint8(htlc.State)
×
378

×
379
                tlvStream, err := tlv.NewStream(
×
380
                        tlv.MakePrimitiveRecord(chanIDType, &chanID),
×
381
                        tlv.MakePrimitiveRecord(htlcIDType, &key.HtlcID),
×
382
                        tlv.MakePrimitiveRecord(amtType, &amt),
×
383
                        tlv.MakePrimitiveRecord(
×
384
                                acceptHeightType, &htlc.AcceptHeight,
×
385
                        ),
×
386
                        tlv.MakePrimitiveRecord(acceptTimeType, &acceptTime),
×
387
                        tlv.MakePrimitiveRecord(resolveTimeType, &resolveTime),
×
388
                        tlv.MakePrimitiveRecord(expiryHeightType, &htlc.Expiry),
×
389
                        tlv.MakePrimitiveRecord(stateType, &state),
×
390
                )
×
391
                if err != nil {
×
392
                        return err
×
393
                }
×
394

395
                var b bytes.Buffer
×
396
                if err := tlvStream.Encode(&b); err != nil {
×
397
                        return err
×
398
                }
×
399

400
                // Write the length of the tlv stream followed by the stream
401
                // bytes.
402
                err = binary.Write(w, byteOrder, uint64(b.Len()))
×
403
                if err != nil {
×
404
                        return err
×
405
                }
×
406

407
                if _, err := w.Write(b.Bytes()); err != nil {
×
408
                        return err
×
409
                }
×
410
        }
411

412
        return nil
×
413
}
414

415
func deserializeInvoice(r io.Reader) (Invoice, error) {
×
416
        var err error
×
417
        invoice := Invoice{}
×
418

×
419
        // TODO(roasbeef): use read full everywhere
×
420
        invoice.Memo, err = wire.ReadVarBytes(r, 0, MaxMemoSize, "")
×
421
        if err != nil {
×
422
                return invoice, err
×
423
        }
×
424
        invoice.Receipt, err = wire.ReadVarBytes(r, 0, MaxReceiptSize, "")
×
425
        if err != nil {
×
426
                return invoice, err
×
427
        }
×
428

429
        invoice.PaymentRequest, err = wire.ReadVarBytes(r, 0, MaxPaymentRequestSize, "")
×
430
        if err != nil {
×
431
                return invoice, err
×
432
        }
×
433

434
        if err := binary.Read(r, byteOrder, &invoice.FinalCltvDelta); err != nil {
×
435
                return invoice, err
×
436
        }
×
437

438
        var expiry int64
×
439
        if err := binary.Read(r, byteOrder, &expiry); err != nil {
×
440
                return invoice, err
×
441
        }
×
442
        invoice.Expiry = time.Duration(expiry)
×
443

×
444
        birthBytes, err := wire.ReadVarBytes(r, 0, 300, "birth")
×
445
        if err != nil {
×
446
                return invoice, err
×
447
        }
×
448
        if err := invoice.CreationDate.UnmarshalBinary(birthBytes); err != nil {
×
449
                return invoice, err
×
450
        }
×
451

452
        settledBytes, err := wire.ReadVarBytes(r, 0, 300, "settled")
×
453
        if err != nil {
×
454
                return invoice, err
×
455
        }
×
456
        if err := invoice.SettleDate.UnmarshalBinary(settledBytes); err != nil {
×
457
                return invoice, err
×
458
        }
×
459

460
        if _, err := io.ReadFull(r, invoice.Terms.PaymentPreimage[:]); err != nil {
×
461
                return invoice, err
×
462
        }
×
463
        var scratch [8]byte
×
464
        if _, err := io.ReadFull(r, scratch[:]); err != nil {
×
465
                return invoice, err
×
466
        }
×
467
        invoice.Terms.Value = lnwire.MilliSatoshi(byteOrder.Uint64(scratch[:]))
×
468

×
469
        if err := binary.Read(r, byteOrder, &invoice.Terms.State); err != nil {
×
470
                return invoice, err
×
471
        }
×
472

473
        if err := binary.Read(r, byteOrder, &invoice.AddIndex); err != nil {
×
474
                return invoice, err
×
475
        }
×
476
        if err := binary.Read(r, byteOrder, &invoice.SettleIndex); err != nil {
×
477
                return invoice, err
×
478
        }
×
479
        if err := binary.Read(r, byteOrder, &invoice.AmtPaid); err != nil {
×
480
                return invoice, err
×
481
        }
×
482

483
        invoice.Htlcs, err = deserializeHtlcs(r)
×
484
        if err != nil {
×
485
                return Invoice{}, err
×
486
        }
×
487

488
        return invoice, nil
×
489
}
490

491
// deserializeHtlcs reads a list of invoice htlcs from a reader and returns it
492
// as a map.
493
func deserializeHtlcs(r io.Reader) (map[CircuitKey]*InvoiceHTLC, error) {
×
494
        htlcs := make(map[CircuitKey]*InvoiceHTLC, 0)
×
495

×
496
        for {
×
497
                // Read the length of the tlv stream for this htlc.
×
498
                var streamLen uint64
×
499
                if err := binary.Read(r, byteOrder, &streamLen); err != nil {
×
500
                        if err == io.EOF {
×
501
                                break
×
502
                        }
503

504
                        return nil, err
×
505
                }
506

507
                streamBytes := make([]byte, streamLen)
×
508
                if _, err := r.Read(streamBytes); err != nil {
×
509
                        return nil, err
×
510
                }
×
511
                streamReader := bytes.NewReader(streamBytes)
×
512

×
513
                // Decode the contents into the htlc fields.
×
514
                var (
×
515
                        htlc                    InvoiceHTLC
×
516
                        key                     CircuitKey
×
517
                        chanID                  uint64
×
518
                        state                   uint8
×
519
                        acceptTime, resolveTime uint64
×
520
                        amt                     uint64
×
521
                )
×
522
                tlvStream, err := tlv.NewStream(
×
523
                        tlv.MakePrimitiveRecord(chanIDType, &chanID),
×
524
                        tlv.MakePrimitiveRecord(htlcIDType, &key.HtlcID),
×
525
                        tlv.MakePrimitiveRecord(amtType, &amt),
×
526
                        tlv.MakePrimitiveRecord(
×
527
                                acceptHeightType, &htlc.AcceptHeight,
×
528
                        ),
×
529
                        tlv.MakePrimitiveRecord(acceptTimeType, &acceptTime),
×
530
                        tlv.MakePrimitiveRecord(resolveTimeType, &resolveTime),
×
531
                        tlv.MakePrimitiveRecord(expiryHeightType, &htlc.Expiry),
×
532
                        tlv.MakePrimitiveRecord(stateType, &state),
×
533
                )
×
534
                if err != nil {
×
535
                        return nil, err
×
536
                }
×
537

538
                if err := tlvStream.Decode(streamReader); err != nil {
×
539
                        return nil, err
×
540
                }
×
541

542
                key.ChanID = lnwire.NewShortChanIDFromInt(chanID)
×
543
                htlc.AcceptTime = time.Unix(0, int64(acceptTime))
×
544
                htlc.ResolveTime = time.Unix(0, int64(resolveTime))
×
545
                htlc.State = HtlcState(state)
×
546
                htlc.Amt = lnwire.MilliSatoshi(amt)
×
547

×
548
                htlcs[key] = &htlc
×
549
        }
550

551
        return htlcs, nil
×
552
}
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