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

lightningnetwork / lnd / 16807123789

07 Aug 2025 02:18PM UTC coverage: 54.85% (-12.1%) from 66.947%
16807123789

Pull #10140

github

web-flow
Merge d256dafec into 2269859d9
Pull Request #10140: [2/3] lnwire: fix encoding customized TLV records

192 of 207 new or added lines in 9 files covered. (92.75%)

23859 existing lines in 288 files now uncovered.

108730 of 198233 relevant lines covered (54.85%)

22096.12 hits per line

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

48.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
        "github.com/lightningnetwork/lnd/tlv"
10
)
11

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

118
        // InboundFee is an optional TLV record that contains the fee
119
        // information for incoming HTLCs.
120
        InboundFee tlv.OptionalRecordT[tlv.TlvType55555, Fee]
121

122
        // ExtraData is the set of data that was appended to this message to
123
        // fill out the full maximum transport message size. These fields can
124
        // be used to specify optional data such as custom TLV fields.
125
        ExtraOpaqueData ExtraOpaqueData
126
}
127

128
// A compile time check to ensure ChannelUpdate implements the lnwire.Message
129
// interface.
130
var _ Message = (*ChannelUpdate1)(nil)
131

132
// A compile time check to ensure ChannelUpdate1 implements the
133
// lnwire.SizeableMessage interface.
134
var _ SizeableMessage = (*ChannelUpdate1)(nil)
135

136
// Decode deserializes a serialized ChannelUpdate stored in the passed
137
// io.Reader observing the specified protocol version.
138
//
139
// This is part of the lnwire.Message interface.
140
func (a *ChannelUpdate1) Decode(r io.Reader, _ uint32) error {
398✔
141
        err := ReadElements(r,
398✔
142
                &a.Signature,
398✔
143
                a.ChainHash[:],
398✔
144
                &a.ShortChannelID,
398✔
145
                &a.Timestamp,
398✔
146
                &a.MessageFlags,
398✔
147
                &a.ChannelFlags,
398✔
148
                &a.TimeLockDelta,
398✔
149
                &a.HtlcMinimumMsat,
398✔
150
                &a.BaseFee,
398✔
151
                &a.FeeRate,
398✔
152
        )
398✔
153
        if err != nil {
469✔
154
                return err
71✔
155
        }
71✔
156

157
        // Now check whether the max HTLC field is present and read it if so.
158
        if a.MessageFlags.HasMaxHtlc() {
467✔
159
                if err := ReadElements(r, &a.HtlcMaximumMsat); err != nil {
147✔
160
                        return err
7✔
161
                }
7✔
162
        }
163

164
        var tlvRecords ExtraOpaqueData
320✔
165
        if err := ReadElements(r, &tlvRecords); err != nil {
320✔
166
                return err
×
167
        }
×
168

169
        var inboundFee = a.InboundFee.Zero()
320✔
170
        knownRecords, extraData, err := ParseAndExtractExtraData(
320✔
171
                tlvRecords, &inboundFee,
320✔
172
        )
320✔
173
        if err != nil {
452✔
174
                return err
132✔
175
        }
132✔
176

177
        if _, ok := knownRecords[a.InboundFee.TlvType()]; ok {
236✔
178
                a.InboundFee = tlv.SomeRecordT(inboundFee)
48✔
179
        }
48✔
180

181
        a.ExtraOpaqueData = extraData
188✔
182

188✔
183
        return nil
188✔
184
}
185

