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

lightningnetwork / lnd / 13211764208

08 Feb 2025 03:08AM UTC coverage: 49.288% (-9.5%) from 58.815%
13211764208

Pull #9489

github

calvinrzachman
itest: verify switchrpc server enforces send then track

We prevent the rpc server from allowing onion dispatches for
attempt IDs which have already been tracked by rpc clients.

This helps protect the client from leaking a duplicate onion
attempt. NOTE: This is not the only method for solving this
issue! The issue could be addressed via careful client side
programming which accounts for the uncertainty and async
nature of dispatching onions to a remote process via RPC.
This would require some lnd ChannelRouter changes for how
we intend to use these RPCs though.
Pull Request #9489: multi: add BuildOnion, SendOnion, and TrackOnion RPCs

474 of 990 new or added lines in 11 files covered. (47.88%)

27321 existing lines in 435 files now uncovered.

101192 of 205306 relevant lines covered (49.29%)

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

×
UNCOV
179
        tlvStream, err := tlv.NewStream(tlvRecords...)
×
UNCOV
180
        if err != nil {
×
181
                return err
×
182
        }
×
183

UNCOV
184
        var extraBytesWriter bytes.Buffer
×
UNCOV
185
        if err := tlvStream.Encode(&extraBytesWriter); err != nil {
×
186
                return err
×
187
        }
×
UNCOV
188
        dp.ExtraData = ExtraOpaqueData(extraBytesWriter.Bytes())
×
UNCOV
189

×
UNCOV
190
        if err := WriteChannelID(w, dp.ChanID); err != nil {
×
191
                return err
×
192
        }
×
193

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

UNCOV
198
        return WriteBytes(w, dp.ExtraData)
×
199
}
200

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

212
        // Parse out TLV stream.
UNCOV
213
        var tlvRecords ExtraOpaqueData
×
UNCOV
214
        if err := ReadElements(r, &tlvRecords); err != nil {
×
215
                return err
×
216
        }
×
217

218
        // Prepare receiving buffers to be filled by TLV extraction.
UNCOV
219
        var dustLimitScratch uint64
×
UNCOV
220
        dustLimit := tlv.MakePrimitiveRecord(
×
UNCOV
221
                DPDustLimitSatoshis, &dustLimitScratch,
×
UNCOV
222
        )
×
UNCOV
223

×
UNCOV
224
        var maxValueScratch uint64
×
UNCOV
225
        maxValue := tlv.MakePrimitiveRecord(
×
UNCOV
226
                DPMaxHtlcValueInFlightMsat, &maxValueScratch,
×
UNCOV
227
        )
×
UNCOV
228

×
UNCOV
229
        var reserveScratch uint64
×
UNCOV
230
        reserve := tlv.MakePrimitiveRecord(
×
UNCOV
231
                DPChannelReserveSatoshis, &reserveScratch,
×
UNCOV
232
        )
×
UNCOV
233

×
UNCOV
234
        var csvDelayScratch uint16
×
UNCOV
235
        csvDelay := tlv.MakePrimitiveRecord(DPToSelfDelay, &csvDelayScratch)
×
UNCOV
236

×
UNCOV
237
        var maxHtlcsScratch uint16
×
UNCOV
238
        maxHtlcs := tlv.MakePrimitiveRecord(
×
UNCOV
239
                DPMaxAcceptedHtlcs, &maxHtlcsScratch,
×
UNCOV
240
        )
×
UNCOV
241

×
UNCOV
242
        var fundingKeyScratch *btcec.PublicKey
×
UNCOV
243
        fundingKey := tlv.MakePrimitiveRecord(
×
UNCOV
244
                DPFundingPubkey, &fundingKeyScratch,
×
UNCOV
245
        )
×
UNCOV
246

×
UNCOV
247
        var chanTypeScratch ChannelType
×
UNCOV
248
        chanType := tlv.MakeDynamicRecord(
×
UNCOV
249
                DPChannelType, &chanTypeScratch, chanTypeScratch.featureBitLen,
×
UNCOV
250
                channelTypeEncoder, channelTypeDecoder,
×
UNCOV
251
        )
×
UNCOV
252

×
UNCOV
253
        var kickoffFeerateScratch uint32
×
UNCOV
254
        kickoffFeerate := tlv.MakePrimitiveRecord(
×
UNCOV
255
                DPKickoffFeerate, &kickoffFeerateScratch,
×
UNCOV
256
        )
×
UNCOV
257

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

×
UNCOV
265
        // Read TLV stream into record set.
×
UNCOV
266
        extraBytesReader := bytes.NewReader(tlvRecords)
×
UNCOV
267
        tlvStream, err := tlv.NewStream(records...)
×
UNCOV
268
        if err != nil {
×
269
                return err
×
270
        }
×
271

UNCOV
272
        typeMap, err := tlvStream.DecodeWithParsedTypesP2P(extraBytesReader)
×
UNCOV
273
        if err != nil {
×
UNCOV
274
                return err
×
UNCOV
275
        }
×
276

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

UNCOV
306
        if len(tlvRecords) != 0 {
×
UNCOV
307
                dp.ExtraData = tlvRecords
×
UNCOV
308
        }
×
309

UNCOV
310
        return nil
×
311
}
312

313
// MsgType returns the MessageType code which uniquely identifies this message
314
// as a DynPropose on the wire.
315
//
316
// This is part of the lnwire.Message interface.
UNCOV
317
func (dp *DynPropose) MsgType() MessageType {
×
UNCOV
318
        return MsgDynPropose
×
UNCOV
319
}
×
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