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

lightningnetwork / lnd / 14193549836

01 Apr 2025 10:40AM UTC coverage: 69.046% (+0.007%) from 69.039%
14193549836

Pull #9665

github

web-flow
Merge e8825f209 into b01f4e514
Pull Request #9665: kvdb: bump etcd libs to v3.5.12

133439 of 193262 relevant lines covered (69.05%)

22119.45 hits per line

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

53.63
/channeldb/migration_01_to_11/payments.go
1
package migration_01_to_11
2

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

12
        "github.com/btcsuite/btcd/btcec/v2"
13
        "github.com/btcsuite/btcd/wire"
14
        lnwire "github.com/lightningnetwork/lnd/channeldb/migration/lnwire21"
15
        "github.com/lightningnetwork/lnd/kvdb"
16
        "github.com/lightningnetwork/lnd/lntypes"
17
        "github.com/lightningnetwork/lnd/tlv"
18
)
19

20
var (
21
        // paymentsRootBucket is the name of the top-level bucket within the
22
        // database that stores all data related to payments. Within this
23
        // bucket, each payment hash its own sub-bucket keyed by its payment
24
        // hash.
25
        //
26
        // Bucket hierarchy:
27
        //
28
        // root-bucket
29
        //      |
30
        //      |-- <paymenthash>
31
        //      |        |--sequence-key: <sequence number>
32
        //      |        |--creation-info-key: <creation info>
33
        //      |        |--attempt-info-key: <attempt info>
34
        //      |        |--settle-info-key: <settle info>
35
        //      |        |--fail-info-key: <fail info>
36
        //      |        |
37
        //      |        |--duplicate-bucket (only for old, completed payments)
38
        //      |                 |
39
        //      |                 |-- <seq-num>
40
        //      |                 |       |--sequence-key: <sequence number>
41
        //      |                 |       |--creation-info-key: <creation info>
42
        //      |                 |       |--attempt-info-key: <attempt info>
43
        //      |                 |       |--settle-info-key: <settle info>
44
        //      |                 |       |--fail-info-key: <fail info>
45
        //      |                 |
46
        //      |                 |-- <seq-num>
47
        //      |                 |       |
48
        //      |                ...     ...
49
        //      |
50
        //      |-- <paymenthash>
51
        //      |        |
52
        //      |       ...
53
        //     ...
54
        //
55
        paymentsRootBucket = []byte("payments-root-bucket")
56

57
        // paymentDublicateBucket is the name of a optional sub-bucket within
58
        // the payment hash bucket, that is used to hold duplicate payments to
59
        // a payment hash. This is needed to support information from earlier
60
        // versions of lnd, where it was possible to pay to a payment hash more
61
        // than once.
62
        paymentDuplicateBucket = []byte("payment-duplicate-bucket")
63

64
        // paymentSequenceKey is a key used in the payment's sub-bucket to
65
        // store the sequence number of the payment.
66
        paymentSequenceKey = []byte("payment-sequence-key")
67

68
        // paymentCreationInfoKey is a key used in the payment's sub-bucket to
69
        // store the creation info of the payment.
70
        paymentCreationInfoKey = []byte("payment-creation-info")
71

72
        // paymentAttemptInfoKey is a key used in the payment's sub-bucket to
73
        // store the info about the latest attempt that was done for the
74
        // payment in question.
75
        paymentAttemptInfoKey = []byte("payment-attempt-info")
76

77
        // paymentSettleInfoKey is a key used in the payment's sub-bucket to
78
        // store the settle info of the payment.
79
        paymentSettleInfoKey = []byte("payment-settle-info")
80

81
        // paymentFailInfoKey is a key used in the payment's sub-bucket to
82
        // store information about the reason a payment failed.
83
        paymentFailInfoKey = []byte("payment-fail-info")
84
)
85

86
// FailureReason encodes the reason a payment ultimately failed.
87
type FailureReason byte
88

