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

lightningnetwork / lnd / 13566028875

27 Feb 2025 12:09PM UTC coverage: 49.396% (-9.4%) from 58.748%
13566028875

Pull #9555

github

ellemouton
graph/db: populate the graph cache in Start instead of during construction

In this commit, we move the graph cache population logic out of the
ChannelGraph constructor and into its Start method instead.
Pull Request #9555: graph: extract cache from CRUD [6]

34 of 54 new or added lines in 4 files covered. (62.96%)

27464 existing lines in 436 files now uncovered.

101095 of 204664 relevant lines covered (49.4%)

1.54 hits per line

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

0.0
/channeldb/migration32/mission_control_store.go
1
package migration32
2

3
import (
4
        "bytes"
5
        "io"
6
        "math"
7
        "time"
8

9
        "github.com/btcsuite/btcd/wire"
10
        lnwire "github.com/lightningnetwork/lnd/channeldb/migration/lnwire21"
11
        "github.com/lightningnetwork/lnd/fn/v2"
12
        "github.com/lightningnetwork/lnd/tlv"
13
)
14

15
const (
16
        // unknownFailureSourceIdx is the database encoding of an unknown error
17
        // source.
18
        unknownFailureSourceIdx = -1
19
)
20

21
var (
22
        // resultsKey is the fixed key under which the attempt results are
23
        // stored.
24
        resultsKey = []byte("missioncontrol-results")
25
)
26

27
// paymentResultOld is the information that becomes available when a payment
28
// attempt completes.
29
type paymentResultOld struct {
30
        id                 uint64
31
        timeFwd, timeReply time.Time
32
        route              *Route
33
        success            bool
34
        failureSourceIdx   *int
35
        failure            lnwire.FailureMessage
36
}
37

38
// deserializeOldResult deserializes a payment result using the old encoding.
UNCOV
39
func deserializeOldResult(k, v []byte) (*paymentResultOld, error) {
×
UNCOV
40
        // Parse payment id.
×
UNCOV
41
        result := paymentResultOld{
×
UNCOV
42
                id: byteOrder.Uint64(k[8:]),
×
UNCOV
43
        }
×
UNCOV
44

×
UNCOV
45
        r := bytes.NewReader(v)
×
UNCOV
46

×
UNCOV
47
        // Read timestamps, success status and failure source index.
×
UNCOV
48
        var (
×
UNCOV
49
                timeFwd, timeReply uint64
×
UNCOV
50
                dbFailureSourceIdx int32
×
UNCOV
51
        )
×
UNCOV
52

×
UNCOV
53
        err := ReadElements(
×
UNCOV
54
                r, &timeFwd, &timeReply, &result.success, &dbFailureSourceIdx,
×
UNCOV
55
        )
×
UNCOV
56
        if err != nil {
×
57
                return nil, err
×
58
        }
×
59

60
        // Convert time stamps to local time zone for consistent logging.
UNCOV
61
        result.timeFwd = time.Unix(0, int64(timeFwd)).Local()
×
UNCOV
62
        result.timeReply = time.Unix(0, int64(timeReply)).Local()
×
UNCOV
63

×
UNCOV
64
        // Convert from unknown index magic number to nil value.
×
UNCOV
65
        if dbFailureSourceIdx != unknownFailureSourceIdx {
×
UNCOV
66
                failureSourceIdx := int(dbFailureSourceIdx)
×
UNCOV
67
                result.failureSourceIdx = &failureSourceIdx
×
UNCOV
68
        }
×
69

70
        // Read route.
UNCOV
71
        route, err := DeserializeRoute(r)
×
UNCOV
72
        if err != nil {
×
73
                return nil, err
×
74
        }
×
UNCOV
75
        result.route = &route
×
UNCOV
76

×
UNCOV
77
        // Read failure.
×
UNCOV
78
        failureBytes, err := wire.ReadVarBytes(r, 0, math.MaxUint16, "failure")
×
UNCOV
79
        if err != nil {
×
80
                return nil, err
×
81
        }
×
UNCOV
82
        if len(failureBytes) > 0 {
×
UNCOV
83
                result.failure, err = lnwire.DecodeFailureMessage(
×
UNCOV
84
                        bytes.NewReader(failureBytes), 0,
×
UNCOV
85
                )
×
UNCOV
86
                if err != nil {
×
87
                        return nil, err
×
88
                }
×
89
        }
90

UNCOV
91
        return &result, nil
×
92
}
93

