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

lightningnetwork / lnd / 11357847688

16 Oct 2024 02:36AM UTC coverage: 57.864% (-0.9%) from 58.779%
11357847688

Pull #9148

github

ProofOfKeags
lnwire: change DynPropose/DynCommit TLV numbers to align with spec
Pull Request #9148: DynComms [2/n]: lnwire: add authenticated wire messages for Dyn*

350 of 644 new or added lines in 12 files covered. (54.35%)

19831 existing lines in 241 files now uncovered.

99337 of 171674 relevant lines covered (57.86%)

38595.9 hits per line

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

52.99
/lnwire/dyn_propose.go
1
package lnwire
2

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

7
        "github.com/btcsuite/btcd/btcutil"
8
        "github.com/lightningnetwork/lnd/fn"
9
        "github.com/lightningnetwork/lnd/keychain"
10
        "github.com/lightningnetwork/lnd/tlv"
11
)
12

13
const (
14
        // DPDustLimitSatoshis is the TLV type number that identifies the record
15
        // for DynPropose.DustLimit.
16
        DPDustLimitSatoshis tlv.Type = 0
17

18
        // DPMaxHtlcValueInFlightMsat is the TLV type number that identifies the
19
        // record for DynPropose.MaxValueInFlight.
20
        DPMaxHtlcValueInFlightMsat tlv.Type = 2
21

22
        // DPHtlcMinimumMsat is the TLV type number that identifies the record
23
        // for DynPropose.HtlcMinimum.
24
        DPHtlcMinimumMsat tlv.Type = 4
25

26
        // DPChannelReserveSatoshis is the TLV type number that identifies the
27
        // for DynPropose.ChannelReserve.
28
        DPChannelReserveSatoshis tlv.Type = 6
29

30
        // DPToSelfDelay is the TLV type number that identifies the record for
31
        // DynPropose.CsvDelay.
32
        DPToSelfDelay tlv.Type = 8
33

34
        // DPMaxAcceptedHtlcs is the TLV type number that identifies the record
35
        // for DynPropose.MaxAcceptedHTLCs.
36
        DPMaxAcceptedHtlcs tlv.Type = 10
37

38
        // DPChannelType is the TLV type number that identifies the record for
39
        // DynPropose.ChannelType.
40
        DPChannelType tlv.Type = 12
41
)
42

43
// DynPropose is a message that is sent during a dynamic commitments negotiation
44
// process. It is sent by both parties to propose new channel parameters.
45
type DynPropose struct {
46
        // ChanID identifies the channel whose parameters we are trying to
47
        // re-negotiate.
48
        ChanID ChannelID
49

50
        // DustLimit, if not nil, proposes a change to the dust_limit_satoshis
51
        // for the sender's commitment transaction.
52
        DustLimit fn.Option[btcutil.Amount]
53

54
        // MaxValueInFlight, if not nil, proposes a change to the
55
        // max_htlc_value_in_flight_msat limit of the sender.
56
        MaxValueInFlight fn.Option[MilliSatoshi]
57

58
        // HtlcMinimum, if not nil, proposes a change to the htlc_minimum_msat
59
        // floor of the sender.
60
        HtlcMinimum fn.Option[MilliSatoshi]
61

62
        // ChannelReserve, if not nil, proposes a change to the
63
        // channel_reserve_satoshis requirement of the recipient.
64
        ChannelReserve fn.Option[btcutil.Amount]
65

66
        // CsvDelay, if not nil, proposes a change to the to_self_delay
67
        // requirement of the recipient.
68
        CsvDelay fn.Option[uint16]
69

70
        // MaxAcceptedHTLCs, if not nil, proposes a change to the
71
        // max_accepted_htlcs limit of the sender.
72
        MaxAcceptedHTLCs fn.Option[uint16]
73

74
        // ChannelType, if not nil, proposes a change to the channel_type
75
        // parameter.
76
        ChannelType fn.Option[ChannelType]
77

78
        // ExtraData is the set of data that was appended to this message to
79
        // fill out the full maximum transport message size. These fields can
80
        // be used to specify optional data such as custom TLV fields.
81
        //
82
        // NOTE: Since the fields in this structure are part of the TLV stream,
83
        // ExtraData will contain all TLV records _except_ the ones that are
84
        // present in earlier parts of this structure.
85
        ExtraData ExtraOpaqueData
86
}
87