186
// Encode serializes the target ChannelUpdate into the passed io.Writer
187
// observing the protocol version specified.
188
//
189
// This is part of the lnwire.Message interface.
190
func (a *ChannelUpdate1) Encode(w *bytes.Buffer, pver uint32) error {
188✔
191
        if err := WriteSig(w, a.Signature); err != nil {
188✔
192
                return err
×
193
        }
×
194

195
        if err := WriteBytes(w, a.ChainHash[:]); err != nil {
188✔
196
                return err
×
197
        }
×
198

199
        if err := WriteShortChannelID(w, a.ShortChannelID); err != nil {
188✔
200
                return err
×
201
        }
×
202

203
        if err := WriteUint32(w, a.Timestamp); err != nil {
188✔
204
                return err
×
205
        }
×
206

207
        if err := WriteChanUpdateMsgFlags(w, a.MessageFlags); err != nil {
188✔
208
                return err
×
209
        }
×
210

211
        if err := WriteChanUpdateChanFlags(w, a.ChannelFlags); err != nil {
188✔
212
                return err
×
213
        }
×
214

215
        if err := WriteUint16(w, a.TimeLockDelta); err != nil {
188✔
216
                return err
×
217
        }
×
218

219
        if err := WriteMilliSatoshi(w, a.HtlcMinimumMsat); err != nil {
188✔
220
                return err
×
221
        }
×
222

223
        if err := WriteUint32(w, a.BaseFee); err != nil {
188✔
224
                return err
×
225
        }
×
226

227
        if err := WriteUint32(w, a.FeeRate); err != nil {
188✔
228
                return err
×
229
        }
×
230

231
        // Now append optional fields if they are set. Currently, the only
232
        // optional field is max HTLC.
233
        if a.MessageFlags.HasMaxHtlc() {
245✔
234
                err := WriteMilliSatoshi(w, a.HtlcMaximumMsat)
57✔
235
                if err != nil {
57✔
236
                        return err
×
237
                }
×
238
        }
239

240
        // Get producers from extra data.
241
        producers, err := a.ExtraOpaqueData.RecordProducers()
188✔
242
        if err != nil {
188✔
NEW
243
                return err
×
NEW
244
        }
×
245

246
        a.InboundFee.WhenSome(func(fee tlv.RecordT[tlv.TlvType55555, Fee]) {
236✔
247
                producers = append(producers, &fee)
48✔
248
        })
48✔
249

250
        // Pack all records into a new TLV stream.
251
        var tlvData ExtraOpaqueData
188✔
252
        err = tlvData.PackRecords(producers...)
188✔
253
        if err != nil {
188✔
254
                return err
×
255
        }
×
256

257
        // Finally, append any extra opaque data.
258
        return WriteBytes(w, tlvData)
188✔
259
}
260

261
// MsgType returns the integer uniquely identifying this message type on the
262
// wire.
263
//
264
// This is part of the lnwire.Message interface.
265
func (a *ChannelUpdate1) MsgType() MessageType {
407✔
266
        return MsgChannelUpdate
407✔
267
}
407✔
268

269
// DataToSign is used to retrieve part of the announcement message which should
270
// be signed.
271
func (a *ChannelUpdate1) DataToSign() ([]byte, error) {
289✔
272
        // We should not include the signatures itself.
289✔
273
        b := make([]byte, 0, MaxMsgBody)
289✔
274
        buf := bytes.NewBuffer(b)
289✔
275
        if err := WriteBytes(buf, a.ChainHash[:]); err != nil {
289✔
276
                return nil, err
×
277
        }
×
278

279
        if err := WriteShortChannelID(buf, a.ShortChannelID); err != nil {
289✔
280
                return nil, err
×
281
        }
×
282

283
        if err := WriteUint32(buf, a.Timestamp); err != nil {
289✔
284
                return nil, err
×
285
        }
×
286

287
        if err := WriteChanUpdateMsgFlags(buf, a.MessageFlags); err != nil {
289✔
288
                return nil, err
×
289
        }
×
290

291
        if err := WriteChanUpdateChanFlags(buf, a.ChannelFlags); err != nil {
289✔
292
                return nil, err
×
293
        }
×
294

295
        if err := WriteUint16(buf, a.TimeLockDelta); err != nil {
289✔
296
                return nil, err
×
297
        }
×
298

299
        if err := WriteMilliSatoshi(buf, a.HtlcMinimumMsat); err != nil {
289✔
300
                return nil, err
×
301
        }
×
302

303
        if err := WriteUint32(buf, a.BaseFee); err != nil {
289✔
304
                return nil, err
×
305
        }
×
306

307
        if err := WriteUint32(buf, a.FeeRate); err != nil {
289✔
308
                return nil, err
×
309
        }
×
310

311
        // Now append optional fields if they are set. Currently, the only
312
        // optional field is max HTLC.
313
        if a.MessageFlags.HasMaxHtlc() {
464✔
314
                err := WriteMilliSatoshi(buf, a.HtlcMaximumMsat)
175✔
315
                if err != nil {
175✔
316
                        return nil, err
×
317
                }
×
318
        }
319

320
        // Finally, append any extra opaque data.
321
        if err := WriteBytes(buf, a.ExtraOpaqueData); err != nil {
289✔
322
                return nil, err
×
323
        }
×
324

325
        return buf.Bytes(), nil
289✔
326
}
327

