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

lightningnetwork / lnd / 11393106485

17 Oct 2024 09:10PM UTC coverage: 57.848% (-1.0%) from 58.81%
11393106485

Pull #9148

github

ProofOfKeags
lnwire: convert DynPropose and DynCommit to use typed tlv records
Pull Request #9148: DynComms [2/n]: lnwire: add authenticated wire messages for Dyn*

142 of 177 new or added lines in 4 files covered. (80.23%)

18983 existing lines in 242 files now uncovered.

99003 of 171143 relevant lines covered (57.85%)

36968.25 hits per line

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

80.1
/contractcourt/taproot_briefcase.go
1
package contractcourt
2

3
import (
4
        "bytes"
5
        "io"
6

7
        "github.com/lightningnetwork/lnd/tlv"
8
)
9

10
const (
11
        commitCtrlBlockType       tlv.Type = 0
12
        revokeCtrlBlockType       tlv.Type = 1
13
        outgoingHtlcCtrlBlockType tlv.Type = 2
14
        incomingHtlcCtrlBlockType tlv.Type = 3
15
        secondLevelCtrlBlockType  tlv.Type = 4
16

17
        anchorTapTweakType                tlv.Type = 0
18
        htlcTweakCtrlBlockType            tlv.Type = 1
19
        secondLevelHtlcTweakCtrlBlockType tlv.Type = 2
20
)
21

22
// taprootBriefcase is a supplemental storage struct that contains all the
23
// information we need to sweep taproot outputs.
24
type taprootBriefcase struct {
25
        // CtrlBlock is the set of control block for the taproot outputs.
26
        CtrlBlocks tlv.RecordT[tlv.TlvType0, ctrlBlocks]
27

28
        // TapTweaks is the set of taproot tweaks for the taproot outputs that
29
        // are to be spent via a keyspend path. This includes anchors, and any
30
        // revocation paths.
31
        TapTweaks tlv.RecordT[tlv.TlvType1, tapTweaks]
32

33
        // SettledCommitBlob is an optional record that contains an opaque blob
34
        // that may be used to properly sweep commitment outputs on a force
35
        // close transaction.
36
        SettledCommitBlob tlv.OptionalRecordT[tlv.TlvType2, tlv.Blob]
37

38
        // BreachCommitBlob is an optional record that contains an opaque blob
39
        // used to sweep a remote party's breached output.
40
        BreachedCommitBlob tlv.OptionalRecordT[tlv.TlvType3, tlv.Blob]
41

42
        // TODO(roasbeef): htlc blobs
43
}
44

45
// TODO(roasbeef): morph into new tlv record
46

47
// newTaprootBriefcase returns a new instance of the taproot specific briefcase
48
// variant.
UNCOV
49
func newTaprootBriefcase() *taprootBriefcase {
×
UNCOV
50
        return &taprootBriefcase{
×
UNCOV
51
                CtrlBlocks: tlv.NewRecordT[tlv.TlvType0](newCtrlBlocks()),
×
UNCOV
52
                TapTweaks:  tlv.NewRecordT[tlv.TlvType1](newTapTweaks()),
×
UNCOV
53
        }
×
UNCOV
54
}
×
55

56
// EncodeRecords returns a slice of TLV records that should be encoded.
57
func (t *taprootBriefcase) EncodeRecords() []tlv.Record {
1✔
58
        records := []tlv.Record{
1✔
59
                t.CtrlBlocks.Record(),
1✔
60
                t.TapTweaks.Record(),
1✔
61
        }
1✔
62

1✔
63
        t.SettledCommitBlob.WhenSome(
1✔
64
                func(r tlv.RecordT[tlv.TlvType2, tlv.Blob]) {
2✔
65
                        records = append(records, r.Record())
1✔
66
                },
1✔
67
        )
68
        t.BreachedCommitBlob.WhenSome(
1✔
69
                func(r tlv.RecordT[tlv.TlvType3, tlv.Blob]) {
2✔
70
                        records = append(records, r.Record())
1✔
71
                },
1✔
72
        )
73

74
        return records
1✔
75
}
76