88
// A compile time check to ensure DynPropose implements the lnwire.Message
89
// interface.
90
var _ Message = (*DynPropose)(nil)
91

92
// Encode serializes the target DynPropose into the passed io.Writer.
93
// Serialization will observe the rules defined by the passed protocol version.
94
//
95
// This is a part of the lnwire.Message interface.
96
func (dp *DynPropose) Encode(w *bytes.Buffer, _ uint32) error {
103✔
97
        var tlvRecords []tlv.Record
103✔
98
        dp.DustLimit.WhenSome(func(dl btcutil.Amount) {
154✔
99
                protoSats := uint64(dl)
51✔
100
                tlvRecords = append(
51✔
101
                        tlvRecords, tlv.MakePrimitiveRecord(
51✔
102
                                DPDustLimitSatoshis, &protoSats,
51✔
103
                        ),
51✔
104
                )
51✔
105
        })
51✔
106
        dp.MaxValueInFlight.WhenSome(func(max MilliSatoshi) {
154✔
107
                protoSats := uint64(max)
51✔
108
                tlvRecords = append(
51✔
109
                        tlvRecords, tlv.MakePrimitiveRecord(
51✔
110
                                DPMaxHtlcValueInFlightMsat, &protoSats,
51✔
111
                        ),
51✔
112
                )
51✔
113
        })
51✔
114
        dp.HtlcMinimum.WhenSome(func(min MilliSatoshi) {
103✔
NEW
115
                protoSats := uint64(min)
×
NEW
116
                tlvRecords = append(
×
NEW
117
                        tlvRecords, tlv.MakePrimitiveRecord(
×
NEW
118
                                DPHtlcMinimumMsat, &protoSats,
×
NEW
119
                        ),
×
NEW
120
                )
×
NEW
121
        })
×
122
        dp.ChannelReserve.WhenSome(func(min btcutil.Amount) {
160✔
123
                channelReserve := uint64(min)
57✔
124
                tlvRecords = append(
57✔
125
                        tlvRecords, tlv.MakePrimitiveRecord(
57✔
126
                                DPChannelReserveSatoshis, &channelReserve,
57✔
127
                        ),
57✔
128
                )
57✔
129
        })
57✔
130
        dp.CsvDelay.WhenSome(func(wait uint16) {
159✔
131
                tlvRecords = append(
56✔
132
                        tlvRecords, tlv.MakePrimitiveRecord(
56✔
133
                                DPToSelfDelay, &wait,
56✔
134
                        ),
56✔
135
                )
56✔
136
        })
56✔
137
        dp.MaxAcceptedHTLCs.WhenSome(func(max uint16) {
165✔
138
                tlvRecords = append(
62✔
139
                        tlvRecords, tlv.MakePrimitiveRecord(
62✔
140
                                DPMaxAcceptedHtlcs, &max,
62✔
141
                        ),
62✔
142
                )
62✔
143
        })
62✔
144
        dp.ChannelType.WhenSome(func(ty ChannelType) {
152✔
145
                tlvRecords = append(
49✔
146
                        tlvRecords, tlv.MakeDynamicRecord(
49✔
147
                                DPChannelType, &ty,
49✔
148
                                ty.featureBitLen,
49✔
149
                                channelTypeEncoder, channelTypeDecoder,
49✔
150
                        ),
49✔
151
                )
49✔
152
        })
49✔
153
        tlv.SortRecords(tlvRecords)
103✔
154

103✔
155
        tlvStream, err := tlv.NewStream(tlvRecords...)
103✔
156
        if err != nil {
103✔
157
                return err
×
158
        }
×
159

160
        var extraBytesWriter bytes.Buffer
103✔
161
        if err := tlvStream.Encode(&extraBytesWriter); err != nil {
103✔
162
                return err
×
163
        }
×
164
        dp.ExtraData = ExtraOpaqueData(extraBytesWriter.Bytes())
103✔
165

103✔
166
        if err := WriteChannelID(w, dp.ChanID); err != nil {
103✔
167
                return err
×
168
        }
×
169

170
        return WriteBytes(w, dp.ExtraData)
103✔
171
}
172