89
const (
90
        // FailureReasonTimeout indicates that the payment did timeout before a
91
        // successful payment attempt was made.
92
        FailureReasonTimeout FailureReason = 0
93

94
        // FailureReasonNoRoute indicates no successful route to the
95
        // destination was found during path finding.
96
        FailureReasonNoRoute FailureReason = 1
97

98
        // FailureReasonError indicates that an unexpected error happened during
99
        // payment.
100
        FailureReasonError FailureReason = 2
101

102
        // FailureReasonIncorrectPaymentDetails indicates that either the hash
103
        // is unknown or the final cltv delta or amount is incorrect.
104
        FailureReasonIncorrectPaymentDetails FailureReason = 3
105

106
        // TODO(halseth): cancel state.
107

108
        // TODO(joostjager): Add failure reasons for:
109
        // LocalLiquidityInsufficient, RemoteCapacityInsufficient.
110
)
111

112
// String returns a human readable FailureReason
113
func (r FailureReason) String() string {
×
114
        switch r {
×
115
        case FailureReasonTimeout:
×
116
                return "timeout"
×
117
        case FailureReasonNoRoute:
×
118
                return "no_route"
×
119
        case FailureReasonError:
×
120
                return "error"
×
121
        case FailureReasonIncorrectPaymentDetails:
×
122
                return "incorrect_payment_details"
×
123
        }
124

125
        return "unknown"
×
126
}
127

128
// PaymentStatus represent current status of payment
129
type PaymentStatus byte
130

131
const (
132
        // StatusUnknown is the status where a payment has never been initiated
133
        // and hence is unknown.
134
        StatusUnknown PaymentStatus = 0
135

136
        // StatusInFlight is the status where a payment has been initiated, but
137
        // a response has not been received.
138
        StatusInFlight PaymentStatus = 1
139

140
        // StatusSucceeded is the status where a payment has been initiated and
141
        // the payment was completed successfully.
142
        StatusSucceeded PaymentStatus = 2
143

144
        // StatusFailed is the status where a payment has been initiated and a
145
        // failure result has come back.
146
        StatusFailed PaymentStatus = 3
147
)
148

149
// Bytes returns status as slice of bytes.
150
func (ps PaymentStatus) Bytes() []byte {
2✔
151
        return []byte{byte(ps)}
2✔
152
}
2✔
153

154
// FromBytes sets status from slice of bytes.
155
func (ps *PaymentStatus) FromBytes(status []byte) error {
2✔
156
        if len(status) != 1 {
2✔
157
                return errors.New("payment status is empty")
×
158
        }
×
159

160
        switch PaymentStatus(status[0]) {
2✔
161
        case StatusUnknown, StatusInFlight, StatusSucceeded, StatusFailed:
2✔
162
                *ps = PaymentStatus(status[0])
2✔
163
        default:
×
164
                return errors.New("unknown payment status")
×
165
        }
166

167
        return nil
2✔
168
}
169

170
// String returns readable representation of payment status.
171
func (ps PaymentStatus) String() string {
×
172
        switch ps {
×
173
        case StatusUnknown:
×
174
                return "Unknown"
×
175
        case StatusInFlight:
×
176
                return "In Flight"
×
177
        case StatusSucceeded:
×
178
                return "Succeeded"
×
179
        case StatusFailed:
×
180
                return "Failed"
×
181
        default:
×
182
                return "Unknown"
×
183
        }
184
}
185

186
// PaymentCreationInfo is the information necessary to have ready when
187
// initiating a payment, moving it into state InFlight.
188
type PaymentCreationInfo struct {
189
        // PaymentHash is the hash this payment is paying to.
190
        PaymentHash lntypes.Hash
191

192
        // Value is the amount we are paying.
193
        Value lnwire.MilliSatoshi
194

195
        // CreatingDate is the time when this payment was initiated.
196
        CreationDate time.Time
197

198
        // PaymentRequest is the full payment request, if any.
199
        PaymentRequest []byte
200
}
201