77
// DecodeRecords returns a slice of TLV records that should be decoded.
78
func (t *taprootBriefcase) DecodeRecords() []tlv.Record {
1✔
79
        return []tlv.Record{
1✔
80
                t.CtrlBlocks.Record(),
1✔
81
                t.TapTweaks.Record(),
1✔
82
        }
1✔
83
}
1✔
84

85
// Encode records returns a slice of TLV records that should be encoded.
86
func (t *taprootBriefcase) Encode(w io.Writer) error {
1✔
87
        stream, err := tlv.NewStream(t.EncodeRecords()...)
1✔
88
        if err != nil {
1✔
89
                return err
×
90
        }
×
91

92
        return stream.Encode(w)
1✔
93
}
94

95
// Decode decodes the given reader into the target struct.
96
func (t *taprootBriefcase) Decode(r io.Reader) error {
1✔
97
        settledCommitBlob := t.SettledCommitBlob.Zero()
1✔
98
        breachedCommitBlob := t.BreachedCommitBlob.Zero()
1✔
99
        records := append(
1✔
100
                t.DecodeRecords(),
1✔
101
                settledCommitBlob.Record(),
1✔
102
                breachedCommitBlob.Record(),
1✔
103
        )
1✔
104
        stream, err := tlv.NewStream(records...)
1✔
105
        if err != nil {
1✔
106
                return err
×
107
        }
×
108

109
        typeMap, err := stream.DecodeWithParsedTypes(r)
1✔
110
        if err != nil {
1✔
111
                return err
×
112
        }
×
113

114
        if val, ok := typeMap[t.SettledCommitBlob.TlvType()]; ok && val == nil {
2✔
115
                t.SettledCommitBlob = tlv.SomeRecordT(settledCommitBlob)
1✔
116
        }
1✔
117
        if v, ok := typeMap[t.BreachedCommitBlob.TlvType()]; ok && v == nil {
2✔
118
                t.BreachedCommitBlob = tlv.SomeRecordT(breachedCommitBlob)
1✔
119
        }
1✔
120

121
        return nil
1✔
122
}
123

124
// resolverCtrlBlocks is a map of resolver IDs to their corresponding control
125
// block.
126
type resolverCtrlBlocks map[resolverID][]byte
127

128
// newResolverCtrlBlockss returns a new instance of the resolverCtrlBlocks.
129
func newResolverCtrlBlocks() resolverCtrlBlocks {
3✔
130
        return make(resolverCtrlBlocks)
3✔
131
}
3✔
132

133
// recordSize returns the size of the record in bytes.
134
func (r *resolverCtrlBlocks) recordSize() uint64 {
6✔
135
        // Each record will be serialized as: <num_total_records> || <record>,
6✔
136
        // where <record> is serialized as: <resolver_key> || <length> ||
6✔
137
        // <ctrl_block>.
6✔
138
        numBlocks := uint64(len(*r))
6✔
139
        baseSize := tlv.VarIntSize(numBlocks)
6✔
140

6✔
141
        recordSize := baseSize
6✔
142
        for _, ctrlBlock := range *r {
540✔
143
                recordSize += resolverIDLen
534✔
144
                recordSize += tlv.VarIntSize(uint64(len(ctrlBlock)))
534✔
145
                recordSize += uint64(len(ctrlBlock))
534✔
146
        }
534✔
147

148
        return recordSize
6✔
149
}
150

151
// Encode encodes the control blocks into the target writer.
152
func (r *resolverCtrlBlocks) Encode(w io.Writer) error {
6✔
153
        numBlocks := uint64(len(*r))
6✔
154

6✔
155
        var buf [8]byte
6✔
156
        if err := tlv.WriteVarInt(w, numBlocks, &buf); err != nil {
6✔
157
                return err
×
158
        }
×
159

160
        for id, ctrlBlock := range *r {
540✔
161
                ctrlBlock := ctrlBlock
534✔
162

534✔
163
                if _, err := w.Write(id[:]); err != nil {
534✔
164
                        return err
×
165
                }
×
166

167
                if err := varBytesEncoder(w, &ctrlBlock, &buf); err != nil {
534✔
168
                        return err
×
169
                }
×
170
        }
171

172
        return nil
6✔
173
}
174

