• 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

41.4
/lnwire/channel_update.go
1
package lnwire
2

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

8
        "github.com/btcsuite/btcd/chaincfg/chainhash"
9
)
10

11
// ChanUpdateMsgFlags is a bitfield that signals whether optional fields are
12
// present in the ChannelUpdate.
13
type ChanUpdateMsgFlags uint8
14

15
const (
16
        // ChanUpdateRequiredMaxHtlc is a bit that indicates whether the
17
        // required htlc_maximum_msat field is present in this ChannelUpdate.
18
        ChanUpdateRequiredMaxHtlc ChanUpdateMsgFlags = 1 << iota
19
)
20

21
// String returns the bitfield flags as a string.
22
func (c ChanUpdateMsgFlags) String() string {
3✔
23
        return fmt.Sprintf("%08b", c)
3✔
24
}
3✔
25

26
// HasMaxHtlc returns true if the htlc_maximum_msat option bit is set in the
27
// message flags.
28
func (c ChanUpdateMsgFlags) HasMaxHtlc() bool {
3✔
29
        return c&ChanUpdateRequiredMaxHtlc != 0
3✔
30
}
3✔
31

32
// ChanUpdateChanFlags is a bitfield that signals various options concerning a
33
// particular channel edge. Each bit is to be examined in order to determine
34
// how the ChannelUpdate message is to be interpreted.
35
type ChanUpdateChanFlags uint8
36

37
const (
38
        // ChanUpdateDirection indicates the direction of a channel update. If
39
        // this bit is set to 0 if Node1 (the node with the "smaller" Node ID)
40
        // is updating the channel, and to 1 otherwise.
41
        ChanUpdateDirection ChanUpdateChanFlags = 1 << iota
42

43
        // ChanUpdateDisabled is a bit that indicates if the channel edge
44
        // selected by the ChanUpdateDirection bit is to be treated as being
45
        // disabled.
46
        ChanUpdateDisabled
47
)
48

49
// IsDisabled determines whether the channel flags has the disabled bit set.
50
func (c ChanUpdateChanFlags) IsDisabled() bool {
3✔
51
        return c&ChanUpdateDisabled == ChanUpdateDisabled
3✔
52
}
3✔
53

54
// String returns the bitfield flags as a string.
55
func (c ChanUpdateChanFlags) String() string {
3✔
56
        return fmt.Sprintf("%08b", c)
3✔
57
}
3✔
58

59
// ChannelUpdate1 message is used after channel has been initially announced.
60
// Each side independently announces its fees and minimum expiry for HTLCs and
61
// other parameters. Also this message is used to redeclare initially set
62
// channel parameters.
63
type ChannelUpdate1 struct {
64
        // Signature is used to validate the announced data and prove the
65
        // ownership of node id.
66
        Signature Sig
67

68
        // ChainHash denotes the target chain that this channel was opened
69
        // within. This value should be the genesis hash of the target chain.
70
        // Along with the short channel ID, this uniquely identifies the
71
        // channel globally in a blockchain.
72
        ChainHash chainhash.Hash
73

74
        // ShortChannelID is the unique description of the funding transaction.
75
        ShortChannelID ShortChannelID
76

77
        // Timestamp allows ordering in the case of multiple announcements. We
78
        // should ignore the message if timestamp is not greater than
79
        // the last-received.
80
        Timestamp uint32
81

82
        // MessageFlags is a bitfield that describes whether optional fields
83
        // are present in this update. Currently, the least-significant bit
84
        // must be set to 1 if the optional field MaxHtlc is present.
85
        MessageFlags ChanUpdateMsgFlags
86

87
        // ChannelFlags is a bitfield that describes additional meta-data
88
        // concerning how the update is to be interpreted. Currently, the
89
        // least-significant bit must be set to 0 if the creating node
90
        // corresponds to the first node in the previously sent channel
91
        // announcement and 1 otherwise. If the second bit is set, then the
92
        // channel is set to be disabled.
93
        ChannelFlags ChanUpdateChanFlags
94

95
        // TimeLockDelta is the minimum number of blocks this node requires to
96
        // be added to the expiry of HTLCs. This is a security parameter
97
        // determined by the node operator. This value represents the required
98
        // gap between the time locks of the incoming and outgoing HTLC's set
99
        // to this node.
100
        TimeLockDelta uint16
101

102
        // HtlcMinimumMsat is the minimum HTLC value which will be accepted.
103
        HtlcMinimumMsat MilliSatoshi
104

105
        // BaseFee is the base fee that must be used for incoming HTLC's to
106
        // this particular channel. This value will be tacked onto the required
107
        // for a payment independent of the size of the payment.
108
        BaseFee uint32
109

110
        // FeeRate is the fee rate that will be charged per millionth of a
111
        // satoshi.
112
        FeeRate uint32
113

114
        // HtlcMaximumMsat is the maximum HTLC value which will be accepted.
115
        HtlcMaximumMsat MilliSatoshi
116

117
        // ExtraData is the set of data that was appended to this message to
118
        // fill out the full maximum transport message size. These fields can
119
        // be used to specify optional data such as custom TLV fields.
120
        ExtraOpaqueData ExtraOpaqueData
121
}
122

