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

lightningnetwork / lnd / 15747152963

19 Jun 2025 01:22AM UTC coverage: 58.151% (-10.1%) from 68.248%
15747152963

push

github

web-flow
Merge pull request #9528 from Roasbeef/res-opt

fn: implement ResultOpt type for operations with optional values

97778 of 168145 relevant lines covered (58.15%)

1.81 hits per line

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

0.0
/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/v2"
10
        "github.com/lightningnetwork/lnd/lnwallet/chainfee"
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
        // DPKickoffFeerate is the TLV type number that identifies the record
44
        // for DynPropose.KickoffFeerate.
45
        DPKickoffFeerate tlv.Type = 7
46
)
47

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

55
        // Initiator is a byte that identifies whether this message was sent as
56
        // the initiator of a dynamic commitment negotiation or the responder
57
        // of a dynamic commitment negotiation. bool true indicates it is the
58
        // initiator
59
        Initiator bool
60

61
        // DustLimit, if not nil, proposes a change to the dust_limit_satoshis
62
        // for the sender's commitment transaction.
63
        DustLimit fn.Option[btcutil.Amount]
64

65
        // MaxValueInFlight, if not nil, proposes a change to the
66
        // max_htlc_value_in_flight_msat limit of the sender.
67
        MaxValueInFlight fn.Option[MilliSatoshi]
68

69
        // ChannelReserve, if not nil, proposes a change to the
70
        // channel_reserve_satoshis requirement of the recipient.
71
        ChannelReserve fn.Option[btcutil.Amount]
72

73
        // CsvDelay, if not nil, proposes a change to the to_self_delay
74
        // requirement of the recipient.
75
        CsvDelay fn.Option[uint16]
76

77
        // MaxAcceptedHTLCs, if not nil, proposes a change to the
78
        // max_accepted_htlcs limit of the sender.
79
        MaxAcceptedHTLCs fn.Option[uint16]
80

81
        // FundingKey, if not nil, proposes a change to the funding_pubkey
82
        // parameter of the sender.
83
        FundingKey fn.Option[btcec.PublicKey]
84

85
        // ChannelType, if not nil, proposes a change to the channel_type
86
        // parameter.
87
        ChannelType fn.Option[ChannelType]
88

89
        // KickoffFeerate proposes the fee rate in satoshis per kw that it
90
        // is offering for a ChannelType conversion that requires a kickoff
91
        // transaction.
92
        KickoffFeerate fn.Option[chainfee.SatPerKWeight]
93

94
        // ExtraData is the set of data that was appended to this message to
95
        // fill out the full maximum transport message size. These fields can
96
        // be used to specify optional data such as custom TLV fields.
97
        //
98
        // NOTE: Since the fields in this structure are part of the TLV stream,
99
        // ExtraData will contain all TLV records _except_ the ones that are
100
        // present in earlier parts of this structure.
101
        ExtraData ExtraOpaqueData
102
}
103

104
// A compile time check to ensure DynPropose implements the lnwire.Message
105
// interface.
106
var _ Message = (*DynPropose)(nil)
107

108
// A compile time check to ensure DynPropose implements the
109
// lnwire.SizeableMessage interface.
110
var _ SizeableMessage = (*DynPropose)(nil)
111