175
// Decode decodes the given reader into the target struct.
176
func (r *resolverCtrlBlocks) Decode(reader io.Reader) error {
3✔
177
        var buf [8]byte
3✔
178

3✔
179
        numBlocks, err := tlv.ReadVarInt(reader, &buf)
3✔
180
        if err != nil {
3✔
181
                return err
×
182
        }
×
183

184
        for i := uint64(0); i < numBlocks; i++ {
270✔
185
                var id resolverID
267✔
186
                if _, err := io.ReadFull(reader, id[:]); err != nil {
267✔
187
                        return err
×
188
                }
×
189

190
                var ctrlBlock []byte
267✔
191
                err := varBytesDecoder(reader, &ctrlBlock, &buf, 0)
267✔
192
                if err != nil {
267✔
193
                        return err
×
194
                }
×
195

196
                (*r)[id] = ctrlBlock
267✔
197
        }
198

199
        return nil
3✔
200
}
201

202
// resolverCtrlBlocksEncoder is a custom TLV encoder for the
203
// resolverCtrlBlocks.
204
func resolverCtrlBlocksEncoder(w io.Writer, val any, _ *[8]byte) error {
6✔
205
        if typ, ok := val.(*resolverCtrlBlocks); ok {
12✔
206
                return (*typ).Encode(w)
6✔
207
        }
6✔
208

209
        return tlv.NewTypeForEncodingErr(val, "resolverCtrlBlocks")
×
210
}
211

212
// rsolverCtrlBlocksDecoder is a custom TLV decoder for the resolverCtrlBlocks.
213
func resolverCtrlBlocksDecoder(r io.Reader, val any, _ *[8]byte,
214
        l uint64) error {
3✔
215

3✔
216
        if typ, ok := val.(*resolverCtrlBlocks); ok {
6✔
217
                blockReader := io.LimitReader(r, int64(l))
3✔
218

3✔
219
                resolverBlocks := newResolverCtrlBlocks()
3✔
220
                err := resolverBlocks.Decode(blockReader)
3✔
221
                if err != nil {
3✔
222
                        return err
×
223
                }
×
224

225
                *typ = resolverBlocks
3✔
226

3✔
227
                return nil
3✔
228
        }
229

230
        return tlv.NewTypeForDecodingErr(val, "resolverCtrlBlocks", l, l)
×
231
}
232

233
// ctrlBlocks is the set of control blocks we need to sweep all the output for
234
// a taproot/musig2 channel.
235
type ctrlBlocks struct {
236
        // CommitSweepCtrlBlock is the serialized control block needed to sweep
237
        // our commitment output.
238
        CommitSweepCtrlBlock []byte
239

240
        // RevokeSweepCtrlBlock is the serialized control block that's used to
241
        // sweep the reovked output of a breaching party.
242
        RevokeSweepCtrlBlock []byte
243

244
        // OutgoingHtlcCtrlBlocks is the set of serialized control blocks for
245
        // all outgoing HTLCs. This is the set of HTLCs that we offered to the
246
        // remote party. Depending on which commitment transaction was
247
        // broadcast, we'll either sweep here and be done, or also need to go
248
        // to the second level.
249
        OutgoingHtlcCtrlBlocks resolverCtrlBlocks
250

251
        // IncomingHtlcCtrlBlocks is the set of serialized control blocks for
252
        // all incoming HTLCs
253
        IncomingHtlcCtrlBlocks resolverCtrlBlocks
254

255
        // SecondLevelCtrlBlocks is the set of serialized control blocks for
256
        // need to sweep the second level HTLCs on our commitment transaction.
257
        SecondLevelCtrlBlocks resolverCtrlBlocks
258
}
259