94
// convertPaymentResult converts a paymentResultOld to a paymentResultNew.
UNCOV
95
func convertPaymentResult(old *paymentResultOld) *paymentResultNew {
×
UNCOV
96
        var failure *paymentFailure
×
UNCOV
97
        if !old.success {
×
UNCOV
98
                failure = newPaymentFailure(old.failureSourceIdx, old.failure)
×
UNCOV
99
        }
×
100

UNCOV
101
        return newPaymentResult(
×
UNCOV
102
                old.id, extractMCRoute(old.route), old.timeFwd, old.timeReply,
×
UNCOV
103
                failure,
×
UNCOV
104
        )
×
105
}
106

107
// newPaymentResult constructs a new paymentResult.
108
func newPaymentResult(id uint64, rt *mcRoute, timeFwd, timeReply time.Time,
UNCOV
109
        failure *paymentFailure) *paymentResultNew {
×
UNCOV
110

×
UNCOV
111
        result := &paymentResultNew{
×
UNCOV
112
                id: id,
×
UNCOV
113
                timeFwd: tlv.NewPrimitiveRecord[tlv.TlvType0](
×
UNCOV
114
                        uint64(timeFwd.UnixNano()),
×
UNCOV
115
                ),
×
UNCOV
116
                timeReply: tlv.NewPrimitiveRecord[tlv.TlvType1](
×
UNCOV
117
                        uint64(timeReply.UnixNano()),
×
UNCOV
118
                ),
×
UNCOV
119
                route: tlv.NewRecordT[tlv.TlvType2](*rt),
×
UNCOV
120
        }
×
UNCOV
121

×
UNCOV
122
        if failure != nil {
×
UNCOV
123
                result.failure = tlv.SomeRecordT(
×
UNCOV
124
                        tlv.NewRecordT[tlv.TlvType3](*failure),
×
UNCOV
125
                )
×
UNCOV
126
        }
×
127

UNCOV
128
        return result
×
129
}
130

131
// paymentResultNew is the information that becomes available when a payment
132
// attempt completes.
133
type paymentResultNew struct {
134
        id        uint64
135
        timeFwd   tlv.RecordT[tlv.TlvType0, uint64]
136
        timeReply tlv.RecordT[tlv.TlvType1, uint64]
137
        route     tlv.RecordT[tlv.TlvType2, mcRoute]
138

139
        // failure holds information related to the failure of a payment. The
140
        // presence of this record indicates a payment failure. The absence of
141
        // this record indicates a successful payment.
142
        failure tlv.OptionalRecordT[tlv.TlvType3, paymentFailure]
143
}
144

145
// paymentFailure represents the presence of a payment failure. It may or may
146
// not include additional information about said failure.
147
type paymentFailure struct {
148
        info tlv.OptionalRecordT[tlv.TlvType0, paymentFailureInfo]
149
}
150

151
// newPaymentFailure constructs a new paymentFailure struct. If the source
152
// index is nil, then an empty paymentFailure is returned. This represents a
153
// failure with unknown details. Otherwise, the index and failure message are
154
// used to populate the info field of the paymentFailure.
155
func newPaymentFailure(sourceIdx *int,
UNCOV
156
        failureMsg lnwire.FailureMessage) *paymentFailure {
×
UNCOV
157

×
UNCOV
158
        if sourceIdx == nil {
×
159
                return &paymentFailure{}
×
160
        }
×
161

UNCOV
162
        info := paymentFailureInfo{
×
UNCOV
163
                sourceIdx: tlv.NewPrimitiveRecord[tlv.TlvType0](
×
UNCOV
164
                        uint8(*sourceIdx),
×
UNCOV
165
                ),
×
UNCOV
166
                msg: tlv.NewRecordT[tlv.TlvType1](failureMessage{failureMsg}),
×
UNCOV
167
        }
×
UNCOV
168

×
UNCOV
169
        return &paymentFailure{
×
UNCOV
170
                info: tlv.SomeRecordT(tlv.NewRecordT[tlv.TlvType0](info)),
×
UNCOV
171
        }
×
172
}
173