112
// Encode serializes the target DynPropose into the passed io.Writer.
113
// Serialization will observe the rules defined by the passed protocol version.
114
//
115
// This is a part of the lnwire.Message interface.
116
func (dp *DynPropose) Encode(w *bytes.Buffer, _ uint32) error {
×
117
        var tlvRecords []tlv.Record
×
118
        dp.DustLimit.WhenSome(func(dl btcutil.Amount) {
×
119
                protoSats := uint64(dl)
×
120
                tlvRecords = append(
×
121
                        tlvRecords, tlv.MakePrimitiveRecord(
×
122
                                DPDustLimitSatoshis, &protoSats,
×
123
                        ),
×
124
                )
×
125
        })
×
126
        dp.MaxValueInFlight.WhenSome(func(max MilliSatoshi) {
×
127
                protoSats := uint64(max)
×
128
                tlvRecords = append(
×
129
                        tlvRecords, tlv.MakePrimitiveRecord(
×
130
                                DPMaxHtlcValueInFlightMsat, &protoSats,
×
131
                        ),
×
132
                )
×
133
        })
×
134
        dp.ChannelReserve.WhenSome(func(min btcutil.Amount) {
×
135
                channelReserve := uint64(min)
×
136
                tlvRecords = append(
×
137
                        tlvRecords, tlv.MakePrimitiveRecord(
×
138
                                DPChannelReserveSatoshis, &channelReserve,
×
139
                        ),
×
140
                )
×
141
        })
×
142
        dp.CsvDelay.WhenSome(func(wait uint16) {
×
143
                tlvRecords = append(
×
144
                        tlvRecords, tlv.MakePrimitiveRecord(
×
145
                                DPToSelfDelay, &wait,
×
146
                        ),
×
147
                )
×
148
        })
×
149
        dp.MaxAcceptedHTLCs.WhenSome(func(max uint16) {
×
150
                tlvRecords = append(
×
151
                        tlvRecords, tlv.MakePrimitiveRecord(
×
152
                                DPMaxAcceptedHtlcs, &max,
×
153
                        ),
×
154
                )
×
155
        })
×
156
        dp.FundingKey.WhenSome(func(key btcec.PublicKey) {
×
157
                keyScratch := &key
×
158
                tlvRecords = append(
×
159
                        tlvRecords, tlv.MakePrimitiveRecord(
×
160
                                DPFundingPubkey, &keyScratch,
×
161
                        ),
×
162
                )
×
163
        })
×
164
        dp.ChannelType.WhenSome(func(ty ChannelType) {
×
165
                tlvRecords = append(
×
166
                        tlvRecords, tlv.MakeDynamicRecord(
×
167
                                DPChannelType, &ty,
×
168
                                ty.featureBitLen,
×
169
                                channelTypeEncoder, channelTypeDecoder,
×
170
                        ),
×
171
                )
×
172
        })
×
173
        dp.KickoffFeerate.WhenSome(func(kickoffFeerate chainfee.SatPerKWeight) {
×
174
                protoSats := uint32(kickoffFeerate)
×
175
                tlvRecords = append(
×
176
                        tlvRecords, tlv.MakePrimitiveRecord(
×
177
                                DPKickoffFeerate, &protoSats,
×
178
                        ),
×
179
                )
×
180
        })
×
181
        tlv.SortRecords(tlvRecords)
×
182

×
183
        tlvStream, err := tlv.NewStream(tlvRecords...)
×
184
        if err != nil {
×
185
                return err
×
186
        }
×
187

188
        var extraBytesWriter bytes.Buffer
×
189
        if err := tlvStream.Encode(&extraBytesWriter); err != nil {
×
190
                return err
×
191
        }
×
192
        dp.ExtraData = ExtraOpaqueData(extraBytesWriter.Bytes())
×
193

×
194
        if err := WriteChannelID(w, dp.ChanID); err != nil {
×
195
                return err
×
196
        }
×
197

198
        if err := WriteBool(w, dp.Initiator); err != nil {
×
199
                return err
×
200
        }
×
201

202
        return WriteBytes(w, dp.ExtraData)
×
203
}
204