260
// newCtrlBlocks returns a new instance of the ctrlBlocks struct.
UNCOV
261
func newCtrlBlocks() ctrlBlocks {
×
UNCOV
262
        return ctrlBlocks{
×
UNCOV
263
                OutgoingHtlcCtrlBlocks: newResolverCtrlBlocks(),
×
UNCOV
264
                IncomingHtlcCtrlBlocks: newResolverCtrlBlocks(),
×
UNCOV
265
                SecondLevelCtrlBlocks:  newResolverCtrlBlocks(),
×
UNCOV
266
        }
×
UNCOV
267
}
×
268

269
// varBytesEncoder is a custom TLV encoder for a variable length byte slice.
270
func varBytesEncoder(w io.Writer, val any, buf *[8]byte) error {
534✔
271
        if t, ok := val.(*[]byte); ok {
1,068✔
272
                if err := tlv.WriteVarInt(w, uint64(len(*t)), buf); err != nil {
534✔
273
                        return err
×
274
                }
×
275

276
                return tlv.EVarBytes(w, t, buf)
534✔
277
        }
278

279
        return tlv.NewTypeForEncodingErr(val, "[]byte")
×
280
}
281

282
// varBytesDecoder is a custom TLV decoder for a variable length byte slice.
283
func varBytesDecoder(r io.Reader, val any, buf *[8]byte, l uint64) error {
267✔
284
        if typ, ok := val.(*[]byte); ok {
534✔
285
                bytesLen, err := tlv.ReadVarInt(r, buf)
267✔
286
                if err != nil {
267✔
287
                        return err
×
288
                }
×
289

290
                var bytes []byte
267✔
291
                if err := tlv.DVarBytes(r, &bytes, buf, bytesLen); err != nil {
267✔
292
                        return err
×
293
                }
×
294

295
                *typ = bytes
267✔
296

267✔
297
                return nil
267✔
298
        }
299

300
        return tlv.NewTypeForDecodingErr(val, "[]byte", l, l)
×
301
}
302

303
// ctrlBlockEncoder is a custom TLV encoder for the ctrlBlocks struct.
304
func ctrlBlockEncoder(w io.Writer, val any, _ *[8]byte) error {
2✔
305
        if t, ok := val.(*ctrlBlocks); ok {
4✔
306
                return (*t).Encode(w)
2✔
307
        }
2✔
308

309
        return tlv.NewTypeForEncodingErr(val, "ctrlBlocks")
×
310
}
311

312
// ctrlBlockDecoder is a custom TLV decoder for the ctrlBlocks struct.
313
func ctrlBlockDecoder(r io.Reader, val any, _ *[8]byte, l uint64) error {
1✔
314
        if typ, ok := val.(*ctrlBlocks); ok {
2✔
315
                ctrlReader := io.LimitReader(r, int64(l))
1✔
316

1✔
317
                var ctrlBlocks ctrlBlocks
1✔
318
                err := ctrlBlocks.Decode(ctrlReader)
1✔
319
                if err != nil {
1✔
320
                        return err
×
321
                }
×
322

323
                *typ = ctrlBlocks
1✔
324

1✔
325
                return nil
1✔
326
        }
327

328
        return tlv.NewTypeForDecodingErr(val, "ctrlBlocks", l, l)
×
329
}
330

