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

lightningnetwork / lnd / 14779943269

01 May 2025 05:22PM UTC coverage: 69.041% (+0.009%) from 69.032%
14779943269

Pull #9752

github

web-flow
Merge 51b1059cc into b068d79df
Pull Request #9752: routerrpc: reject payment to invoice that don't have payment secret or blinded paths

5 of 6 new or added lines in 1 file covered. (83.33%)

241 existing lines in 16 files now uncovered.

133931 of 193989 relevant lines covered (69.04%)

22108.46 hits per line

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

67.58
/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.
39
func deserializeOldResult(k, v []byte) (*paymentResultOld, error) {
3✔
40
        // Parse payment id.
3✔
41
        result := paymentResultOld{
3✔
42
                id: byteOrder.Uint64(k[8:]),
3✔
43
        }
3✔
44

3✔
45
        r := bytes.NewReader(v)
3✔
46

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

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

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

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

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

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

91
        return &result, nil
3✔
92
}
93

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

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

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

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

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

2✔
128
        return result
2✔
129
}
2✔
130

131
// paymentResultNew is the information that becomes available when a payment
3✔
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
4✔
154
// used to populate the info field of the paymentFailure.
4✔
155
func newPaymentFailure(sourceIdx *int,
4✔
156
        failureMsg lnwire.FailureMessage) *paymentFailure {
4✔
157

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

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

4✔
169
        return &paymentFailure{
6✔
170
                info: tlv.SomeRecordT(tlv.NewRecordT[tlv.TlvType0](info)),
2✔
171
        }
2✔
172
}
2✔
173

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

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

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

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

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

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

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

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

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

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

4✔
229
                *v = h
4✔
230

4✔
231
                return nil
232
        }
233

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

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

243
// Record returns a TLV record that can be used to encode/decode a
UNCOV
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)
×
UNCOV
253
                }
×
UNCOV
254

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

×
UNCOV
258
        return tlv.MakeDynamicRecord(
×
259
                0, r, recordSize, encodePaymentFailureInfo,
UNCOV
260
                decodePaymentFailureInfo,
×
UNCOV
261
        )
×
UNCOV
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(
×
267
                        w, lnwire.ProduceRecordsSorted(
UNCOV
268
                                &v.sourceIdx, &v.msg,
×
UNCOV
269
                        ),
×
UNCOV
270
                )
×
271
        }
272

273
        return tlv.NewTypeForEncodingErr(val, "routing.paymentFailureInfo")
×
UNCOV
274
}
×
UNCOV
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)...,
4✔
285
                )
8✔
286
                if err != nil {
4✔
287
                        return err
4✔
288
                }
4✔
289

4✔
290
                *v = h
4✔
291

×
292
                return nil
293
        }
294

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

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

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

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

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

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

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

UNCOV
334
                return err
×
335
        }
336

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

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

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

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

3✔
353
                return nil
3✔
354
        }
355

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

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

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

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

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

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

407
        return &h
408
}
6✔
409

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

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

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

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

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

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

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

453
                *v = *route
454

12✔
455
                return nil
456
        }
457

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

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

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

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

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

×
484
func encodeMCHops(w io.Writer, val interface{}, buf *[8]byte) error {
485
        if v, ok := val.(*mcHops); ok {
48✔
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

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

×
UNCOV
500
                        // We encode the record with a varint length followed by
×
UNCOV
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
                        }
×
UNCOV
510
                }
×
UNCOV
511

×
UNCOV
512
                return nil
×
UNCOV
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
                }
×
UNCOV
526

×
527
                // Now that we know how many records we'll need to read, we can
UNCOV
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.
12✔
540
                        innerTlvReader := &io.LimitedReader{
12✔
541
                                R: r,
12✔
542
                                N: int64(hopSize),
12✔
543
                        }
12✔
544

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

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

×
553
                return nil
×
UNCOV
554
        }
×
UNCOV
555

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

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

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

×
UNCOV
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
        }
×
UNCOV
584

×
585
        return &rt, nil
UNCOV
586
}
×
UNCOV
587

×
UNCOV
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,
48✔
600
                &custom,
48✔
601
        )
48✔
602

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

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

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

32✔
616
        return &h, nil
32✔
617
}
618

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

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

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

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

3✔
637
                recordProducers = append(recordProducers, &hasCustom)
3✔
638
        })
3✔
639

4✔
640
        return lnwire.EncodeRecordsTo(
1✔
641
                w, lnwire.ProduceRecordsSorted(recordProducers...),
3✔
642
        )
2✔
643
}
2✔
644

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

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

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

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

6✔
696
        return key, b.Bytes(), nil
6✔
697
}
6✔
698

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

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

6✔
712
        return keyBytes[:]
6✔
713
}
6✔
714

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

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

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

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

741
        return key, buff.Bytes(), nil
742
}
743

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

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

757
        return keyBytes[:]
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