205
// Decode deserializes the serialized DynPropose stored in the passed io.Reader
206
// into the target DynPropose using the deserialization rules defined by the
207
// passed protocol version.
208
//
209
// This is a part of the lnwire.Message interface.
210
func (dp *DynPropose) Decode(r io.Reader, _ uint32) error {
×
211
        // Parse out the only required field.
×
212
        if err := ReadElements(r, &dp.ChanID, &dp.Initiator); err != nil {
×
213
                return err
×
214
        }
×
215

216
        // Parse out TLV stream.
217
        var tlvRecords ExtraOpaqueData
×
218
        if err := ReadElements(r, &tlvRecords); err != nil {
×
219
                return err
×
220
        }
×
221

222
        // Prepare receiving buffers to be filled by TLV extraction.
223
        var dustLimitScratch uint64
×
224
        dustLimit := tlv.MakePrimitiveRecord(
×
225
                DPDustLimitSatoshis, &dustLimitScratch,
×
226
        )
×
227

×
228
        var maxValueScratch uint64
×
229
        maxValue := tlv.MakePrimitiveRecord(
×
230
                DPMaxHtlcValueInFlightMsat, &maxValueScratch,
×
231
        )
×
232

×
233
        var reserveScratch uint64
×
234
        reserve := tlv.MakePrimitiveRecord(
×
235
                DPChannelReserveSatoshis, &reserveScratch,
×
236
        )
×
237

×
238
        var csvDelayScratch uint16
×
239
        csvDelay := tlv.MakePrimitiveRecord(DPToSelfDelay, &csvDelayScratch)
×
240

×
241
        var maxHtlcsScratch uint16
×
242
        maxHtlcs := tlv.MakePrimitiveRecord(
×
243
                DPMaxAcceptedHtlcs, &maxHtlcsScratch,
×
244
        )
×
245

×
246
        var fundingKeyScratch *btcec.PublicKey
×
247
        fundingKey := tlv.MakePrimitiveRecord(
×
248
                DPFundingPubkey, &fundingKeyScratch,
×
249
        )
×
250

×
251
        var chanTypeScratch ChannelType
×
252
        chanType := tlv.MakeDynamicRecord(
×
253
                DPChannelType, &chanTypeScratch, chanTypeScratch.featureBitLen,
×
254
                channelTypeEncoder, channelTypeDecoder,
×
255
        )
×
256

×
257
        var kickoffFeerateScratch uint32
×
258
        kickoffFeerate := tlv.MakePrimitiveRecord(
×
259
                DPKickoffFeerate, &kickoffFeerateScratch,
×
260
        )
×
261

×
262
        // Create set of Records to read TLV bytestream into.
×
263
        records := []tlv.Record{
×
264
                dustLimit, maxValue, reserve, csvDelay, maxHtlcs, fundingKey,
×
265
                chanType, kickoffFeerate,
×
266
        }
×
267
        tlv.SortRecords(records)
×
268

×
269
        // Read TLV stream into record set.
×
270
        extraBytesReader := bytes.NewReader(tlvRecords)
×
271
        tlvStream, err := tlv.NewStream(records...)
×
272
        if err != nil {
×
273
                return err
×
274
        }
×
275

276
        typeMap, err := tlvStream.DecodeWithParsedTypesP2P(extraBytesReader)
×
277
        if err != nil {
×
278
                return err
×
279
        }
×
280

281
        // Check the results of the TLV Stream decoding and appropriately set
282
        // message fields.
283
        if val, ok := typeMap[DPDustLimitSatoshis]; ok && val == nil {
×
284
                dp.DustLimit = fn.Some(btcutil.Amount(dustLimitScratch))
×
285
        }
×
286
        if val, ok := typeMap[DPMaxHtlcValueInFlightMsat]; ok && val == nil {
×
287
                dp.MaxValueInFlight = fn.Some(MilliSatoshi(maxValueScratch))
×
288
        }
×
289
        if val, ok := typeMap[DPChannelReserveSatoshis]; ok && val == nil {
×
290
                dp.ChannelReserve = fn.Some(btcutil.Amount(reserveScratch))
×
291
        }
×
292
        if val, ok := typeMap[DPToSelfDelay]; ok && val == nil {
×
293
                dp.CsvDelay = fn.Some(csvDelayScratch)
×
294
        }
×
295
        if val, ok := typeMap[DPMaxAcceptedHtlcs]; ok && val == nil {
×
296
                dp.MaxAcceptedHTLCs = fn.Some(maxHtlcsScratch)
×
297
        }
×
298
        if val, ok := typeMap[DPFundingPubkey]; ok && val == nil {
×
299
                dp.FundingKey = fn.Some(*fundingKeyScratch)
×
300
        }
×
301
        if val, ok := typeMap[DPChannelType]; ok && val == nil {
×
302
                dp.ChannelType = fn.Some(chanTypeScratch)
×
303
        }
×
304
        if val, ok := typeMap[DPKickoffFeerate]; ok && val == nil {
×
305
                dp.KickoffFeerate = fn.Some(
×
306
                        chainfee.SatPerKWeight(kickoffFeerateScratch),
×
307
                )
×
308
        }
×
309

310
        if len(tlvRecords) != 0 {
×
311
                dp.ExtraData = tlvRecords
×
312
        }
×
313

314
        return nil
×
315
}
316

317
// MsgType returns the MessageType code which uniquely identifies this message
318
// as a DynPropose on the wire.
319
//
320
// This is part of the lnwire.Message interface.
321
func (dp *DynPropose) MsgType() MessageType {
×
322
        return MsgDynPropose
×
323
}
×
324

325
// SerializedSize returns the serialized size of the message in bytes.
326
//
327
// This is part of the lnwire.SizeableMessage interface.
328
func (dp *DynPropose) SerializedSize() (uint32, error) {
×
329
        return MessageSerializedSize(dp)
×
330
}
×
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