331
// EncodeRecords returns the set of TLV records that encode the control block
332
// for the commitment transaction.
333
func (c *ctrlBlocks) EncodeRecords() []tlv.Record {
2✔
334
        var records []tlv.Record
2✔
335

2✔
336
        if len(c.CommitSweepCtrlBlock) > 0 {
4✔
337
                records = append(records, tlv.MakePrimitiveRecord(
2✔
338
                        commitCtrlBlockType, &c.CommitSweepCtrlBlock,
2✔
339
                ))
2✔
340
        }
2✔
341

342
        if len(c.RevokeSweepCtrlBlock) > 0 {
4✔
343
                records = append(records, tlv.MakePrimitiveRecord(
2✔
344
                        revokeCtrlBlockType, &c.RevokeSweepCtrlBlock,
2✔
345
                ))
2✔
346
        }
2✔
347

348
        if c.OutgoingHtlcCtrlBlocks != nil {
4✔
349
                records = append(records, tlv.MakeDynamicRecord(
2✔
350
                        outgoingHtlcCtrlBlockType, &c.OutgoingHtlcCtrlBlocks,
2✔
351
                        c.OutgoingHtlcCtrlBlocks.recordSize,
2✔
352
                        resolverCtrlBlocksEncoder, resolverCtrlBlocksDecoder,
2✔
353
                ))
2✔
354
        }
2✔
355

356
        if c.IncomingHtlcCtrlBlocks != nil {
4✔
357
                records = append(records, tlv.MakeDynamicRecord(
2✔
358
                        incomingHtlcCtrlBlockType, &c.IncomingHtlcCtrlBlocks,
2✔
359
                        c.IncomingHtlcCtrlBlocks.recordSize,
2✔
360
                        resolverCtrlBlocksEncoder, resolverCtrlBlocksDecoder,
2✔
361
                ))
2✔
362
        }
2✔
363

364
        if c.SecondLevelCtrlBlocks != nil {
4✔
365
                records = append(records, tlv.MakeDynamicRecord(
2✔
366
                        secondLevelCtrlBlockType, &c.SecondLevelCtrlBlocks,
2✔
367
                        c.SecondLevelCtrlBlocks.recordSize,
2✔
368
                        resolverCtrlBlocksEncoder, resolverCtrlBlocksDecoder,
2✔
369
                ))
2✔
370
        }
2✔
371

372
        return records
2✔
373
}
374

375
// DecodeRecords returns the set of TLV records that decode the control block.
376
func (c *ctrlBlocks) DecodeRecords() []tlv.Record {
1✔
377
        return []tlv.Record{
1✔
378
                tlv.MakePrimitiveRecord(
1✔
379
                        commitCtrlBlockType, &c.CommitSweepCtrlBlock,
1✔
380
                ),
1✔
381
                tlv.MakePrimitiveRecord(
1✔
382
                        revokeCtrlBlockType, &c.RevokeSweepCtrlBlock,
1✔
383
                ),
1✔
384
                tlv.MakeDynamicRecord(
1✔
385
                        outgoingHtlcCtrlBlockType, &c.OutgoingHtlcCtrlBlocks,
1✔
386
                        c.OutgoingHtlcCtrlBlocks.recordSize,
1✔
387
                        resolverCtrlBlocksEncoder, resolverCtrlBlocksDecoder,
1✔
388
                ),
1✔
389
                tlv.MakeDynamicRecord(
1✔
390
                        incomingHtlcCtrlBlockType, &c.IncomingHtlcCtrlBlocks,
1✔
391
                        c.IncomingHtlcCtrlBlocks.recordSize,
1✔
392
                        resolverCtrlBlocksEncoder, resolverCtrlBlocksDecoder,
1✔
393
                ),
1✔
394
                tlv.MakeDynamicRecord(
1✔
395
                        secondLevelCtrlBlockType, &c.SecondLevelCtrlBlocks,
1✔
396
                        c.SecondLevelCtrlBlocks.recordSize,
1✔
397
                        resolverCtrlBlocksEncoder, resolverCtrlBlocksDecoder,
1✔
398
                ),
1✔
399
        }
1✔
400
}
1✔
401

402
// Record returns a TLV record that can be used to encode/decode the control
403
// blocks.  type from a given TLV stream.
404
func (c *ctrlBlocks) Record() tlv.Record {
2✔
405
        recordSize := func() uint64 {
3✔
406
                var (
1✔
407
                        b   bytes.Buffer
1✔
408
                        buf [8]byte
1✔
409
                )
1✔
410
                if err := ctrlBlockEncoder(&b, c, &buf); err != nil {
1✔
411
                        panic(err)
×
412
                }
413

414
                return uint64(len(b.Bytes()))
1✔
415
        }
416

417
        return tlv.MakeDynamicRecord(
2✔
418
                0, c, recordSize, ctrlBlockEncoder, ctrlBlockDecoder,
2✔
419
        )
2✔
420
}
421

