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

lightningnetwork / lnd / 15561477203

10 Jun 2025 01:54PM UTC coverage: 58.351% (-10.1%) from 68.487%
15561477203

Pull #9356

github

web-flow
Merge 6440b25db into c6d6d4c0b
Pull Request #9356: lnrpc: add incoming/outgoing channel ids filter to forwarding history request

33 of 36 new or added lines in 2 files covered. (91.67%)

28366 existing lines in 455 files now uncovered.

97715 of 167461 relevant lines covered (58.35%)

1.81 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 fn.Option[paymentFailure]
×
UNCOV
97
        if !old.success {
×
UNCOV
98
                failure = fn.Some(newPaymentFailure(
×
UNCOV
99
                        old.failureSourceIdx,
×
UNCOV
100
                        old.failure,
×
UNCOV
101
                ))
×
UNCOV
102
        }
×
103

UNCOV
104
        return newPaymentResult(
×
UNCOV
105
                old.id, extractMCRoute(old.route), old.timeFwd, old.timeReply,
×
UNCOV
106
                failure,
×
UNCOV
107
        )
×
108
}
109

110
// newPaymentResult constructs a new paymentResult.
111
func newPaymentResult(id uint64, rt *mcRoute, timeFwd, timeReply time.Time,
UNCOV
112
        failure fn.Option[paymentFailure]) *paymentResultNew {
×
UNCOV
113

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

×
UNCOV
125
        failure.WhenSome(func(f paymentFailure) {
×
UNCOV
126
                result.failure = tlv.SomeRecordT(
×
UNCOV
127
                        tlv.NewRecordT[tlv.TlvType3](f),
×
UNCOV
128
                )
×
UNCOV
129
        })
×
130

UNCOV
131
        return result
×
132
}
133

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

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

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

×
UNCOV
155
        // If we can't identify a failure source, we also won't have a decrypted
×
UNCOV
156
        // failure message. In this case we return an empty payment failure.
×
UNCOV
157
        if sourceIdx == nil {
×
158
                return paymentFailure{}
×
159
        }
×
160

UNCOV
161
        info := paymentFailure{
×
UNCOV
162
                sourceIdx: tlv.SomeRecordT(
×
UNCOV
163
                        tlv.NewPrimitiveRecord[tlv.TlvType0](
×
UNCOV
164
                                uint8(*sourceIdx),
×
UNCOV
165
                        ),
×
UNCOV
166
                ),
×
UNCOV
167
        }
×
UNCOV
168

×
UNCOV
169
        if failureMsg != nil {
×
UNCOV
170
                info.msg = tlv.SomeRecordT(
×
UNCOV
171
                        tlv.NewRecordT[tlv.TlvType1](
×
UNCOV
172
                                failureMessage{failureMsg},
×
UNCOV
173
                        ),
×
UNCOV
174
                )
×
UNCOV
175
        }
×
176

UNCOV
177
        return info
×
178
}
179

180
// paymentFailure holds additional information about a payment failure.
181
type paymentFailure struct {
182
        // sourceIdx is the hop the error was reported from. In order to be able
183
        // to decrypt the error message, we need to know the source, which is
184
        // why an error message can only be present if the source is known.
185
        sourceIdx tlv.OptionalRecordT[tlv.TlvType0, uint8]
186

187
        // msg is the error why a payment failed. If we identify the failure of
188
        // a certain hop at the above index, but aren't able to decode the
189
        // failure message we indicate this by not setting this field.
190
        msg tlv.OptionalRecordT[tlv.TlvType1, failureMessage]
191
}
192

193
// Record returns a TLV record that can be used to encode/decode a
194
// paymentFailure to/from a TLV stream.
UNCOV
195
func (r *paymentFailure) Record() tlv.Record {
×
UNCOV
196
        recordSize := func() uint64 {
×
UNCOV
197
                var (
×
UNCOV
198
                        b   bytes.Buffer
×
UNCOV
199
                        buf [8]byte
×
UNCOV
200
                )
×
UNCOV
201
                if err := encodePaymentFailure(&b, r, &buf); err != nil {
×
202
                        panic(err)
×
203
                }
204

UNCOV
205
                return uint64(len(b.Bytes()))
×
206
        }
207

UNCOV
208
        return tlv.MakeDynamicRecord(
×
UNCOV
209
                0, r, recordSize, encodePaymentFailure, decodePaymentFailure,
×
UNCOV
210
        )
×
211
}
212