174
// Record returns a TLV record that can be used to encode/decode a
175
// paymentFailure to/from a TLV stream.
UNCOV
176
func (r *paymentFailure) Record() tlv.Record {
×
UNCOV
177
        recordSize := func() uint64 {
×
UNCOV
178
                var (
×
UNCOV
179
                        b   bytes.Buffer
×
UNCOV
180
                        buf [8]byte
×
UNCOV
181
                )
×
UNCOV
182
                if err := encodePaymentFailure(&b, r, &buf); err != nil {
×
183
                        panic(err)
×
184
                }
185

UNCOV
186
                return uint64(len(b.Bytes()))
×
187
        }
188

UNCOV
189
        return tlv.MakeDynamicRecord(
×
UNCOV
190
                0, r, recordSize, encodePaymentFailure, decodePaymentFailure,
×
UNCOV
191
        )
×
192
}
193

UNCOV
194
func encodePaymentFailure(w io.Writer, val interface{}, _ *[8]byte) error {
×
UNCOV
195
        if v, ok := val.(*paymentFailure); ok {
×
UNCOV
196
                var recordProducers []tlv.RecordProducer
×
UNCOV
197
                v.info.WhenSome(
×
UNCOV
198
                        func(r tlv.RecordT[tlv.TlvType0, paymentFailureInfo]) {
×
UNCOV
199
                                recordProducers = append(recordProducers, &r)
×
UNCOV
200
                        },
×
201
                )
202

UNCOV
203
                return lnwire.EncodeRecordsTo(
×
UNCOV
204
                        w, lnwire.ProduceRecordsSorted(recordProducers...),
×
UNCOV
205
                )
×
206
        }
207

208
        return tlv.NewTypeForEncodingErr(val, "routing.paymentFailure")
×
209
}
210

211
func decodePaymentFailure(r io.Reader, val interface{}, _ *[8]byte,
212
        l uint64) error {
×
213

×
214
        if v, ok := val.(*paymentFailure); ok {
×
215
                var h paymentFailure
×
216

×
217
                info := tlv.ZeroRecordT[tlv.TlvType0, paymentFailureInfo]()
×
218
                typeMap, err := lnwire.DecodeRecords(
×
219
                        r, lnwire.ProduceRecordsSorted(&info)...,
×
220
                )
×
221
                if err != nil {
×
222
                        return err
×
223
                }
×
224

225
                if _, ok := typeMap[h.info.TlvType()]; ok {
×
226
                        h.info = tlv.SomeRecordT(info)
×
227
                }
×
228

229
                *v = h
×
230

×
231
                return nil
×
232
        }
233

234
        return tlv.NewTypeForDecodingErr(val, "routing.paymentFailure", l, l)
×
235
}
236

237
// paymentFailureInfo holds additional information about a payment failure.
238
type paymentFailureInfo struct {
239
        sourceIdx tlv.RecordT[tlv.TlvType0, uint8]
240
        msg       tlv.RecordT[tlv.TlvType1, failureMessage]
241
}
242

243
// Record returns a TLV record that can be used to encode/decode a
244
// paymentFailureInfo to/from a TLV stream.
UNCOV
245
func (r *paymentFailureInfo) Record() tlv.Record {
×
UNCOV
246
        recordSize := func() uint64 {
×
UNCOV
247
                var (
×
UNCOV
248
                        b   bytes.Buffer
×
UNCOV
249
                        buf [8]byte
×
UNCOV
250
                )
×
UNCOV
251
                if err := encodePaymentFailureInfo(&b, r, &buf); err != nil {
×
252
                        panic(err)
×
253
                }
254

UNCOV
255
                return uint64(len(b.Bytes()))
×
256
        }
257

UNCOV
258
        return tlv.MakeDynamicRecord(
×
UNCOV
259
                0, r, recordSize, encodePaymentFailureInfo,
×
UNCOV
260
                decodePaymentFailureInfo,
×
UNCOV
261
        )
×
262
}
263

UNCOV
264
func encodePaymentFailureInfo(w io.Writer, val interface{}, _ *[8]byte) error {
×
UNCOV
265
        if v, ok := val.(*paymentFailureInfo); ok {
×
UNCOV
266
                return lnwire.EncodeRecordsTo(
×
UNCOV
267
                        w, lnwire.ProduceRecordsSorted(
×
UNCOV
268
                                &v.sourceIdx, &v.msg,
×
UNCOV
269
                        ),
×
UNCOV
270
                )
×
UNCOV
271
        }
×
272

273
        return tlv.NewTypeForEncodingErr(val, "routing.paymentFailureInfo")
×
274
}
275

