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

lightningnetwork / lnd / 11166428937

03 Oct 2024 05:07PM UTC coverage: 58.738% (-0.08%) from 58.817%
11166428937

push

github

web-flow
Merge pull request #8960 from lightningnetwork/0-19-staging-rebased

[custom channels 5/5]: merge custom channel staging branch into master

657 of 875 new or added lines in 29 files covered. (75.09%)

260 existing lines in 20 files now uncovered.

130540 of 222243 relevant lines covered (58.74%)

28084.43 hits per line

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

84.65
/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.
49
func newTaprootBriefcase() *taprootBriefcase {
3✔
50
        return &taprootBriefcase{
3✔
51
                CtrlBlocks: tlv.NewRecordT[tlv.TlvType0](newCtrlBlocks()),
3✔
52
                TapTweaks:  tlv.NewRecordT[tlv.TlvType1](newTapTweaks()),
3✔
53
        }
3✔
54
}
3✔
55

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

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

74
        return records
4✔
75
}
76

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

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

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

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

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

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

121
        return nil
4✔
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 {
6✔
130
        return make(resolverCtrlBlocks)
6✔
131
}
6✔
132

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

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

148
        return recordSize
9✔
149
}
150

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

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

160
        for id, ctrlBlock := range *r {
750✔
161
                ctrlBlock := ctrlBlock
741✔
162

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

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

172
        return nil
9✔
173
}
174

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

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

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

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

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

199
        return nil
6✔
200
}
201