173
// Decode deserializes the serialized DynPropose stored in the passed io.Reader
174
// into the target DynPropose using the deserialization rules defined by the
175
// passed protocol version.
176
//
177
// This is a part of the lnwire.Message interface.
178
func (dp *DynPropose) Decode(r io.Reader, _ uint32) error {
208✔
179
        // Parse out the only required field.
208✔
180
        if err := ReadElements(r, &dp.ChanID); err != nil {
210✔
181
                return err
2✔
182
        }
2✔
183

184
        // Parse out TLV stream.
185
        var tlvRecords ExtraOpaqueData
206✔
186
        if err := ReadElements(r, &tlvRecords); err != nil {
206✔
187
                return err
×
188
        }
×
189

190
        // Prepare receiving buffers to be filled by TLV extraction.
191
        var dustLimitScratch uint64
206✔
192
        dustLimit := tlv.MakePrimitiveRecord(
206✔
193
                DPDustLimitSatoshis, &dustLimitScratch,
206✔
194
        )
206✔
195

206✔
196
        var maxValueScratch uint64
206✔
197
        maxValue := tlv.MakePrimitiveRecord(
206✔
198
                DPMaxHtlcValueInFlightMsat, &maxValueScratch,
206✔
199
        )
206✔
200

206✔
201
        var htlcMinScratch uint64
206✔
202
        htlcMin := tlv.MakePrimitiveRecord(
206✔
203
                DPHtlcMinimumMsat, &htlcMinScratch,
206✔
204
        )
206✔
205

206✔
206
        var reserveScratch uint64
206✔
207
        reserve := tlv.MakePrimitiveRecord(
206✔
208
                DPChannelReserveSatoshis, &reserveScratch,
206✔
209
        )
206✔
210

206✔
211
        var csvDelayScratch uint16
206✔
212
        csvDelay := tlv.MakePrimitiveRecord(DPToSelfDelay, &csvDelayScratch)
206✔
213

206✔
214
        var maxHtlcsScratch uint16
206✔
215
        maxHtlcs := tlv.MakePrimitiveRecord(
206✔
216
                DPMaxAcceptedHtlcs, &maxHtlcsScratch,
206✔
217
        )
206✔
218

206✔
219
        var chanTypeScratch ChannelType
206✔
220
        chanType := tlv.MakeDynamicRecord(
206✔
221
                DPChannelType, &chanTypeScratch, chanTypeScratch.featureBitLen,
206✔
222
                channelTypeEncoder, channelTypeDecoder,
206✔
223
        )
206✔
224

206✔
225
        // Create set of Records to read TLV bytestream into.
206✔
226
        records := []tlv.Record{
206✔
227
                dustLimit, maxValue, htlcMin, reserve, csvDelay, maxHtlcs,
206✔
228
                chanType,
206✔
229
        }
206✔
230
        tlv.SortRecords(records)
206✔
231

206✔
232
        // Read TLV stream into record set.
206✔
233
        extraBytesReader := bytes.NewReader(tlvRecords)
206✔
234
        tlvStream, err := tlv.NewStream(records...)
206✔
235
        if err != nil {
206✔
236
                return err
×
237
        }
×
238

239
        typeMap, err := tlvStream.DecodeWithParsedTypesP2P(extraBytesReader)
206✔
240
        if err != nil {
306✔
241
                return err
100✔
242
        }
100✔
243

244
        // Check the results of the TLV Stream decoding and appropriately set
245
        // message fields.
246
        if val, ok := typeMap[DPDustLimitSatoshis]; ok && val == nil {
157✔
247
                dp.DustLimit = fn.Some(btcutil.Amount(dustLimitScratch))
51✔
248
        }
51✔
249
        if val, ok := typeMap[DPMaxHtlcValueInFlightMsat]; ok && val == nil {
157✔
250
                dp.MaxValueInFlight = fn.Some(MilliSatoshi(maxValueScratch))
51✔
251
        }
51✔
252
        if val, ok := typeMap[DPHtlcMinimumMsat]; ok && val == nil {
106✔
NEW
253
                dp.HtlcMinimum = fn.Some(MilliSatoshi(htlcMinScratch))
×
NEW
254
        }
×
255
        if val, ok := typeMap[DPChannelReserveSatoshis]; ok && val == nil {
163✔
256
                dp.ChannelReserve = fn.Some(btcutil.Amount(reserveScratch))
57✔
257
        }
57✔
258
        if val, ok := typeMap[DPToSelfDelay]; ok && val == nil {
162✔
259
                dp.CsvDelay = fn.Some(csvDelayScratch)
56✔
260
        }
56✔
261
        if val, ok := typeMap[DPMaxAcceptedHtlcs]; ok && val == nil {
168✔
262
                dp.MaxAcceptedHTLCs = fn.Some(maxHtlcsScratch)
62✔
263
        }
62✔
264
        if val, ok := typeMap[DPChannelType]; ok && val == nil {
155✔
265
                dp.ChannelType = fn.Some(chanTypeScratch)
49✔
266
        }
49✔
267

268
        if len(tlvRecords) != 0 {
208✔
269
                dp.ExtraData = tlvRecords
102✔
270
        }
102✔
271

272
        return nil
106✔
273
}
274