UNCOV
213
func encodePaymentFailure(w io.Writer, val interface{}, _ *[8]byte) error {
×
UNCOV
214
        if v, ok := val.(*paymentFailure); ok {
×
UNCOV
215
                var recordProducers []tlv.RecordProducer
×
UNCOV
216

×
UNCOV
217
                v.sourceIdx.WhenSome(
×
UNCOV
218
                        func(r tlv.RecordT[tlv.TlvType0, uint8]) {
×
UNCOV
219
                                recordProducers = append(
×
UNCOV
220
                                        recordProducers, &r,
×
UNCOV
221
                                )
×
UNCOV
222
                        },
×
223
                )
224

UNCOV
225
                v.msg.WhenSome(
×
UNCOV
226
                        func(r tlv.RecordT[tlv.TlvType1, failureMessage]) {
×
UNCOV
227
                                recordProducers = append(
×
UNCOV
228
                                        recordProducers, &r,
×
UNCOV
229
                                )
×
UNCOV
230
                        },
×
231
                )
232

UNCOV
233
                return lnwire.EncodeRecordsTo(
×
UNCOV
234
                        w, lnwire.ProduceRecordsSorted(
×
UNCOV
235
                                recordProducers...,
×
UNCOV
236
                        ),
×
UNCOV
237
                )
×
238
        }
239

240
        return tlv.NewTypeForEncodingErr(val, "routing.paymentFailure")
×
241
}
242

243
func decodePaymentFailure(r io.Reader, val interface{}, _ *[8]byte,
244
        l uint64) error {
×
245
        if v, ok := val.(*paymentFailure); ok {
×
246
                var h paymentFailure
×
247

×
248
                sourceIdx := tlv.ZeroRecordT[tlv.TlvType0, uint8]()
×
249
                msg := tlv.ZeroRecordT[tlv.TlvType1, failureMessage]()
×
250

×
251
                typeMap, err := lnwire.DecodeRecords(
×
252
                        r,
×
253
                        lnwire.ProduceRecordsSorted(&sourceIdx, &msg)...,
×
254
                )
×
255

×
256
                if err != nil {
×
257
                        return err
×
258
                }
×
259

260
                if _, ok := typeMap[h.sourceIdx.TlvType()]; ok {
×
261
                        h.sourceIdx = tlv.SomeRecordT(sourceIdx)
×
262
                }
×
263

264
                if _, ok := typeMap[h.msg.TlvType()]; ok {
×
265
                        h.msg = tlv.SomeRecordT(msg)
×
266
                }
×
267

268
                *v = h
×
269

×
270
                return nil
×
271
        }
272

273
        return tlv.NewTypeForDecodingErr(
×
274
                val, "routing.paymentFailure", l, l,
×
275
        )
×
276
}
277

278
type failureMessage struct {
279
        lnwire.FailureMessage
280
}
281

282
// Record returns a TLV record that can be used to encode/decode a list of
283
// failureMessage to/from a TLV stream.
UNCOV
284
func (r *failureMessage) Record() tlv.Record {
×
UNCOV
285
        recordSize := func() uint64 {
×
UNCOV
286
                var (
×
UNCOV
287
                        b   bytes.Buffer
×
UNCOV
288
                        buf [8]byte
×
UNCOV
289
                )
×
UNCOV
290
                if err := encodeFailureMessage(&b, r, &buf); err != nil {
×
291
                        panic(err)
×
292
                }
293

UNCOV
294
                return uint64(len(b.Bytes()))
×
295
        }
296

UNCOV
297
        return tlv.MakeDynamicRecord(
×
UNCOV
298
                0, r, recordSize, encodeFailureMessage, decodeFailureMessage,
×
UNCOV
299
        )
×
300
}
301