276
func decodePaymentFailureInfo(r io.Reader, val interface{}, _ *[8]byte,
277
        l uint64) error {
×
278

×
279
        if v, ok := val.(*paymentFailureInfo); ok {
×
280
                var h paymentFailureInfo
×
281

×
282
                _, err := lnwire.DecodeRecords(
×
283
                        r,
×
284
                        lnwire.ProduceRecordsSorted(&h.sourceIdx, &h.msg)...,
×
285
                )
×
286
                if err != nil {
×
287
                        return err
×
288
                }
×
289

290
                *v = h
×
291

×
292
                return nil
×
293
        }
294

295
        return tlv.NewTypeForDecodingErr(
×
296
                val, "routing.paymentFailureInfo", l, l,
×
297
        )
×
298
}
299

300
type failureMessage struct {
301
        lnwire.FailureMessage
302
}
303

304
// Record returns a TLV record that can be used to encode/decode a list of
305
// failureMessage to/from a TLV stream.
UNCOV
306
func (r *failureMessage) Record() tlv.Record {
×
UNCOV
307
        recordSize := func() uint64 {
×
UNCOV
308
                var (
×
UNCOV
309
                        b   bytes.Buffer
×
UNCOV
310
                        buf [8]byte
×
UNCOV
311
                )
×
UNCOV
312
                if err := encodeFailureMessage(&b, r, &buf); err != nil {
×
313
                        panic(err)
×
314
                }
315

UNCOV
316
                return uint64(len(b.Bytes()))
×
317
        }
318

UNCOV
319
        return tlv.MakeDynamicRecord(
×
UNCOV
320
                0, r, recordSize, encodeFailureMessage, decodeFailureMessage,
×
UNCOV
321
        )
×
322
}
323

UNCOV
324
func encodeFailureMessage(w io.Writer, val interface{}, _ *[8]byte) error {
×
UNCOV
325
        if v, ok := val.(*failureMessage); ok {
×
UNCOV
326
                var b bytes.Buffer
×
UNCOV
327
                err := lnwire.EncodeFailureMessage(&b, v.FailureMessage, 0)
×
UNCOV
328
                if err != nil {
×
329
                        return err
×
330
                }
×
331

UNCOV
332
                _, err = w.Write(b.Bytes())
×
UNCOV
333

×
UNCOV
334
                return err
×
335
        }
336

337
        return tlv.NewTypeForEncodingErr(val, "routing.failureMessage")
×
338
}
339

340
func decodeFailureMessage(r io.Reader, val interface{}, _ *[8]byte,
341
        l uint64) error {
×
342

×
343
        if v, ok := val.(*failureMessage); ok {
×
344
                msg, err := lnwire.DecodeFailureMessage(r, 0)
×
345
                if err != nil {
×
346
                        return err
×
347
                }
×
348

349
                *v = failureMessage{
×
350
                        FailureMessage: msg,
×
351
                }
×
352

×
353
                return nil
×
354
        }
355

356
        return tlv.NewTypeForDecodingErr(val, "routing.failureMessage", l, l)
×
357
}
358

359
// extractMCRoute extracts the fields required by MC from the Route struct to
360
// create the more minimal mcRoute struct.
UNCOV
361
func extractMCRoute(r *Route) *mcRoute {
×
UNCOV
362
        return &mcRoute{
×
UNCOV
363
                sourcePubKey: tlv.NewRecordT[tlv.TlvType0](r.SourcePubKey),
×
UNCOV
364
                totalAmount:  tlv.NewRecordT[tlv.TlvType1](r.TotalAmount),
×
UNCOV
365
                hops: tlv.NewRecordT[tlv.TlvType2](
×
UNCOV
366
                        extractMCHops(r.Hops),
×
UNCOV
367
                ),
×
UNCOV
368
        }
×
UNCOV
369
}
×
370

371
// extractMCHops extracts the Hop fields that MC actually uses from a slice of
372
// Hops.
UNCOV
373
func extractMCHops(hops []*Hop) mcHops {
×
UNCOV
374
        return fn.Map(hops, extractMCHop)
×
UNCOV
375
}
×
376