123
// A compile time check to ensure ChannelUpdate implements the lnwire.Message
124
// interface.
125
var _ Message = (*ChannelUpdate1)(nil)
126

127
// Decode deserializes a serialized ChannelUpdate stored in the passed
128
// io.Reader observing the specified protocol version.
129
//
130
// This is part of the lnwire.Message interface.
131
func (a *ChannelUpdate1) Decode(r io.Reader, pver uint32) error {
3✔
132
        err := ReadElements(r,
3✔
133
                &a.Signature,
3✔
134
                a.ChainHash[:],
3✔
135
                &a.ShortChannelID,
3✔
136
                &a.Timestamp,
3✔
137
                &a.MessageFlags,
3✔
138
                &a.ChannelFlags,
3✔
139
                &a.TimeLockDelta,
3✔
140
                &a.HtlcMinimumMsat,
3✔
141
                &a.BaseFee,
3✔
142
                &a.FeeRate,
3✔
143
        )
3✔
144
        if err != nil {
3✔
UNCOV
145
                return err
×
UNCOV
146
        }
×
147

148
        // Now check whether the max HTLC field is present and read it if so.
149
        if a.MessageFlags.HasMaxHtlc() {
6✔
150
                if err := ReadElements(r, &a.HtlcMaximumMsat); err != nil {
3✔
UNCOV
151
                        return err
×
UNCOV
152
                }
×
153
        }
154

155
        return a.ExtraOpaqueData.Decode(r)
3✔
156
}
157

158
// Encode serializes the target ChannelUpdate into the passed io.Writer
159
// observing the protocol version specified.
160
//
161
// This is part of the lnwire.Message interface.
162
func (a *ChannelUpdate1) Encode(w *bytes.Buffer, pver uint32) error {
3✔
163
        if err := WriteSig(w, a.Signature); err != nil {
3✔
164
                return err
×
165
        }
×
166

167
        if err := WriteBytes(w, a.ChainHash[:]); err != nil {
3✔
168
                return err
×
169
        }
×
170

171
        if err := WriteShortChannelID(w, a.ShortChannelID); err != nil {
3✔
172
                return err
×
173
        }
×
174

175
        if err := WriteUint32(w, a.Timestamp); err != nil {
3✔
176
                return err
×
177
        }
×
178

179
        if err := WriteChanUpdateMsgFlags(w, a.MessageFlags); err != nil {
3✔
180
                return err
×
181
        }
×
182

183
        if err := WriteChanUpdateChanFlags(w, a.ChannelFlags); err != nil {
3✔
184
                return err
×
185
        }
×
186

187
        if err := WriteUint16(w, a.TimeLockDelta); err != nil {
3✔
188
                return err
×
189
        }
×
190

191
        if err := WriteMilliSatoshi(w, a.HtlcMinimumMsat); err != nil {
3✔
192
                return err
×
193
        }
×
194

195
        if err := WriteUint32(w, a.BaseFee); err != nil {
3✔
196
                return err
×
197
        }
×
198

199
        if err := WriteUint32(w, a.FeeRate); err != nil {
3✔
200
                return err
×
201
        }
×
202

203
        // Now append optional fields if they are set. Currently, the only
204
        // optional field is max HTLC.
205
        if a.MessageFlags.HasMaxHtlc() {
6✔
206
                err := WriteMilliSatoshi(w, a.HtlcMaximumMsat)
3✔
207
                if err != nil {
3✔
208
                        return err
×
209
                }
×
210
        }
211

212
        // Finally, append any extra opaque data.
213
        return WriteBytes(w, a.ExtraOpaqueData)
3✔
214
}
215

216
// MsgType returns the integer uniquely identifying this message type on the
217
// wire.
218
//
219
// This is part of the lnwire.Message interface.
220
func (a *ChannelUpdate1) MsgType() MessageType {
3✔
221
        return MsgChannelUpdate
3✔
222
}
3✔
223