UNCOV
302
func encodeFailureMessage(w io.Writer, val interface{}, _ *[8]byte) error {
×
UNCOV
303
        if v, ok := val.(*failureMessage); ok {
×
UNCOV
304
                var b bytes.Buffer
×
UNCOV
305
                err := lnwire.EncodeFailureMessage(&b, v.FailureMessage, 0)
×
UNCOV
306
                if err != nil {
×
307
                        return err
×
308
                }
×
309

UNCOV
310
                _, err = w.Write(b.Bytes())
×
UNCOV
311

×
UNCOV
312
                return err
×
313
        }
314

315
        return tlv.NewTypeForEncodingErr(val, "routing.failureMessage")
×
316
}
317

318
func decodeFailureMessage(r io.Reader, val interface{}, _ *[8]byte,
319
        l uint64) error {
×
320

×
321
        if v, ok := val.(*failureMessage); ok {
×
322
                msg, err := lnwire.DecodeFailureMessage(r, 0)
×
323
                if err != nil {
×
324
                        return err
×
325
                }
×
326

327
                *v = failureMessage{
×
328
                        FailureMessage: msg,
×
329
                }
×
330

×
331
                return nil
×
332
        }
333

334
        return tlv.NewTypeForDecodingErr(val, "routing.failureMessage", l, l)
×
335
}
336

337
// extractMCRoute extracts the fields required by MC from the Route struct to
338
// create the more minimal mcRoute struct.
UNCOV
339
func extractMCRoute(r *Route) *mcRoute {
×
UNCOV
340
        return &mcRoute{
×
UNCOV
341
                sourcePubKey: tlv.NewRecordT[tlv.TlvType0](r.SourcePubKey),
×
UNCOV
342
                totalAmount:  tlv.NewRecordT[tlv.TlvType1](r.TotalAmount),
×
UNCOV
343
                hops: tlv.NewRecordT[tlv.TlvType2](
×
UNCOV
344
                        extractMCHops(r.Hops),
×
UNCOV
345
                ),
×
UNCOV
346
        }
×
UNCOV
347
}
×
348

349
// extractMCHops extracts the Hop fields that MC actually uses from a slice of
350
// Hops.
UNCOV
351
func extractMCHops(hops []*Hop) mcHops {
×
UNCOV
352
        return fn.Map(hops, extractMCHop)
×
UNCOV
353
}
×
354

355
// extractMCHop extracts the Hop fields that MC actually uses from a Hop.
UNCOV
356
func extractMCHop(hop *Hop) *mcHop {
×
UNCOV
357
        h := mcHop{
×
UNCOV
358
                channelID: tlv.NewPrimitiveRecord[tlv.TlvType0, uint64](
×
UNCOV
359
                        hop.ChannelID,
×
UNCOV
360
                ),
×
UNCOV
361
                pubKeyBytes: tlv.NewRecordT[tlv.TlvType1, Vertex](
×
UNCOV
362
                        hop.PubKeyBytes,
×
UNCOV
363
                ),
×
UNCOV
364
                amtToFwd: tlv.NewRecordT[tlv.TlvType2, lnwire.MilliSatoshi](
×
UNCOV
365
                        hop.AmtToForward,
×
UNCOV
366
                ),
×
UNCOV
367
        }
×
UNCOV
368

×
UNCOV
369
        if hop.BlindingPoint != nil {
×
UNCOV
370
                h.hasBlindingPoint = tlv.SomeRecordT(
×
UNCOV
371
                        tlv.NewRecordT[tlv.TlvType3, lnwire.TrueBoolean](
×
UNCOV
372
                                lnwire.TrueBoolean{},
×
UNCOV
373
                        ),
×
UNCOV
374
                )
×
UNCOV
375
        }
×
376

UNCOV
377
        if len(hop.CustomRecords) != 0 {
×
UNCOV
378
                h.hasCustomRecords = tlv.SomeRecordT(
×
UNCOV
379
                        tlv.NewRecordT[tlv.TlvType4, lnwire.TrueBoolean](
×
UNCOV
380
                                lnwire.TrueBoolean{},
×
UNCOV
381
                        ),
×
UNCOV
382
                )
×
UNCOV
383
        }
×
384

UNCOV
385
        return &h
×
386
}
387