377
// extractMCHop extracts the Hop fields that MC actually uses from a Hop.
UNCOV
378
func extractMCHop(hop *Hop) *mcHop {
×
UNCOV
379
        h := mcHop{
×
UNCOV
380
                channelID: tlv.NewPrimitiveRecord[tlv.TlvType0, uint64](
×
UNCOV
381
                        hop.ChannelID,
×
UNCOV
382
                ),
×
UNCOV
383
                pubKeyBytes: tlv.NewRecordT[tlv.TlvType1, Vertex](
×
UNCOV
384
                        hop.PubKeyBytes,
×
UNCOV
385
                ),
×
UNCOV
386
                amtToFwd: tlv.NewRecordT[tlv.TlvType2, lnwire.MilliSatoshi](
×
UNCOV
387
                        hop.AmtToForward,
×
UNCOV
388
                ),
×
UNCOV
389
        }
×
UNCOV
390

×
UNCOV
391
        if hop.BlindingPoint != nil {
×
UNCOV
392
                h.hasBlindingPoint = tlv.SomeRecordT(
×
UNCOV
393
                        tlv.NewRecordT[tlv.TlvType3, lnwire.TrueBoolean](
×
UNCOV
394
                                lnwire.TrueBoolean{},
×
UNCOV
395
                        ),
×
UNCOV
396
                )
×
UNCOV
397
        }
×
398

UNCOV
399
        if len(hop.CustomRecords) != 0 {
×
UNCOV
400
                h.hasCustomRecords = tlv.SomeRecordT(
×
UNCOV
401
                        tlv.NewRecordT[tlv.TlvType4, lnwire.TrueBoolean](
×
UNCOV
402
                                lnwire.TrueBoolean{},
×
UNCOV
403
                        ),
×
UNCOV
404
                )
×
UNCOV
405
        }
×
406

UNCOV
407
        return &h
×
408
}
409

410
// mcRoute holds the bare minimum info about a payment attempt route that MC
411
// requires.
412
type mcRoute struct {
413
        sourcePubKey tlv.RecordT[tlv.TlvType0, Vertex]
414
        totalAmount  tlv.RecordT[tlv.TlvType1, lnwire.MilliSatoshi]
415
        hops         tlv.RecordT[tlv.TlvType2, mcHops]
416
}
417

418
// Record returns a TLV record that can be used to encode/decode an mcRoute
419
// to/from a TLV stream.
UNCOV
420
func (r *mcRoute) Record() tlv.Record {
×
UNCOV
421
        recordSize := func() uint64 {
×
UNCOV
422
                var (
×
UNCOV
423
                        b   bytes.Buffer
×
UNCOV
424
                        buf [8]byte
×
UNCOV
425
                )
×
UNCOV
426
                if err := encodeMCRoute(&b, r, &buf); err != nil {
×
427
                        panic(err)
×
428
                }
429

UNCOV
430
                return uint64(len(b.Bytes()))
×
431
        }
432

UNCOV
433
        return tlv.MakeDynamicRecord(
×
UNCOV
434
                0, r, recordSize, encodeMCRoute, decodeMCRoute,
×
UNCOV
435
        )
×
436
}
437

UNCOV
438
func encodeMCRoute(w io.Writer, val interface{}, _ *[8]byte) error {
×
UNCOV
439
        if v, ok := val.(*mcRoute); ok {
×
UNCOV
440
                return serializeRoute(w, v)
×
UNCOV
441
        }
×
442

443
        return tlv.NewTypeForEncodingErr(val, "routing.mcRoute")
×
444
}
445

446
func decodeMCRoute(r io.Reader, val interface{}, _ *[8]byte, l uint64) error {
×
447
        if v, ok := val.(*mcRoute); ok {
×
448
                route, err := deserializeRoute(io.LimitReader(r, int64(l)))
×
449
                if err != nil {
×
450
                        return err
×
451
                }
×
452

453
                *v = *route
×
454

×
455
                return nil
×
456
        }
457

458
        return tlv.NewTypeForDecodingErr(val, "routing.mcRoute", l, l)
×
459
}
460

461
// mcHops is a list of mcHop records.
462
type mcHops []*mcHop
463

464
// Record returns a TLV record that can be used to encode/decode a list of
465
// mcHop to/from a TLV stream.
UNCOV
466
func (h *mcHops) Record() tlv.Record {
×
UNCOV
467
        recordSize := func() uint64 {
×
UNCOV
468
                var (
×
UNCOV
469
                        b   bytes.Buffer
×
UNCOV
470
                        buf [8]byte
×
UNCOV
471
                )
×
UNCOV
472
                if err := encodeMCHops(&b, h, &buf); err != nil {
×
473
                        panic(err)
×
474
                }
475

UNCOV
476
                return uint64(len(b.Bytes()))
×
477
        }
478

UNCOV
479
        return tlv.MakeDynamicRecord(
×
UNCOV
480
                0, h, recordSize, encodeMCHops, decodeMCHops,
×
UNCOV
481
        )
×
482
}
483