422
// Encode encodes the set of control blocks.
423
func (c *ctrlBlocks) Encode(w io.Writer) error {
2✔
424
        stream, err := tlv.NewStream(c.EncodeRecords()...)
2✔
425
        if err != nil {
2✔
426
                return err
×
427
        }
×
428

429
        return stream.Encode(w)
2✔
430
}
431

432
// Decode decodes the set of control blocks.
433
func (c *ctrlBlocks) Decode(r io.Reader) error {
1✔
434
        stream, err := tlv.NewStream(c.DecodeRecords()...)
1✔
435
        if err != nil {
1✔
436
                return err
×
437
        }
×
438

439
        return stream.Decode(r)
1✔
440
}
441

442
// htlcTapTweakss maps an outpoint (the same format as the resolver ID) to the
443
// tap tweak needed to sweep a breached HTLC output. This is used for both the
444
// first and second level HTLC outputs.
445
type htlcTapTweaks map[resolverID][32]byte
446

447
// newHtlcTapTweaks returns a new instance of the htlcTapTweaks struct.
448
func newHtlcTapTweaks() htlcTapTweaks {
2✔
449
        return make(htlcTapTweaks)
2✔
450
}
2✔
451

452
// recordSize returns the size of the record in bytes.
453
func (h *htlcTapTweaks) recordSize() uint64 {
4✔
454
        // Each record will be serialized as: <num_tweaks> || <tweak>, where
4✔
455
        // <tweak> is serialized as: <resolver_key> || <tweak>.
4✔
456
        numTweaks := uint64(len(*h))
4✔
457
        baseSize := tlv.VarIntSize(numTweaks)
4✔
458

4✔
459
        recordSize := baseSize
4✔
460
        for range *h {
822✔
461
                // Each tweak is a fixed 32 bytes, so we just tally that an the
818✔
462
                // size of the resolver ID.
818✔
463
                recordSize += resolverIDLen
818✔
464
                recordSize += 32
818✔
465
        }
818✔
466

467
        return recordSize
4✔
468
}
469

470
// Encode encodes the tap tweaks into the target writer.
471
func (h *htlcTapTweaks) Encode(w io.Writer) error {
4✔
472
        numTweaks := uint64(len(*h))
4✔
473

4✔
474
        var buf [8]byte
4✔
475
        if err := tlv.WriteVarInt(w, numTweaks, &buf); err != nil {
4✔
476
                return err
×
477
        }
×
478

479
        for id, tweak := range *h {
822✔
480
                tweak := tweak
818✔
481

818✔
482
                if _, err := w.Write(id[:]); err != nil {
818✔
483
                        return err
×
484
                }
×
485

486
                if _, err := w.Write(tweak[:]); err != nil {
818✔
487
                        return err
×
488
                }
×
489
        }
490

491
        return nil
4✔
492
}
493

494
// htlcTapTweaksEncoder is a custom TLV encoder for the htlcTapTweaks struct.
495
func htlcTapTweaksEncoder(w io.Writer, val any, _ *[8]byte) error {
4✔
496
        if t, ok := val.(*htlcTapTweaks); ok {
8✔
497
                return (*t).Encode(w)
4✔
498
        }
4✔
499

500
        return tlv.NewTypeForEncodingErr(val, "htlcTapTweaks")
×
501
}
502