388
// mcRoute holds the bare minimum info about a payment attempt route that MC
389
// requires.
390
type mcRoute struct {
391
        sourcePubKey tlv.RecordT[tlv.TlvType0, Vertex]
392
        totalAmount  tlv.RecordT[tlv.TlvType1, lnwire.MilliSatoshi]
393
        hops         tlv.RecordT[tlv.TlvType2, mcHops]
394
}
395

396
// Record returns a TLV record that can be used to encode/decode an mcRoute
397
// to/from a TLV stream.
UNCOV
398
func (r *mcRoute) Record() tlv.Record {
×
UNCOV
399
        recordSize := func() uint64 {
×
UNCOV
400
                var (
×
UNCOV
401
                        b   bytes.Buffer
×
UNCOV
402
                        buf [8]byte
×
UNCOV
403
                )
×
UNCOV
404
                if err := encodeMCRoute(&b, r, &buf); err != nil {
×
405
                        panic(err)
×
406
                }
407

UNCOV
408
                return uint64(len(b.Bytes()))
×
409
        }
410

UNCOV
411
        return tlv.MakeDynamicRecord(
×
UNCOV
412
                0, r, recordSize, encodeMCRoute, decodeMCRoute,
×
UNCOV
413
        )
×
414
}
415

UNCOV
416
func encodeMCRoute(w io.Writer, val interface{}, _ *[8]byte) error {
×
UNCOV
417
        if v, ok := val.(*mcRoute); ok {
×
UNCOV
418
                return serializeRoute(w, v)
×
UNCOV
419
        }
×
420

421
        return tlv.NewTypeForEncodingErr(val, "routing.mcRoute")
×
422
}
423

424
func decodeMCRoute(r io.Reader, val interface{}, _ *[8]byte, l uint64) error {
×
425
        if v, ok := val.(*mcRoute); ok {
×
426
                route, err := deserializeRoute(io.LimitReader(r, int64(l)))
×
427
                if err != nil {
×
428
                        return err
×
429
                }
×
430

431
                *v = *route
×
432

×
433
                return nil
×
434
        }
435

436
        return tlv.NewTypeForDecodingErr(val, "routing.mcRoute", l, l)
×
437
}
438

439
// mcHops is a list of mcHop records.
440
type mcHops []*mcHop
441

442
// Record returns a TLV record that can be used to encode/decode a list of
443
// mcHop to/from a TLV stream.
UNCOV
444
func (h *mcHops) Record() tlv.Record {
×
UNCOV
445
        recordSize := func() uint64 {
×
UNCOV
446
                var (
×
UNCOV
447
                        b   bytes.Buffer
×
UNCOV
448
                        buf [8]byte
×
UNCOV
449
                )
×
UNCOV
450
                if err := encodeMCHops(&b, h, &buf); err != nil {
×
451
                        panic(err)
×
452
                }
453

UNCOV
454
                return uint64(len(b.Bytes()))
×
455
        }
456

UNCOV
457
        return tlv.MakeDynamicRecord(
×
UNCOV
458
                0, h, recordSize, encodeMCHops, decodeMCHops,
×
UNCOV
459
        )
×
460
}
461