224
// DataToSign is used to retrieve part of the announcement message which should
225
// be signed.
226
func (a *ChannelUpdate1) DataToSign() ([]byte, error) {
3✔
227
        // We should not include the signatures itself.
3✔
228
        b := make([]byte, 0, MaxMsgBody)
3✔
229
        buf := bytes.NewBuffer(b)
3✔
230
        if err := WriteBytes(buf, a.ChainHash[:]); err != nil {
3✔
231
                return nil, err
×
232
        }
×
233

234
        if err := WriteShortChannelID(buf, a.ShortChannelID); err != nil {
3✔
235
                return nil, err
×
236
        }
×
237

238
        if err := WriteUint32(buf, a.Timestamp); err != nil {
3✔
239
                return nil, err
×
240
        }
×
241

242
        if err := WriteChanUpdateMsgFlags(buf, a.MessageFlags); err != nil {
3✔
243
                return nil, err
×
244
        }
×
245

246
        if err := WriteChanUpdateChanFlags(buf, a.ChannelFlags); err != nil {
3✔
247
                return nil, err
×
248
        }
×
249

250
        if err := WriteUint16(buf, a.TimeLockDelta); err != nil {
3✔
251
                return nil, err
×
252
        }
×
253

254
        if err := WriteMilliSatoshi(buf, a.HtlcMinimumMsat); err != nil {
3✔
255
                return nil, err
×
256
        }
×
257

258
        if err := WriteUint32(buf, a.BaseFee); err != nil {
3✔
259
                return nil, err
×
260
        }
×
261

262
        if err := WriteUint32(buf, a.FeeRate); err != nil {
3✔
263
                return nil, err
×
264
        }
×
265

266
        // Now append optional fields if they are set. Currently, the only
267
        // optional field is max HTLC.
268
        if a.MessageFlags.HasMaxHtlc() {
6✔
269
                err := WriteMilliSatoshi(buf, a.HtlcMaximumMsat)
3✔
270
                if err != nil {
3✔
271
                        return nil, err
×
272
                }
×
273
        }
274

275
        // Finally, append any extra opaque data.
276
        if err := WriteBytes(buf, a.ExtraOpaqueData); err != nil {
3✔
277
                return nil, err
×
278
        }
×
279

280
        return buf.Bytes(), nil
3✔
281
}
282

283
// SCID returns the ShortChannelID of the channel that the update applies to.
284
//
285
// NOTE: this is part of the ChannelUpdate interface.
286
func (a *ChannelUpdate1) SCID() ShortChannelID {
×
287
        return a.ShortChannelID
×
288
}
×
289

290
// IsNode1 is true if the update was produced by node 1 of the channel peers.
291
// Node 1 is the node with the lexicographically smaller public key.
292
//
293
// NOTE: this is part of the ChannelUpdate interface.
294
func (a *ChannelUpdate1) IsNode1() bool {
×
295
        return a.ChannelFlags&ChanUpdateDirection == 0
×
296
}
×
297

298
// IsDisabled is true if the update is announcing that the channel should be
299
// considered disabled.
300
//
301
// NOTE: this is part of the ChannelUpdate interface.
302
func (a *ChannelUpdate1) IsDisabled() bool {
×
303
        return a.ChannelFlags&ChanUpdateDisabled == ChanUpdateDisabled
×
304
}
×
305

306
// GetChainHash returns the hash of the chain that the message is referring to.
307
//
308
// NOTE: this is part of the ChannelUpdate interface.
309
func (a *ChannelUpdate1) GetChainHash() chainhash.Hash {
×
310
        return a.ChainHash
×
311
}
×
312

313
// ForwardingPolicy returns the set of forwarding constraints of the update.
314
//
315
// NOTE: this is part of the ChannelUpdate interface.
316
func (a *ChannelUpdate1) ForwardingPolicy() *ForwardingPolicy {
×
317
        return &ForwardingPolicy{
×
318
                TimeLockDelta: a.TimeLockDelta,
×
319
                BaseFee:       MilliSatoshi(a.BaseFee),
×
320
                FeeRate:       MilliSatoshi(a.FeeRate),
×
321
                MinHTLC:       a.HtlcMinimumMsat,
×
322
                HasMaxHTLC:    a.MessageFlags.HasMaxHtlc(),
×
323
                MaxHTLC:       a.HtlcMaximumMsat,
×
324
        }
×
325
}
×
326

327
// CmpAge can be used to determine if the update is older or newer than the
328
// passed update. It returns 1 if this update is newer, -1 if it is older, and
329
// 0 if they are the same age.
330
//
331
// NOTE: this is part of the ChannelUpdate interface.
332
func (a *ChannelUpdate1) CmpAge(update ChannelUpdate) (CompareResult, error) {
×
333
        other, ok := update.(*ChannelUpdate1)
×
334
        if !ok {
×
335
                return 0, fmt.Errorf("expected *ChannelUpdate1, got: %T",
×
336
                        update)
×
337
        }
×
338

339
        switch {
×
340
        case a.Timestamp > other.Timestamp:
×
341
                return GreaterThan, nil
×
342
        case a.Timestamp < other.Timestamp:
×
343
                return LessThan, nil
×
344
        default:
×
345
                return EqualTo, nil
×
346
        }
347
}
348

349
// SetDisabledFlag can be used to adjust the disabled flag of an update.
350
//
351
// NOTE: this is part of the ChannelUpdate interface.
352
func (a *ChannelUpdate1) SetDisabledFlag(disabled bool) {
×
353
        if disabled {
×
354
                a.ChannelFlags |= ChanUpdateDisabled
×
355
        } else {
×
356
                a.ChannelFlags &= ^ChanUpdateDisabled
×
357
        }
×
358
}
359

360
// SetSCID can be used to overwrite the SCID of the update.
361
//
362
// NOTE: this is part of the ChannelUpdate interface.
363
func (a *ChannelUpdate1) SetSCID(scid ShortChannelID) {
×
364
        a.ShortChannelID = scid
×
365
}
×
366

367
// A compile time assertion to ensure ChannelUpdate1 implements the
368
// ChannelUpdate interface.
369
var _ ChannelUpdate = (*ChannelUpdate1)(nil)
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