503
// htlcTapTweaksDecoder is a custom TLV decoder for the htlcTapTweaks struct.
504
func htlcTapTweaksDecoder(r io.Reader, val any, _ *[8]byte,
505
        l uint64) error {
2✔
506

2✔
507
        if typ, ok := val.(*htlcTapTweaks); ok {
4✔
508
                tweakReader := io.LimitReader(r, int64(l))
2✔
509

2✔
510
                htlcTweaks := newHtlcTapTweaks()
2✔
511
                err := htlcTweaks.Decode(tweakReader)
2✔
512
                if err != nil {
2✔
513
                        return err
×
514
                }
×
515

516
                *typ = htlcTweaks
2✔
517

2✔
518
                return nil
2✔
519
        }
520

521
        return tlv.NewTypeForDecodingErr(val, "htlcTapTweaks", l, l)
×
522
}
523

524
// Decode decodes the tap tweaks into the target struct.
525
func (h *htlcTapTweaks) Decode(reader io.Reader) error {
2✔
526
        var buf [8]byte
2✔
527

2✔
528
        numTweaks, err := tlv.ReadVarInt(reader, &buf)
2✔
529
        if err != nil {
2✔
530
                return err
×
531
        }
×
532

533
        for i := uint64(0); i < numTweaks; i++ {
411✔
534
                var id resolverID
409✔
535
                if _, err := io.ReadFull(reader, id[:]); err != nil {
409✔
536
                        return err
×
537
                }
×
538

539
                var tweak [32]byte
409✔
540
                if _, err := io.ReadFull(reader, tweak[:]); err != nil {
409✔
541
                        return err
×
542
                }
×
543

544
                (*h)[id] = tweak
409✔
545
        }
546

547
        return nil
2✔
548
}
549

550
// tapTweaks stores the set of taptweaks needed to perform keyspends for the
551
// commitment outputs.
552
type tapTweaks struct {
553
        // AnchorTweak is the tweak used to derive the key used to spend the
554
        // anchor output.
555
        AnchorTweak []byte
556

557
        // BreachedHtlcTweaks stores the set of tweaks needed to sweep the
558
        // revoked first level output of an HTLC.
559
        BreachedHtlcTweaks htlcTapTweaks
560

561
        // BreachedSecondLevelHtlcTweaks stores the set of tweaks needed to
562
        // sweep the revoked *second* level output of an HTLC.
563
        BreachedSecondLevelHltcTweaks htlcTapTweaks
564
}
565

566
// newTapTweaks returns a new tapTweaks struct.
UNCOV
567
func newTapTweaks() tapTweaks {
×
UNCOV
568
        return tapTweaks{
×
UNCOV
569
                BreachedHtlcTweaks:            make(htlcTapTweaks),
×
UNCOV
570
                BreachedSecondLevelHltcTweaks: make(htlcTapTweaks),
×
UNCOV
571
        }
×
UNCOV
572
}
×
573

574
// tapTweaksEncoder is a custom TLV encoder for the tapTweaks struct.
575
func tapTweaksEncoder(w io.Writer, val any, _ *[8]byte) error {
2✔
576
        if t, ok := val.(*tapTweaks); ok {
4✔
577
                return (*t).Encode(w)
2✔
578
        }
2✔
579

580
        return tlv.NewTypeForEncodingErr(val, "tapTweaks")
×
581
}
582

583
// tapTweaksDecoder is a custom TLV decoder for the tapTweaks struct.
584
func tapTweaksDecoder(r io.Reader, val any, _ *[8]byte, l uint64) error {
1✔
585
        if typ, ok := val.(*tapTweaks); ok {
2✔
586
                tweakReader := io.LimitReader(r, int64(l))
1✔
587

1✔
588
                var tapTweaks tapTweaks
1✔
589
                err := tapTweaks.Decode(tweakReader)
1✔
590
                if err != nil {
1✔
591
                        return err
×
592
                }
×
593

594
                *typ = tapTweaks
1✔
595

1✔
596
                return nil
1✔
597
        }
598

599
        return tlv.NewTypeForDecodingErr(val, "tapTweaks", l, l)
×
600
}
601

