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

lightningnetwork / lnd / 11216766535

07 Oct 2024 01:37PM UTC coverage: 57.817% (-1.0%) from 58.817%
11216766535

Pull #9148

github

ProofOfKeags
lnwire: remove kickoff feerate from propose/commit
Pull Request #9148: DynComms [2/n]: lnwire: add authenticated wire messages for Dyn*

571 of 879 new or added lines in 16 files covered. (64.96%)

23253 existing lines in 251 files now uncovered.

99022 of 171268 relevant lines covered (57.82%)

38420.67 hits per line

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

56.34
/lnwire/dyn_propose.go
1
package lnwire
2

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

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

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

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

23
        // DPChannelReserveSatoshis is the TLV type number that identifies the
24
        // for DynPropose.ChannelReserve.
25
        DPChannelReserveSatoshis tlv.Type = 2
26

27
        // DPToSelfDelay is the TLV type number that identifies the record for
28
        // DynPropose.CsvDelay.
29
        DPToSelfDelay tlv.Type = 3
30

31
        // DPMaxAcceptedHtlcs is the TLV type number that identifies the record
32
        // for DynPropose.MaxAcceptedHTLCs.
33
        DPMaxAcceptedHtlcs tlv.Type = 4
34

35
        // DPFundingPubkey is the TLV type number that identifies the record for
36
        // DynPropose.FundingKey.
37
        DPFundingPubkey tlv.Type = 5
38

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

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

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

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

59
        // ChannelReserve, if not nil, proposes a change to the
60
        // channel_reserve_satoshis requirement of the recipient.
61
        ChannelReserve fn.Option[btcutil.Amount]
62

63
        // CsvDelay, if not nil, proposes a change to the to_self_delay
64
        // requirement of the recipient.
65
        CsvDelay fn.Option[uint16]
66

67
        // MaxAcceptedHTLCs, if not nil, proposes a change to the
68
        // max_accepted_htlcs limit of the sender.
69
        MaxAcceptedHTLCs fn.Option[uint16]
70

71
        // FundingKey, if not nil, proposes a change to the funding_pubkey
72
        // parameter of the sender.
73
        FundingKey fn.Option[btcec.PublicKey]
74

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

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

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

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

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

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

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

171
        return WriteBytes(w, dp.ExtraData)
102✔
172
}
173

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

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

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

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

205✔
202
        var reserveScratch uint64
205✔
203
        reserve := tlv.MakePrimitiveRecord(
205✔
204
                DPChannelReserveSatoshis, &reserveScratch,
205✔
205
        )
205✔
206

205✔
207
        var csvDelayScratch uint16
205✔
208
        csvDelay := tlv.MakePrimitiveRecord(DPToSelfDelay, &csvDelayScratch)
205✔
209

205✔
210
        var maxHtlcsScratch uint16
205✔
211
        maxHtlcs := tlv.MakePrimitiveRecord(
205✔
212
                DPMaxAcceptedHtlcs, &maxHtlcsScratch,
205✔
213
        )
205✔
214

205✔
215
        var fundingKeyScratch *btcec.PublicKey
205✔
216
        fundingKey := tlv.MakePrimitiveRecord(
205✔
217
                DPFundingPubkey, &fundingKeyScratch,
205✔
218
        )
205✔
219

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

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

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

240
        typeMap, err := tlvStream.DecodeWithParsedTypesP2P(extraBytesReader)
205✔
241
        if err != nil {
306✔
242
                return err
101✔
243
        }
101✔
244

245
        // Check the results of the TLV Stream decoding and appropriately set
246
        // message fields.
247
        if val, ok := typeMap[DPDustLimitSatoshis]; ok && val == nil {
156✔
248
                dp.DustLimit = fn.Some(btcutil.Amount(dustLimitScratch))
52✔
249
        }
52✔
250
        if val, ok := typeMap[DPMaxHtlcValueInFlightMsat]; ok && val == nil {
153✔
251
                dp.MaxValueInFlight = fn.Some(MilliSatoshi(maxValueScratch))
49✔
252
        }
49✔
253
        if val, ok := typeMap[DPChannelReserveSatoshis]; ok && val == nil {
158✔
254
                dp.ChannelReserve = fn.Some(btcutil.Amount(reserveScratch))
54✔
255
        }
54✔
256
        if val, ok := typeMap[DPToSelfDelay]; ok && val == nil {
149✔
257
                dp.CsvDelay = fn.Some(csvDelayScratch)
45✔
258
        }
45✔
259
        if val, ok := typeMap[DPMaxAcceptedHtlcs]; ok && val == nil {
155✔
260
                dp.MaxAcceptedHTLCs = fn.Some(maxHtlcsScratch)
51✔
261
        }
51✔
262
        if val, ok := typeMap[DPFundingPubkey]; ok && val == nil {
154✔
263
                dp.FundingKey = fn.Some(*fundingKeyScratch)
50✔
264
        }
50✔
265
        if val, ok := typeMap[DPChannelType]; ok && val == nil {
150✔
266
                dp.ChannelType = fn.Some(chanTypeScratch)
46✔
267
        }
46✔
268

269
        if len(tlvRecords) != 0 {
205✔
270
                dp.ExtraData = tlvRecords
101✔
271
        }
101✔
272

273
        return nil
104✔
274
}
275

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

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

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

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

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

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

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

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

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

NEW
381
        msg.Write(tlvData)
×
NEW
382

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

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

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

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

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