UNCOV
484
func encodeMCHops(w io.Writer, val interface{}, buf *[8]byte) error {
×
UNCOV
485
        if v, ok := val.(*mcHops); ok {
×
UNCOV
486
                // Encode the number of hops as a var int.
×
UNCOV
487
                if err := tlv.WriteVarInt(w, uint64(len(*v)), buf); err != nil {
×
488
                        return err
×
489
                }
×
490

491
                // With that written out, we'll now encode the entries
492
                // themselves as a sub-TLV record, which includes its _own_
493
                // inner length prefix.
UNCOV
494
                for _, hop := range *v {
×
UNCOV
495
                        var hopBytes bytes.Buffer
×
UNCOV
496
                        if err := serializeNewHop(&hopBytes, hop); err != nil {
×
497
                                return err
×
498
                        }
×
499

500
                        // We encode the record with a varint length followed by
501
                        // the _raw_ TLV bytes.
UNCOV
502
                        tlvLen := uint64(len(hopBytes.Bytes()))
×
UNCOV
503
                        if err := tlv.WriteVarInt(w, tlvLen, buf); err != nil {
×
504
                                return err
×
505
                        }
×
506

UNCOV
507
                        if _, err := w.Write(hopBytes.Bytes()); err != nil {
×
508
                                return err
×
509
                        }
×
510
                }
511

UNCOV
512
                return nil
×
513
        }
514

515
        return tlv.NewTypeForEncodingErr(val, "routing.mcHops")
×
516
}
517

518
func decodeMCHops(r io.Reader, val interface{}, buf *[8]byte, l uint64) error {
×
519
        if v, ok := val.(*mcHops); ok {
×
520
                // First, we'll decode the varint that encodes how many hops
×
521
                // are encoded in the stream.
×
522
                numHops, err := tlv.ReadVarInt(r, buf)
×
523
                if err != nil {
×
524
                        return err
×
525
                }
×
526

527
                // Now that we know how many records we'll need to read, we can
528
                // iterate and read them all out in series.
529
                for i := uint64(0); i < numHops; i++ {
×
530
                        // Read out the varint that encodes the size of this
×
531
                        // inner TLV record.
×
532
                        hopSize, err := tlv.ReadVarInt(r, buf)
×
533
                        if err != nil {
×
534
                                return err
×
535
                        }
×
536

537
                        // Using this information, we'll create a new limited
538
                        // reader that'll return an EOF once the end has been
539
                        // reached so the stream stops consuming bytes.
540
                        innerTlvReader := &io.LimitedReader{
×
541
                                R: r,
×
542
                                N: int64(hopSize),
×
543
                        }
×
544

×
545
                        hop, err := deserializeNewHop(innerTlvReader)
×
546
                        if err != nil {
×
547
                                return err
×
548
                        }
×
549

550
                        *v = append(*v, hop)
×
551
                }
552

553
                return nil
×
554
        }
555

556
        return tlv.NewTypeForDecodingErr(val, "routing.mcHops", l, l)
×
557
}
558

559
// serializeRoute serializes a mcRoute and writes the resulting bytes to the
560
// given io.Writer.
UNCOV
561
func serializeRoute(w io.Writer, r *mcRoute) error {
×
UNCOV
562
        records := lnwire.ProduceRecordsSorted(
×
UNCOV
563
                &r.sourcePubKey,
×
UNCOV
564
                &r.totalAmount,
×
UNCOV
565
                &r.hops,
×
UNCOV
566
        )
×
UNCOV
567

×
UNCOV
568
        return lnwire.EncodeRecordsTo(w, records)
×
UNCOV
569
}
×
570

571
// deserializeRoute deserializes the mcRoute from the given io.Reader.
572
func deserializeRoute(r io.Reader) (*mcRoute, error) {
×
573
        var rt mcRoute
×
574
        records := lnwire.ProduceRecordsSorted(
×
575
                &rt.sourcePubKey,
×
576
                &rt.totalAmount,
×
577
                &rt.hops,
×
578
        )
×
579

×
580
        _, err := lnwire.DecodeRecords(r, records...)
×
581
        if err != nil {
×
582
                return nil, err
×
583
        }
×
584

585
        return &rt, nil
×
586
}
587