602
// EncodeRecords returns the set of TLV records that encode the tweaks.
603
func (t *tapTweaks) EncodeRecords() []tlv.Record {
2✔
604
        var records []tlv.Record
2✔
605

2✔
606
        if len(t.AnchorTweak) > 0 {
4✔
607
                records = append(records, tlv.MakePrimitiveRecord(
2✔
608
                        anchorTapTweakType, &t.AnchorTweak,
2✔
609
                ))
2✔
610
        }
2✔
611

612
        if len(t.BreachedHtlcTweaks) > 0 {
4✔
613
                records = append(records, tlv.MakeDynamicRecord(
2✔
614
                        htlcTweakCtrlBlockType, &t.BreachedHtlcTweaks,
2✔
615
                        t.BreachedHtlcTweaks.recordSize,
2✔
616
                        htlcTapTweaksEncoder, htlcTapTweaksDecoder,
2✔
617
                ))
2✔
618
        }
2✔
619

620
        if len(t.BreachedSecondLevelHltcTweaks) > 0 {
4✔
621
                records = append(records, tlv.MakeDynamicRecord(
2✔
622
                        secondLevelHtlcTweakCtrlBlockType,
2✔
623
                        &t.BreachedSecondLevelHltcTweaks,
2✔
624
                        t.BreachedSecondLevelHltcTweaks.recordSize,
2✔
625
                        htlcTapTweaksEncoder, htlcTapTweaksDecoder,
2✔
626
                ))
2✔
627
        }
2✔
628

629
        return records
2✔
630
}
631

632
// DecodeRecords returns the set of TLV records that decode the tweaks.
633
func (t *tapTweaks) DecodeRecords() []tlv.Record {
1✔
634
        return []tlv.Record{
1✔
635
                tlv.MakePrimitiveRecord(anchorTapTweakType, &t.AnchorTweak),
1✔
636
                tlv.MakeDynamicRecord(
1✔
637
                        htlcTweakCtrlBlockType, &t.BreachedHtlcTweaks,
1✔
638
                        t.BreachedHtlcTweaks.recordSize,
1✔
639
                        htlcTapTweaksEncoder, htlcTapTweaksDecoder,
1✔
640
                ),
1✔
641
                tlv.MakeDynamicRecord(
1✔
642
                        secondLevelHtlcTweakCtrlBlockType,
1✔
643
                        &t.BreachedSecondLevelHltcTweaks,
1✔
644
                        t.BreachedSecondLevelHltcTweaks.recordSize,
1✔
645
                        htlcTapTweaksEncoder, htlcTapTweaksDecoder,
1✔
646
                ),
1✔
647
        }
1✔
648
}
1✔
649

650
// Record returns a TLV record that can be used to encode/decode the tap
651
// tweaks.
652
func (t *tapTweaks) Record() tlv.Record {
2✔
653
        recordSize := func() uint64 {
3✔
654
                var (
1✔
655
                        b   bytes.Buffer
1✔
656
                        buf [8]byte
1✔
657
                )
1✔
658
                if err := tapTweaksEncoder(&b, t, &buf); err != nil {
1✔
659
                        panic(err)
×
660
                }
661

662
                return uint64(len(b.Bytes()))
1✔
663
        }
664

665
        return tlv.MakeDynamicRecord(
2✔
666
                0, t, recordSize, tapTweaksEncoder, tapTweaksDecoder,
2✔
667
        )
2✔
668
}
669

670
// Encode encodes the set of tap tweaks.
671
func (t *tapTweaks) Encode(w io.Writer) error {
2✔
672
        stream, err := tlv.NewStream(t.EncodeRecords()...)
2✔
673
        if err != nil {
2✔
674
                return err
×
675
        }
×
676

677
        return stream.Encode(w)
2✔
678
}
679

680
// Decode decodes the set of tap tweaks.
681
func (t *tapTweaks) Decode(r io.Reader) error {
1✔
682
        stream, err := tlv.NewStream(t.DecodeRecords()...)
1✔
683
        if err != nil {
1✔
684
                return err
×
685
        }
×
686

687
        return stream.Decode(r)
1✔
688
}
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