275
// MsgType returns the MessageType code which uniquely identifies this message
276
// as a DynPropose on the wire.
277
//
278
// This is part of the lnwire.Message interface.
279
func (dp *DynPropose) MsgType() MessageType {
103✔
280
        return MsgDynPropose
103✔
281
}
103✔
282

283
// SerializeTlvData takes just the TLV data of DynPropose (which covers all of
284
// the parameters on deck for changing) and serializes just this component. The
285
// main purpose of this is to make it easier to validate the DynAck signature.
NEW
286
func (dp *DynPropose) SerializeTlvData() ([]byte, error) {
×
NEW
287
        var tlvRecords []tlv.Record
×
NEW
288
        dp.DustLimit.WhenSome(func(dl btcutil.Amount) {
×
NEW
289
                protoSats := uint64(dl)
×
NEW
290
                tlvRecords = append(
×
NEW
291
                        tlvRecords, tlv.MakePrimitiveRecord(
×
NEW
292
                                DPDustLimitSatoshis, &protoSats,
×
NEW
293
                        ),
×
NEW
294
                )
×
NEW
295
        })
×
NEW
296
        dp.MaxValueInFlight.WhenSome(func(max MilliSatoshi) {
×
NEW
297
                protoSats := uint64(max)
×
NEW
298
                tlvRecords = append(
×
NEW
299
                        tlvRecords, tlv.MakePrimitiveRecord(
×
NEW
300
                                DPMaxHtlcValueInFlightMsat, &protoSats,
×
NEW
301
                        ),
×
NEW
302
                )
×
NEW
303
        })
×
NEW
304
        dp.HtlcMinimum.WhenSome(func(min MilliSatoshi) {
×
NEW
305
                protoSats := uint64(min)
×
NEW
306
                tlvRecords = append(
×
NEW
307
                        tlvRecords, tlv.MakePrimitiveRecord(
×
NEW
308
                                DPHtlcMinimumMsat, &protoSats,
×
NEW
309
                        ),
×
NEW
310
                )
×
NEW
311
        })
×
NEW
312
        dp.ChannelReserve.WhenSome(func(min btcutil.Amount) {
×
NEW
313
                channelReserve := uint64(min)
×
NEW
314
                tlvRecords = append(
×
NEW
315
                        tlvRecords, tlv.MakePrimitiveRecord(
×
NEW
316
                                DPChannelReserveSatoshis, &channelReserve,
×
NEW
317
                        ),
×
NEW
318
                )
×
NEW
319
        })
×
NEW
320
        dp.CsvDelay.WhenSome(func(wait uint16) {
×
NEW
321
                tlvRecords = append(
×
NEW
322
                        tlvRecords, tlv.MakePrimitiveRecord(
×
NEW
323
                                DPToSelfDelay, &wait,
×
NEW
324
                        ),
×
NEW
325
                )
×
NEW
326
        })
×
NEW
327
        dp.MaxAcceptedHTLCs.WhenSome(func(max uint16) {
×
NEW
328
                tlvRecords = append(
×
NEW
329
                        tlvRecords, tlv.MakePrimitiveRecord(
×
NEW
330
                                DPMaxAcceptedHtlcs, &max,
×
NEW
331
                        ),
×
NEW
332
                )
×
NEW
333
        })
×
NEW
334
        dp.ChannelType.WhenSome(func(ty ChannelType) {
×
NEW
335
                tlvRecords = append(
×
NEW
336
                        tlvRecords, tlv.MakeDynamicRecord(
×
NEW
337
                                DPChannelType, &ty,
×
NEW
338
                                ty.featureBitLen,
×
NEW
339
                                channelTypeEncoder, channelTypeDecoder,
×
NEW
340
                        ),
×
NEW
341
                )
×
NEW
342
        })
×
NEW
343
        tlv.SortRecords(tlvRecords)
×
NEW
344

×
NEW
345
        tlvStream, err := tlv.NewStream(tlvRecords...)
×
NEW
346
        if err != nil {
×
NEW
347
                return nil, err
×
NEW
348
        }
×
349

NEW
350
        var outBuf bytes.Buffer
×
NEW
351
        err = tlvStream.Encode(&outBuf)
×
NEW
352
        if err != nil {
×
NEW
353
                return nil, err
×
NEW
354
        }
×
355

NEW
356
        return outBuf.Bytes(), nil
×
357
}
358