UNCOV
462
func encodeMCHops(w io.Writer, val interface{}, buf *[8]byte) error {
×
UNCOV
463
        if v, ok := val.(*mcHops); ok {
×
UNCOV
464
                // Encode the number of hops as a var int.
×
UNCOV
465
                if err := tlv.WriteVarInt(w, uint64(len(*v)), buf); err != nil {
×
466
                        return err
×
467
                }
×
468

469
                // With that written out, we'll now encode the entries
470
                // themselves as a sub-TLV record, which includes its _own_
471
                // inner length prefix.
UNCOV
472
                for _, hop := range *v {
×
UNCOV
473
                        var hopBytes bytes.Buffer
×
UNCOV
474
                        if err := serializeNewHop(&hopBytes, hop); err != nil {
×
475
                                return err
×
476
                        }
×
477

478
                        // We encode the record with a varint length followed by
479
                        // the _raw_ TLV bytes.
UNCOV
480
                        tlvLen := uint64(len(hopBytes.Bytes()))
×
UNCOV
481
                        if err := tlv.WriteVarInt(w, tlvLen, buf); err != nil {
×
482
                                return err
×
483
                        }
×
484

UNCOV
485
                        if _, err := w.Write(hopBytes.Bytes()); err != nil {
×
486
                                return err
×
487
                        }
×
488
                }
489

UNCOV
490
                return nil
×
491
        }
492

493
        return tlv.NewTypeForEncodingErr(val, "routing.mcHops")
×
494
}
495

496
func decodeMCHops(r io.Reader, val interface{}, buf *[8]byte, l uint64) error {
×
497
        if v, ok := val.(*mcHops); ok {
×
498
                // First, we'll decode the varint that encodes how many hops
×
499
                // are encoded in the stream.
×
500
                numHops, err := tlv.ReadVarInt(r, buf)
×
501
                if err != nil {
×
502
                        return err
×
503
                }
×
504

505
                // Now that we know how many records we'll need to read, we can
506
                // iterate and read them all out in series.
507
                for i := uint64(0); i < numHops; i++ {
×
508
                        // Read out the varint that encodes the size of this
×
509
                        // inner TLV record.
×
510
                        hopSize, err := tlv.ReadVarInt(r, buf)
×
511
                        if err != nil {
×
512
                                return err
×
513
                        }
×
514

515
                        // Using this information, we'll create a new limited
516
                        // reader that'll return an EOF once the end has been
517
                        // reached so the stream stops consuming bytes.
518
                        innerTlvReader := &io.LimitedReader{
×
519
                                R: r,
×
520
                                N: int64(hopSize),
×
521
                        }
×
522

×
523
                        hop, err := deserializeNewHop(innerTlvReader)
×
524
                        if err != nil {
×
525
                                return err
×
526
                        }
×
527

528
                        *v = append(*v, hop)
×
529
                }
530

531
                return nil
×
532
        }
533

534
        return tlv.NewTypeForDecodingErr(val, "routing.mcHops", l, l)
×
535
}
536

537
// serializeRoute serializes a mcRoute and writes the resulting bytes to the
538
// given io.Writer.
UNCOV
539
func serializeRoute(w io.Writer, r *mcRoute) error {
×
UNCOV
540
        records := lnwire.ProduceRecordsSorted(
×
UNCOV
541
                &r.sourcePubKey,
×
UNCOV
542
                &r.totalAmount,
×
UNCOV
543
                &r.hops,
×
UNCOV
544
        )
×
UNCOV
545

×
UNCOV
546
        return lnwire.EncodeRecordsTo(w, records)
×
UNCOV
547
}
×
548

549
// deserializeRoute deserializes the mcRoute from the given io.Reader.
550
func deserializeRoute(r io.Reader) (*mcRoute, error) {
×
551
        var rt mcRoute
×
552
        records := lnwire.ProduceRecordsSorted(
×
553
                &rt.sourcePubKey,
×
554
                &rt.totalAmount,
×
555
                &rt.hops,
×
556
        )
×
557

×
558
        _, err := lnwire.DecodeRecords(r, records...)
×
559
        if err != nil {
×
560
                return nil, err
×
561
        }
×
562

563
        return &rt, nil
×
564
}
565