202
// PaymentAttemptInfo contains information about a specific payment attempt for
203
// a given payment. This information is used by the router to handle any errors
204
// coming back after an attempt is made, and to query the switch about the
205
// status of a payment. For settled payment this will be the information for
206
// the succeeding payment attempt.
207
type PaymentAttemptInfo struct {
208
        // PaymentID is the unique ID used for this attempt.
209
        PaymentID uint64
210

211
        // SessionKey is the ephemeral key used for this payment attempt.
212
        SessionKey *btcec.PrivateKey
213

214
        // Route is the route attempted to send the HTLC.
215
        Route Route
216
}
217

218
// Payment is a wrapper around a payment's PaymentCreationInfo,
219
// PaymentAttemptInfo, and preimage. All payments will have the
220
// PaymentCreationInfo set, the PaymentAttemptInfo will be set only if at least
221
// one payment attempt has been made, while only completed payments will have a
222
// non-zero payment preimage.
223
type Payment struct {
224
        // sequenceNum is a unique identifier used to sort the payments in
225
        // order of creation.
226
        sequenceNum uint64
227

228
        // Status is the current PaymentStatus of this payment.
229
        Status PaymentStatus
230

231
        // Info holds all static information about this payment, and is
232
        // populated when the payment is initiated.
233
        Info *PaymentCreationInfo
234

235
        // Attempt is the information about the last payment attempt made.
236
        //
237
        // NOTE: Can be nil if no attempt is yet made.
238
        Attempt *PaymentAttemptInfo
239

240
        // PaymentPreimage is the preimage of a successful payment. This serves
241
        // as a proof of payment. It will only be non-nil for settled payments.
242
        //
243
        // NOTE: Can be nil if payment is not settled.
244
        PaymentPreimage *lntypes.Preimage
245

246
        // Failure is a failure reason code indicating the reason the payment
247
        // failed. It is only non-nil for failed payments.
248
        //
249
        // NOTE: Can be nil if payment is not failed.
250
        Failure *FailureReason
251
}
252

253
// FetchPayments returns all sent payments found in the DB.
254
func (db *DB) FetchPayments() ([]*Payment, error) {
1✔
255
        var payments []*Payment
1✔
256

1✔
257
        err := kvdb.View(db, func(tx kvdb.RTx) error {
2✔
258
                paymentsBucket := tx.ReadBucket(paymentsRootBucket)
1✔
259
                if paymentsBucket == nil {
1✔
260
                        return nil
×
261
                }
×
262

263
                return paymentsBucket.ForEach(func(k, v []byte) error {
4✔
264
                        bucket := paymentsBucket.NestedReadBucket(k)
3✔
265
                        if bucket == nil {
3✔
266
                                // We only expect sub-buckets to be found in
×
267
                                // this top-level bucket.
×
268
                                return fmt.Errorf("non bucket element in " +
×
269
                                        "payments bucket")
×
270
                        }
×
271

272
                        p, err := fetchPayment(bucket)
3✔
273
                        if err != nil {
3✔
274
                                return err
×
275
                        }
×
276

277
                        payments = append(payments, p)
3✔
278

3✔
279
                        // For older versions of lnd, duplicate payments to a
3✔
280
                        // payment has was possible. These will be found in a
3✔
281
                        // sub-bucket indexed by their sequence number if
3✔
282
                        // available.
3✔
283
                        dup := bucket.NestedReadBucket(paymentDuplicateBucket)
3✔
284
                        if dup == nil {
5✔
285
                                return nil
2✔
286
                        }
2✔
287

288
                        return dup.ForEach(func(k, v []byte) error {
2✔
289
                                subBucket := dup.NestedReadBucket(k)
1✔
290
                                if subBucket == nil {
1✔
291
                                        // We one bucket for each duplicate to
×
292
                                        // be found.
×
293
                                        return fmt.Errorf("non bucket element" +
×
294
                                                "in duplicate bucket")
×
295
                                }
×
296

297
                                p, err := fetchPayment(subBucket)
1✔
298
                                if err != nil {
1✔
299
                                        return err
×
300
                                }
×
301

302
                                payments = append(payments, p)
1✔
303
                                return nil
1✔
304
                        })
305
                })
306
        }, func() {
1✔
307
                payments = nil
1✔
308
        })
1✔
309
        if err != nil {
1✔
310
                return nil, err
×
311
        }
×
312

313
        // Before returning, sort the payments by their sequence number.
314
        sort.Slice(payments, func(i, j int) bool {
6✔
315
                return payments[i].sequenceNum < payments[j].sequenceNum
5✔
316
        })
5✔
317

318
        return payments, nil
1✔
319
}
320