359
// Accept provides a convenience method for taking a DynPropose and issuing a
360
// corresponding DynAck using the provided MessageSignerRing.
361
func (dp *DynPropose) Accept(nextHeight uint64,
NEW
362
        signer keychain.MessageSignerRing) (DynAck, error) {
×
NEW
363

×
NEW
364
        var msg bytes.Buffer
×
NEW
365
        err := WriteChannelID(&msg, dp.ChanID)
×
NEW
366
        if err != nil {
×
NEW
367
                return DynAck{}, err
×
NEW
368
        }
×
369

NEW
370
        err = WriteElement(&msg, nextHeight)
×
NEW
371
        if err != nil {
×
NEW
372
                return DynAck{}, err
×
NEW
373
        }
×
374

NEW
375
        tlvData, err := dp.SerializeTlvData()
×
NEW
376
        if err != nil {
×
NEW
377
                return DynAck{}, err
×
NEW
378
        }
×
379

NEW
380
        msg.Write(tlvData)
×
NEW
381

×
NEW
382
        nodeKeyLoc := keychain.KeyLocator{
×
NEW
383
                Family: keychain.KeyFamilyNodeKey,
×
NEW
384
                Index:  0,
×
NEW
385
        }
×
NEW
386

×
NEW
387
        rawSig, err := signer.SignMessageCompact(nodeKeyLoc, msg.Bytes(), false)
×
NEW
388
        if err != nil {
×
NEW
389
                return DynAck{}, err
×
NEW
390
        }
×
391

NEW
392
        var sigFixed [64]byte
×
NEW
393
        copy(sigFixed[:], rawSig[0:64])
×
NEW
394

×
NEW
395
        sig := Sig{
×
NEW
396
                bytes:   sigFixed,
×
NEW
397
                sigType: sigTypeECDSA,
×
NEW
398
        }
×
NEW
399

×
NEW
400
        return DynAck{
×
NEW
401
                ChanID: dp.ChanID,
×
NEW
402
                Sig:    sig,
×
NEW
403
        }, nil
×
404
}
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