566
// deserializeNewHop deserializes the mcHop from the given io.Reader.
567
func deserializeNewHop(r io.Reader) (*mcHop, error) {
×
568
        var (
×
569
                h        mcHop
×
570
                blinding = tlv.ZeroRecordT[tlv.TlvType3, lnwire.TrueBoolean]()
×
571
                custom   = tlv.ZeroRecordT[tlv.TlvType4, lnwire.TrueBoolean]()
×
572
        )
×
573
        records := lnwire.ProduceRecordsSorted(
×
574
                &h.channelID,
×
575
                &h.pubKeyBytes,
×
576
                &h.amtToFwd,
×
577
                &blinding,
×
578
                &custom,
×
579
        )
×
580

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

586
        if _, ok := typeMap[h.hasBlindingPoint.TlvType()]; ok {
×
587
                h.hasBlindingPoint = tlv.SomeRecordT(blinding)
×
588
        }
×
589

590
        if _, ok := typeMap[h.hasCustomRecords.TlvType()]; ok {
×
591
                h.hasCustomRecords = tlv.SomeRecordT(custom)
×
592
        }
×
593

594
        return &h, nil
×
595
}
596

597
// serializeNewHop serializes a mcHop and writes the resulting bytes to the
598
// given io.Writer.
UNCOV
599
func serializeNewHop(w io.Writer, h *mcHop) error {
×
UNCOV
600
        recordProducers := []tlv.RecordProducer{
×
UNCOV
601
                &h.channelID,
×
UNCOV
602
                &h.pubKeyBytes,
×
UNCOV
603
                &h.amtToFwd,
×
UNCOV
604
        }
×
UNCOV
605

×
UNCOV
606
        h.hasBlindingPoint.WhenSome(func(
×
UNCOV
607
                hasBlinding tlv.RecordT[tlv.TlvType3, lnwire.TrueBoolean]) {
×
UNCOV
608

×
UNCOV
609
                recordProducers = append(recordProducers, &hasBlinding)
×
UNCOV
610
        })
×
611

UNCOV
612
        h.hasCustomRecords.WhenSome(func(
×
UNCOV
613
                hasCustom tlv.RecordT[tlv.TlvType4, lnwire.TrueBoolean]) {
×
UNCOV
614

×
UNCOV
615
                recordProducers = append(recordProducers, &hasCustom)
×
UNCOV
616
        })
×
617

UNCOV
618
        return lnwire.EncodeRecordsTo(
×
UNCOV
619
                w, lnwire.ProduceRecordsSorted(recordProducers...),
×
UNCOV
620
        )
×
621
}
622

623
// mcHop holds the bare minimum info about a payment attempt route hop that MC
624
// requires.
625
type mcHop struct {
626
        channelID        tlv.RecordT[tlv.TlvType0, uint64]
627
        pubKeyBytes      tlv.RecordT[tlv.TlvType1, Vertex]
628
        amtToFwd         tlv.RecordT[tlv.TlvType2, lnwire.MilliSatoshi]
629
        hasBlindingPoint tlv.OptionalRecordT[tlv.TlvType3, lnwire.TrueBoolean]
630
        hasCustomRecords tlv.OptionalRecordT[tlv.TlvType4, lnwire.TrueBoolean]
631
}
632

633
// serializeOldResult serializes a payment result and returns a key and value
634
// byte slice to insert into the bucket.
UNCOV
635
func serializeOldResult(rp *paymentResultOld) ([]byte, []byte, error) {
×
UNCOV
636
        // Write timestamps, success status, failure source index and route.
×
UNCOV
637
        var b bytes.Buffer
×
UNCOV
638
        var dbFailureSourceIdx int32
×
UNCOV
639
        if rp.failureSourceIdx == nil {
×
UNCOV
640
                dbFailureSourceIdx = unknownFailureSourceIdx
×
UNCOV
641
        } else {
×
UNCOV
642
                dbFailureSourceIdx = int32(*rp.failureSourceIdx)
×
UNCOV
643
        }
×
UNCOV
644
        err := WriteElements(
×
UNCOV
645
                &b,
×
UNCOV
646
                uint64(rp.timeFwd.UnixNano()),
×
UNCOV
647
                uint64(rp.timeReply.UnixNano()),
×
UNCOV
648
                rp.success, dbFailureSourceIdx,
×
UNCOV
649
        )
×
UNCOV
650
        if err != nil {
×
651
                return nil, nil, err
×
652
        }
×
653

UNCOV
654
        if err := SerializeRoute(&b, *rp.route); err != nil {
×
655
                return nil, nil, err
×
656
        }
×
657

658
        // Write failure. If there is no failure message, write an empty
659
        // byte slice.
UNCOV
660
        var failureBytes bytes.Buffer
×
UNCOV
661
        if rp.failure != nil {
×
UNCOV
662
                err := lnwire.EncodeFailureMessage(&failureBytes, rp.failure, 0)
×
UNCOV
663
                if err != nil {
×
664
                        return nil, nil, err
×
665
                }
×
666
        }
UNCOV
667
        err = wire.WriteVarBytes(&b, 0, failureBytes.Bytes())
×
UNCOV
668
        if err != nil {
×
669
                return nil, nil, err
×
670
        }
×
671
        // Compose key that identifies this result.
UNCOV
672
        key := getResultKeyOld(rp)
×
UNCOV
673

×
UNCOV
674
        return key, b.Bytes(), nil
×
675
}
676