321
func fetchPayment(bucket kvdb.RBucket) (*Payment, error) {
4✔
322
        var (
4✔
323
                err error
4✔
324
                p   = &Payment{}
4✔
325
        )
4✔
326

4✔
327
        seqBytes := bucket.Get(paymentSequenceKey)
4✔
328
        if seqBytes == nil {
4✔
329
                return nil, fmt.Errorf("sequence number not found")
×
330
        }
×
331

332
        p.sequenceNum = binary.BigEndian.Uint64(seqBytes)
4✔
333

4✔
334
        // Get the payment status.
4✔
335
        p.Status = fetchPaymentStatus(bucket)
4✔
336

4✔
337
        // Get the PaymentCreationInfo.
4✔
338
        b := bucket.Get(paymentCreationInfoKey)
4✔
339
        if b == nil {
4✔
340
                return nil, fmt.Errorf("creation info not found")
×
341
        }
×
342

343
        r := bytes.NewReader(b)
4✔
344
        p.Info, err = deserializePaymentCreationInfo(r)
4✔
345
        if err != nil {
4✔
346
                return nil, err
×
347

×
348
        }
×
349

350
        // Get the PaymentAttemptInfo. This can be unset.
351
        b = bucket.Get(paymentAttemptInfoKey)
4✔
352
        if b != nil {
8✔
353
                r = bytes.NewReader(b)
4✔
354
                p.Attempt, err = deserializePaymentAttemptInfo(r)
4✔
355
                if err != nil {
4✔
356
                        return nil, err
×
357
                }
×
358
        }
359

360
        // Get the payment preimage. This is only found for
361
        // completed payments.
362
        b = bucket.Get(paymentSettleInfoKey)
4✔
363
        if b != nil {
4✔
364
                var preimg lntypes.Preimage
×
365
                copy(preimg[:], b[:])
×
366
                p.PaymentPreimage = &preimg
×
367
        }
×
368

369
        // Get failure reason if available.
370
        b = bucket.Get(paymentFailInfoKey)
4✔
371
        if b != nil {
4✔
372
                reason := FailureReason(b[0])
×
373
                p.Failure = &reason
×
374
        }
×
375

376
        return p, nil
4✔
377
}
378

379
func serializePaymentCreationInfo(w io.Writer, c *PaymentCreationInfo) error {
8✔
380
        var scratch [8]byte
8✔
381

8✔
382
        if _, err := w.Write(c.PaymentHash[:]); err != nil {
8✔
383
                return err
×
384
        }
×
385

386
        byteOrder.PutUint64(scratch[:], uint64(c.Value))
8✔
387
        if _, err := w.Write(scratch[:]); err != nil {
8✔
388
                return err
×
389
        }
×
390

391
        byteOrder.PutUint64(scratch[:], uint64(c.CreationDate.Unix()))
8✔
392
        if _, err := w.Write(scratch[:]); err != nil {
8✔
393
                return err
×
394
        }
×
395

396
        byteOrder.PutUint32(scratch[:4], uint32(len(c.PaymentRequest)))
8✔
397
        if _, err := w.Write(scratch[:4]); err != nil {
8✔
398
                return err
×
399
        }
×
400

401
        if _, err := w.Write(c.PaymentRequest[:]); err != nil {
8✔
402
                return err
×
403
        }
×
404

405
        return nil
8✔
406
}
407