202
// resolverCtrlBlocksEncoder is a custom TLV encoder for the
203
// resolverCtrlBlocks.
204
func resolverCtrlBlocksEncoder(w io.Writer, val any, _ *[8]byte) error {
9✔
205
        if typ, ok := val.(*resolverCtrlBlocks); ok {
18✔
206
                return (*typ).Encode(w)
9✔
207
        }
9✔
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 {
6✔
215

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

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

225
                *typ = resolverBlocks
6✔
226

6✔
227
                return nil
6✔
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.
261
func newCtrlBlocks() ctrlBlocks {
3✔
262
        return ctrlBlocks{
3✔
263
                OutgoingHtlcCtrlBlocks: newResolverCtrlBlocks(),
3✔
264
                IncomingHtlcCtrlBlocks: newResolverCtrlBlocks(),
3✔
265
                SecondLevelCtrlBlocks:  newResolverCtrlBlocks(),
3✔
266
        }
3✔
267
}
3✔
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 {
741✔
271
        if t, ok := val.(*[]byte); ok {
1,482✔
272
                if err := tlv.WriteVarInt(w, uint64(len(*t)), buf); err != nil {
741✔
273
                        return err
×
274
                }
×
275

276
                return tlv.EVarBytes(w, t, buf)
741✔
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 {
372✔
284
        if typ, ok := val.(*[]byte); ok {
744✔
285
                bytesLen, err := tlv.ReadVarInt(r, buf)
372✔
286
                if err != nil {
372✔
287
                        return err
×
288
                }
×
289

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

295
                *typ = bytes
372✔
296

372✔
297
                return nil
372✔
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 {
5✔
305
        if t, ok := val.(*ctrlBlocks); ok {
10✔
306
                return (*t).Encode(w)
5✔
307
        }
5✔
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 {
4✔
314
        if typ, ok := val.(*ctrlBlocks); ok {
8✔
315
                ctrlReader := io.LimitReader(r, int64(l))
4✔
316

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

323
                *typ = ctrlBlocks
4✔
324

4✔
325
                return nil
4✔
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 {
5✔
334
        var records []tlv.Record
5✔
335

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

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

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

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

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

372
        return records
5✔
373
}
374

375
// DecodeRecords returns the set of TLV records that decode the control block.
376
func (c *ctrlBlocks) DecodeRecords() []tlv.Record {
4✔
377
        return []tlv.Record{
4✔
378
                tlv.MakePrimitiveRecord(
4✔
379
                        commitCtrlBlockType, &c.CommitSweepCtrlBlock,
4✔
380
                ),
4✔
381
                tlv.MakePrimitiveRecord(
4✔
382
                        revokeCtrlBlockType, &c.RevokeSweepCtrlBlock,
4✔
383
                ),
4✔
384
                tlv.MakeDynamicRecord(
4✔
385
                        outgoingHtlcCtrlBlockType, &c.OutgoingHtlcCtrlBlocks,
4✔
386
                        c.OutgoingHtlcCtrlBlocks.recordSize,
4✔
387
                        resolverCtrlBlocksEncoder, resolverCtrlBlocksDecoder,
4✔
388
                ),
4✔
389
                tlv.MakeDynamicRecord(
4✔
390
                        incomingHtlcCtrlBlockType, &c.IncomingHtlcCtrlBlocks,
4✔
391
                        c.IncomingHtlcCtrlBlocks.recordSize,
4✔
392
                        resolverCtrlBlocksEncoder, resolverCtrlBlocksDecoder,
4✔
393
                ),
4✔
394
                tlv.MakeDynamicRecord(
4✔
395
                        secondLevelCtrlBlockType, &c.SecondLevelCtrlBlocks,
4✔
396
                        c.SecondLevelCtrlBlocks.recordSize,
4✔
397
                        resolverCtrlBlocksEncoder, resolverCtrlBlocksDecoder,
4✔
398
                ),
4✔
399
        }
4✔
400
}
4✔
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 {
5✔
405
        recordSize := func() uint64 {
9✔
406
                var (
4✔
407
                        b   bytes.Buffer
4✔
408
                        buf [8]byte
4✔
409
                )
4✔
410
                if err := ctrlBlockEncoder(&b, c, &buf); err != nil {
4✔
NEW
411
                        panic(err)
×
412
                }
413

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

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

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

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

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

439
        return stream.Decode(r)
4✔
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 {
5✔
449
        return make(htlcTapTweaks)
5✔
450
}
5✔
451

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

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

467
        return recordSize
7✔
468
}
469

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

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

479
        for id, tweak := range *h {
468✔
480
                tweak := tweak
461✔
481

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

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

491
        return nil
7✔
492
}
493

494
// htlcTapTweaksEncoder is a custom TLV encoder for the htlcTapTweaks struct.
495
func htlcTapTweaksEncoder(w io.Writer, val any, _ *[8]byte) error {
7✔
496
        if t, ok := val.(*htlcTapTweaks); ok {
14✔
497
                return (*t).Encode(w)
7✔
498
        }
7✔
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 {
5✔
506

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

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

516
                *typ = htlcTweaks
5✔
517

5✔
518
                return nil
5✔
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 {
5✔
526
        var buf [8]byte
5✔
527

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

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

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

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

547
        return nil
5✔
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.
567
func newTapTweaks() tapTweaks {
3✔
568
        return tapTweaks{
3✔
569
                BreachedHtlcTweaks:            make(htlcTapTweaks),
3✔
570
                BreachedSecondLevelHltcTweaks: make(htlcTapTweaks),
3✔
571
        }
3✔
572
}
3✔
573

574
// tapTweaksEncoder is a custom TLV encoder for the tapTweaks struct.
575
func tapTweaksEncoder(w io.Writer, val any, _ *[8]byte) error {
5✔
576
        if t, ok := val.(*tapTweaks); ok {
10✔
577
                return (*t).Encode(w)
5✔
578
        }
5✔
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 {
4✔
585
        if typ, ok := val.(*tapTweaks); ok {
8✔
586
                tweakReader := io.LimitReader(r, int64(l))
4✔
587

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

594
                *typ = tapTweaks
4✔
595

4✔
596
                return nil
4✔
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 {
5✔
604
        var records []tlv.Record
5✔
605

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

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

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

629
        return records
5✔
630
}
631

632
// DecodeRecords returns the set of TLV records that decode the tweaks.
633
func (t *tapTweaks) DecodeRecords() []tlv.Record {
4✔
634
        return []tlv.Record{
4✔
635
                tlv.MakePrimitiveRecord(anchorTapTweakType, &t.AnchorTweak),
4✔
636
                tlv.MakeDynamicRecord(
4✔
637
                        htlcTweakCtrlBlockType, &t.BreachedHtlcTweaks,
4✔
638
                        t.BreachedHtlcTweaks.recordSize,
4✔
639
                        htlcTapTweaksEncoder, htlcTapTweaksDecoder,
4✔
640
                ),
4✔
641
                tlv.MakeDynamicRecord(
4✔
642
                        secondLevelHtlcTweakCtrlBlockType,
4✔
643
                        &t.BreachedSecondLevelHltcTweaks,
4✔
644
                        t.BreachedSecondLevelHltcTweaks.recordSize,
4✔
645
                        htlcTapTweaksEncoder, htlcTapTweaksDecoder,
4✔
646
                ),
4✔
647
        }
4✔
648
}
4✔
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 {
5✔
653
        recordSize := func() uint64 {
9✔
654
                var (
4✔
655
                        b   bytes.Buffer
4✔
656
                        buf [8]byte
4✔
657
                )
4✔
658
                if err := tapTweaksEncoder(&b, t, &buf); err != nil {
4✔
NEW
659
                        panic(err)
×
660
                }
661

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

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

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

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

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

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