677
// getResultKeyOld returns a byte slice representing a unique key for this
678
// payment result.
UNCOV
679
func getResultKeyOld(rp *paymentResultOld) []byte {
×
UNCOV
680
        var keyBytes [8 + 8 + 33]byte
×
UNCOV
681

×
UNCOV
682
        // Identify records by a combination of time, payment id and sender pub
×
UNCOV
683
        // key. This allows importing mission control data from an external
×
UNCOV
684
        // source without key collisions and keeps the records sorted
×
UNCOV
685
        // chronologically.
×
UNCOV
686
        byteOrder.PutUint64(keyBytes[:], uint64(rp.timeReply.UnixNano()))
×
UNCOV
687
        byteOrder.PutUint64(keyBytes[8:], rp.id)
×
UNCOV
688
        copy(keyBytes[16:], rp.route.SourcePubKey[:])
×
UNCOV
689

×
UNCOV
690
        return keyBytes[:]
×
UNCOV
691
}
×
692

693
// serializeNewResult serializes a payment result and returns a key and value
694
// byte slice to insert into the bucket.
UNCOV
695
func serializeNewResult(rp *paymentResultNew) ([]byte, []byte, error) {
×
UNCOV
696
        recordProducers := []tlv.RecordProducer{
×
UNCOV
697
                &rp.timeFwd,
×
UNCOV
698
                &rp.timeReply,
×
UNCOV
699
                &rp.route,
×
UNCOV
700
        }
×
UNCOV
701

×
UNCOV
702
        rp.failure.WhenSome(
×
UNCOV
703
                func(failure tlv.RecordT[tlv.TlvType3, paymentFailure]) {
×
UNCOV
704
                        recordProducers = append(recordProducers, &failure)
×
UNCOV
705
                },
×
706
        )
707

708
        // Compose key that identifies this result.
UNCOV
709
        key := getResultKeyNew(rp)
×
UNCOV
710

×
UNCOV
711
        var buff bytes.Buffer
×
UNCOV
712
        err := lnwire.EncodeRecordsTo(
×
UNCOV
713
                &buff, lnwire.ProduceRecordsSorted(recordProducers...),
×
UNCOV
714
        )
×
UNCOV
715
        if err != nil {
×
716
                return nil, nil, err
×
717
        }
×
718

UNCOV
719
        return key, buff.Bytes(), nil
×
720
}
721

722
// getResultKeyNew returns a byte slice representing a unique key for this
723
// payment result.
UNCOV
724
func getResultKeyNew(rp *paymentResultNew) []byte {
×
UNCOV
725
        var keyBytes [8 + 8 + 33]byte
×
UNCOV
726

×
UNCOV
727
        // Identify records by a combination of time, payment id and sender pub
×
UNCOV
728
        // key. This allows importing mission control data from an external
×
UNCOV
729
        // source without key collisions and keeps the records sorted
×
UNCOV
730
        // chronologically.
×
UNCOV
731
        byteOrder.PutUint64(keyBytes[:], rp.timeReply.Val)
×
UNCOV
732
        byteOrder.PutUint64(keyBytes[8:], rp.id)
×
UNCOV
733
        copy(keyBytes[16:], rp.route.Val.sourcePubKey.Val[:])
×
UNCOV
734

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