588
// deserializeNewHop deserializes the mcHop from the given io.Reader.
589
func deserializeNewHop(r io.Reader) (*mcHop, error) {
×
590
        var (
×
591
                h        mcHop
×
592
                blinding = tlv.ZeroRecordT[tlv.TlvType3, lnwire.TrueBoolean]()
×
593
                custom   = tlv.ZeroRecordT[tlv.TlvType4, lnwire.TrueBoolean]()
×
594
        )
×
595
        records := lnwire.ProduceRecordsSorted(
×
596
                &h.channelID,
×
597
                &h.pubKeyBytes,
×
598
                &h.amtToFwd,
×
599
                &blinding,
×
600
                &custom,
×
601
        )
×
602

×
603
        typeMap, err := lnwire.DecodeRecords(r, records...)
×
604
        if err != nil {
×
605
                return nil, err
×
606
        }
×
607

608
        if _, ok := typeMap[h.hasBlindingPoint.TlvType()]; ok {
×
609
                h.hasBlindingPoint = tlv.SomeRecordT(blinding)
×
610
        }
×
611

612
        if _, ok := typeMap[h.hasCustomRecords.TlvType()]; ok {
×
613
                h.hasCustomRecords = tlv.SomeRecordT(custom)
×
614
        }
×
615

616
        return &h, nil
×
617
}
618

619
// serializeNewHop serializes a mcHop and writes the resulting bytes to the
620
// given io.Writer.
UNCOV
621
func serializeNewHop(w io.Writer, h *mcHop) error {
×
UNCOV
622
        recordProducers := []tlv.RecordProducer{
×
UNCOV
623
                &h.channelID,
×
UNCOV
624
                &h.pubKeyBytes,
×
UNCOV
625
                &h.amtToFwd,
×
UNCOV
626
        }
×
UNCOV
627

×
UNCOV
628
        h.hasBlindingPoint.WhenSome(func(
×
UNCOV
629
                hasBlinding tlv.RecordT[tlv.TlvType3, lnwire.TrueBoolean]) {
×
UNCOV
630

×
UNCOV
631
                recordProducers = append(recordProducers, &hasBlinding)
×
UNCOV
632
        })
×
633

UNCOV
634
        h.hasCustomRecords.WhenSome(func(
×
UNCOV
635
                hasCustom tlv.RecordT[tlv.TlvType4, lnwire.TrueBoolean]) {
×
UNCOV
636

×
UNCOV
637
                recordProducers = append(recordProducers, &hasCustom)
×
UNCOV
638
        })
×
639

UNCOV
640
        return lnwire.EncodeRecordsTo(
×
UNCOV
641
                w, lnwire.ProduceRecordsSorted(recordProducers...),
×
UNCOV
642
        )
×
643
}
644

645
// mcHop holds the bare minimum info about a payment attempt route hop that MC
646
// requires.
647
type mcHop struct {
648
        channelID        tlv.RecordT[tlv.TlvType0, uint64]
649
        pubKeyBytes      tlv.RecordT[tlv.TlvType1, Vertex]
650
        amtToFwd         tlv.RecordT[tlv.TlvType2, lnwire.MilliSatoshi]
651
        hasBlindingPoint tlv.OptionalRecordT[tlv.TlvType3, lnwire.TrueBoolean]
652
        hasCustomRecords tlv.OptionalRecordT[tlv.TlvType4, lnwire.TrueBoolean]
653
}
654

655
// serializeOldResult serializes a payment result and returns a key and value
656
// byte slice to insert into the bucket.
UNCOV
657
func serializeOldResult(rp *paymentResultOld) ([]byte, []byte, error) {
×
UNCOV
658
        // Write timestamps, success status, failure source index and route.
×
UNCOV
659
        var b bytes.Buffer
×
UNCOV
660
        var dbFailureSourceIdx int32
×
UNCOV
661
        if rp.failureSourceIdx == nil {
×
UNCOV
662
                dbFailureSourceIdx = unknownFailureSourceIdx
×
UNCOV
663
        } else {
×
UNCOV
664
                dbFailureSourceIdx = int32(*rp.failureSourceIdx)
×
UNCOV
665
        }
×
UNCOV
666
        err := WriteElements(
×
UNCOV
667
                &b,
×
UNCOV
668
                uint64(rp.timeFwd.UnixNano()),
×
UNCOV
669
                uint64(rp.timeReply.UnixNano()),
×
UNCOV
670
                rp.success, dbFailureSourceIdx,
×
UNCOV
671
        )
×
UNCOV
672
        if err != nil {
×
673
                return nil, nil, err
×
674
        }
×
675

UNCOV
676
        if err := SerializeRoute(&b, *rp.route); err != nil {
×
677
                return nil, nil, err
×
678
        }
×
679

680
        // Write failure. If there is no failure message, write an empty
681
        // byte slice.
UNCOV
682
        var failureBytes bytes.Buffer
×
UNCOV
683
        if rp.failure != nil {
×
UNCOV
684
                err := lnwire.EncodeFailureMessage(&failureBytes, rp.failure, 0)
×
UNCOV
685
                if err != nil {
×
686
                        return nil, nil, err
×
687
                }
×
688
        }
UNCOV
689
        err = wire.WriteVarBytes(&b, 0, failureBytes.Bytes())
×
UNCOV
690
        if err != nil {
×
691
                return nil, nil, err
×
692
        }
×
693
        // Compose key that identifies this result.
UNCOV
694
        key := getResultKeyOld(rp)
×
UNCOV
695

×
UNCOV
696
        return key, b.Bytes(), nil
×
697
}
698