328
// SCID returns the ShortChannelID of the channel that the update applies to.
329
//
330
// NOTE: this is part of the ChannelUpdate interface.
331
func (a *ChannelUpdate1) SCID() ShortChannelID {
×
332
        return a.ShortChannelID
×
333
}
×
334

335
// IsNode1 is true if the update was produced by node 1 of the channel peers.
336
// Node 1 is the node with the lexicographically smaller public key.
337
//
338
// NOTE: this is part of the ChannelUpdate interface.
339
func (a *ChannelUpdate1) IsNode1() bool {
×
340
        return a.ChannelFlags&ChanUpdateDirection == 0
×
341
}
×
342

343
// IsDisabled is true if the update is announcing that the channel should be
344
// considered disabled.
345
//
346
// NOTE: this is part of the ChannelUpdate interface.
347
func (a *ChannelUpdate1) IsDisabled() bool {
×
348
        return a.ChannelFlags&ChanUpdateDisabled == ChanUpdateDisabled
×
349
}
×
350

351
// GetChainHash returns the hash of the chain that the message is referring to.
352
//
353
// NOTE: this is part of the ChannelUpdate interface.
354
func (a *ChannelUpdate1) GetChainHash() chainhash.Hash {
×
355
        return a.ChainHash
×
356
}
×
357

358
// ForwardingPolicy returns the set of forwarding constraints of the update.
359
//
360
// NOTE: this is part of the ChannelUpdate interface.
361
func (a *ChannelUpdate1) ForwardingPolicy() *ForwardingPolicy {
×
362
        return &ForwardingPolicy{
×
363
                TimeLockDelta: a.TimeLockDelta,
×
364
                BaseFee:       MilliSatoshi(a.BaseFee),
×
365
                FeeRate:       MilliSatoshi(a.FeeRate),
×
366
                MinHTLC:       a.HtlcMinimumMsat,
×
367
                HasMaxHTLC:    a.MessageFlags.HasMaxHtlc(),
×
368
                MaxHTLC:       a.HtlcMaximumMsat,
×
369
        }
×
370
}
×
371

372
// CmpAge can be used to determine if the update is older or newer than the
373
// passed update. It returns 1 if this update is newer, -1 if it is older, and
374
// 0 if they are the same age.
375
//
376
// NOTE: this is part of the ChannelUpdate interface.
377
func (a *ChannelUpdate1) CmpAge(update ChannelUpdate) (CompareResult, error) {
×
378
        other, ok := update.(*ChannelUpdate1)
×
379
        if !ok {
×
380
                return 0, fmt.Errorf("expected *ChannelUpdate1, got: %T",
×
381
                        update)
×
382
        }
×
383

384
        switch {
×
385
        case a.Timestamp > other.Timestamp:
×
386
                return GreaterThan, nil
×
387
        case a.Timestamp < other.Timestamp:
×
388
                return LessThan, nil
×
389
        default:
×
390
                return EqualTo, nil
×
391
        }
392
}
393

394
// SetDisabledFlag can be used to adjust the disabled flag of an update.
395
//
396
// NOTE: this is part of the ChannelUpdate interface.
397
func (a *ChannelUpdate1) SetDisabledFlag(disabled bool) {
×
398
        if disabled {
×
399
                a.ChannelFlags |= ChanUpdateDisabled
×
400
        } else {
×
401
                a.ChannelFlags &= ^ChanUpdateDisabled
×
402
        }
×
403
}
404

405
// SetSCID can be used to overwrite the SCID of the update.
406
//
407
// NOTE: this is part of the ChannelUpdate interface.
408
func (a *ChannelUpdate1) SetSCID(scid ShortChannelID) {
×
409
        a.ShortChannelID = scid
×
410
}
×
411

412
// A compile time assertion to ensure ChannelUpdate1 implements the
413
// ChannelUpdate interface.
414
var _ ChannelUpdate = (*ChannelUpdate1)(nil)
415

416
// SerializedSize returns the serialized size of the message in bytes.
417
//
418
// This is part of the lnwire.SizeableMessage interface.
UNCOV
419
func (a *ChannelUpdate1) SerializedSize() (uint32, error) {
×
UNCOV
420
        return MessageSerializedSize(a)
×
UNCOV
421
}
×
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