408
func deserializePaymentCreationInfo(r io.Reader) (*PaymentCreationInfo, error) {
8✔
409
        var scratch [8]byte
8✔
410

8✔
411
        c := &PaymentCreationInfo{}
8✔
412

8✔
413
        if _, err := io.ReadFull(r, c.PaymentHash[:]); err != nil {
8✔
414
                return nil, err
×
415
        }
×
416

417
        if _, err := io.ReadFull(r, scratch[:]); err != nil {
8✔
418
                return nil, err
×
419
        }
×
420
        c.Value = lnwire.MilliSatoshi(byteOrder.Uint64(scratch[:]))
8✔
421

8✔
422
        if _, err := io.ReadFull(r, scratch[:]); err != nil {
8✔
423
                return nil, err
×
424
        }
×
425
        c.CreationDate = time.Unix(int64(byteOrder.Uint64(scratch[:])), 0)
8✔
426

8✔
427
        if _, err := io.ReadFull(r, scratch[:4]); err != nil {
8✔
428
                return nil, err
×
429
        }
×
430

431
        reqLen := uint32(byteOrder.Uint32(scratch[:4]))
8✔
432
        payReq := make([]byte, reqLen)
8✔
433
        if reqLen > 0 {
16✔
434
                if _, err := io.ReadFull(r, payReq[:]); err != nil {
8✔
435
                        return nil, err
×
436
                }
×
437
        }
438
        c.PaymentRequest = payReq
8✔
439

8✔
440
        return c, nil
8✔
441
}
442

443
func serializePaymentAttemptInfo(w io.Writer, a *PaymentAttemptInfo) error {
4✔
444
        if err := WriteElements(w, a.PaymentID, a.SessionKey); err != nil {
4✔
445
                return err
×
446
        }
×
447

448
        if err := SerializeRoute(w, a.Route); err != nil {
4✔
449
                return err
×
450
        }
×
451

452
        return nil
4✔
453
}
454

455
func deserializePaymentAttemptInfo(r io.Reader) (*PaymentAttemptInfo, error) {
4✔
456
        a := &PaymentAttemptInfo{}
4✔
457
        err := ReadElements(r, &a.PaymentID, &a.SessionKey)
4✔
458
        if err != nil {
4✔
459
                return nil, err
×
460
        }
×
461
        a.Route, err = DeserializeRoute(r)
4✔
462
        if err != nil {
4✔
463
                return nil, err
×
464
        }
×
465
        return a, nil
4✔
466
}
467

468
func serializeHop(w io.Writer, h *Hop) error {
8✔
469
        if err := WriteElements(w,
8✔
470
                h.PubKeyBytes[:], h.ChannelID, h.OutgoingTimeLock,
8✔
471
                h.AmtToForward,
8✔
472
        ); err != nil {
8✔
473
                return err
×
474
        }
×
475

476
        if err := binary.Write(w, byteOrder, h.LegacyPayload); err != nil {
8✔
477
                return err
×
478
        }
×
479

480
        // For legacy payloads, we don't need to write any TLV records, so
481
        // we'll write a zero indicating the our serialized TLV map has no
482
        // records.
483
        if h.LegacyPayload {
16✔
484
                return WriteElements(w, uint32(0))
8✔
485
        }
8✔
486

487
        // Otherwise, we'll transform our slice of records into a map of the
488
        // raw bytes, then serialize them in-line with a length (number of
489
        // elements) prefix.
490
        mapRecords, err := tlv.RecordsToMap(h.TLVRecords)
×
491
        if err != nil {
×
492
                return err
×
493
        }
×
494

495
        numRecords := uint32(len(mapRecords))
×
496
        if err := WriteElements(w, numRecords); err != nil {
×
497
                return err
×
498
        }
×
499

500
        for recordType, rawBytes := range mapRecords {
×
501
                if err := WriteElements(w, recordType); err != nil {
×
502
                        return err
×
503
                }
×
504

505
                if err := wire.WriteVarBytes(w, 0, rawBytes); err != nil {
×
506
                        return err
×
507
                }
×
508
        }
509

510
        return nil
×
511
}
512