699
// getResultKeyOld returns a byte slice representing a unique key for this
700
// payment result.
UNCOV
701
func getResultKeyOld(rp *paymentResultOld) []byte {
×
UNCOV
702
        var keyBytes [8 + 8 + 33]byte
×
UNCOV
703

×
UNCOV
704
        // Identify records by a combination of time, payment id and sender pub
×
UNCOV
705
        // key. This allows importing mission control data from an external
×
UNCOV
706
        // source without key collisions and keeps the records sorted
×
UNCOV
707
        // chronologically.
×
UNCOV
708
        byteOrder.PutUint64(keyBytes[:], uint64(rp.timeReply.UnixNano()))
×
UNCOV
709
        byteOrder.PutUint64(keyBytes[8:], rp.id)
×
UNCOV
710
        copy(keyBytes[16:], rp.route.SourcePubKey[:])
×
UNCOV
711

×
UNCOV
712
        return keyBytes[:]
×
UNCOV
713
}
×
714

715
// serializeNewResult serializes a payment result and returns a key and value
716
// byte slice to insert into the bucket.
UNCOV
717
func serializeNewResult(rp *paymentResultNew) ([]byte, []byte, error) {
×
UNCOV
718
        recordProducers := []tlv.RecordProducer{
×
UNCOV
719
                &rp.timeFwd,
×
UNCOV
720
                &rp.timeReply,
×
UNCOV
721
                &rp.route,
×
UNCOV
722
        }
×
UNCOV
723

×
UNCOV
724
        rp.failure.WhenSome(
×
UNCOV
725
                func(failure tlv.RecordT[tlv.TlvType3, paymentFailure]) {
×
UNCOV
726
                        recordProducers = append(recordProducers, &failure)
×
UNCOV
727
                },
×
728
        )
729

730
        // Compose key that identifies this result.
UNCOV
731
        key := getResultKeyNew(rp)
×
UNCOV
732

×
UNCOV
733
        var buff bytes.Buffer
×
UNCOV
734
        err := lnwire.EncodeRecordsTo(
×
UNCOV
735
                &buff, lnwire.ProduceRecordsSorted(recordProducers...),
×
UNCOV
736
        )
×
UNCOV
737
        if err != nil {
×
738
                return nil, nil, err
×
739
        }
×
740

UNCOV
741
        return key, buff.Bytes(), err
×
742
}
743

744
// getResultKeyNew returns a byte slice representing a unique key for this
745
// payment result.
UNCOV
746
func getResultKeyNew(rp *paymentResultNew) []byte {
×
UNCOV
747
        var keyBytes [8 + 8 + 33]byte
×
UNCOV
748

×
UNCOV
749
        // Identify records by a combination of time, payment id and sender pub
×
UNCOV
750
        // key. This allows importing mission control data from an external
×
UNCOV
751
        // source without key collisions and keeps the records sorted
×
UNCOV
752
        // chronologically.
×
UNCOV
753
        byteOrder.PutUint64(keyBytes[:], rp.timeReply.Val)
×
UNCOV
754
        byteOrder.PutUint64(keyBytes[8:], rp.id)
×
UNCOV
755
        copy(keyBytes[16:], rp.route.Val.sourcePubKey.Val[:])
×
UNCOV
756

×
UNCOV
757
        return keyBytes[:]
×
UNCOV
758
}
×
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