513
// maxOnionPayloadSize is the largest Sphinx payload possible, so we don't need
514
// to read/write a TLV stream larger than this.
515
const maxOnionPayloadSize = 1300
516

517
func deserializeHop(r io.Reader) (*Hop, error) {
8✔
518
        h := &Hop{}
8✔
519

8✔
520
        var pub []byte
8✔
521
        if err := ReadElements(r, &pub); err != nil {
8✔
522
                return nil, err
×
523
        }
×
524
        copy(h.PubKeyBytes[:], pub)
8✔
525

8✔
526
        if err := ReadElements(r,
8✔
527
                &h.ChannelID, &h.OutgoingTimeLock, &h.AmtToForward,
8✔
528
        ); err != nil {
8✔
529
                return nil, err
×
530
        }
×
531

532
        // TODO(roasbeef): change field to allow LegacyPayload false to be the
533
        // legacy default?
534
        err := binary.Read(r, byteOrder, &h.LegacyPayload)
8✔
535
        if err != nil {
8✔
536
                return nil, err
×
537
        }
×
538

539
        var numElements uint32
8✔
540
        if err := ReadElements(r, &numElements); err != nil {
8✔
541
                return nil, err
×
542
        }
×
543

544
        // If there're no elements, then we can return early.
545
        if numElements == 0 {
16✔
546
                return h, nil
8✔
547
        }
8✔
548

549
        tlvMap := make(map[uint64][]byte)
×
550
        for i := uint32(0); i < numElements; i++ {
×
551
                var tlvType uint64
×
552
                if err := ReadElements(r, &tlvType); err != nil {
×
553
                        return nil, err
×
554
                }
×
555

556
                rawRecordBytes, err := wire.ReadVarBytes(
×
557
                        r, 0, maxOnionPayloadSize, "tlv",
×
558
                )
×
559
                if err != nil {
×
560
                        return nil, err
×
561
                }
×
562

563
                tlvMap[tlvType] = rawRecordBytes
×
564
        }
565

566
        h.TLVRecords = tlv.MapToRecords(tlvMap)
×
567

×
568
        return h, nil
×
569
}
570

571
// SerializeRoute serializes a route.
572
func SerializeRoute(w io.Writer, r Route) error {
4✔
573
        if err := WriteElements(w,
4✔
574
                r.TotalTimeLock, r.TotalAmount, r.SourcePubKey[:],
4✔
575
        ); err != nil {
4✔
576
                return err
×
577
        }
×
578

579
        if err := WriteElements(w, uint32(len(r.Hops))); err != nil {
4✔
580
                return err
×
581
        }
×
582

583
        for _, h := range r.Hops {
12✔
584
                if err := serializeHop(w, h); err != nil {
8✔
585
                        return err
×
586
                }
×
587
        }
588

589
        return nil
4✔
590
}
591

592
// DeserializeRoute deserializes a route.
593
func DeserializeRoute(r io.Reader) (Route, error) {
4✔
594
        rt := Route{}
4✔
595
        if err := ReadElements(r,
4✔
596
                &rt.TotalTimeLock, &rt.TotalAmount,
4✔
597
        ); err != nil {
4✔
598
                return rt, err
×
599
        }
×
600

601
        var pub []byte
4✔
602
        if err := ReadElements(r, &pub); err != nil {
4✔
603
                return rt, err
×
604
        }
×
605
        copy(rt.SourcePubKey[:], pub)
4✔
606

4✔
607
        var numHops uint32
4✔
608
        if err := ReadElements(r, &numHops); err != nil {
4✔
609
                return rt, err
×
610
        }
×
611

612
        var hops []*Hop
4✔
613
        for i := uint32(0); i < numHops; i++ {
12✔
614
                hop, err := deserializeHop(r)
8✔
615
                if err != nil {
8✔
616
                        return rt, err
×
617
                }
×
618
                hops = append(hops, hop)
8✔
619
        }
620
        rt.Hops = hops
4✔
621

4✔
622
        return rt, nil
4✔
623
}
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