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

lightningnetwork / lnd / 15561477203

10 Jun 2025 01:54PM UTC coverage: 58.351% (-10.1%) from 68.487%
15561477203

Pull #9356

github

web-flow
Merge 6440b25db into c6d6d4c0b
Pull Request #9356: lnrpc: add incoming/outgoing channel ids filter to forwarding history request

33 of 36 new or added lines in 2 files covered. (91.67%)

28366 existing lines in 455 files now uncovered.

97715 of 167461 relevant lines covered (58.35%)

1.81 hits per line

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

6.7
/lnwire/channel_update_2.go
1
package lnwire
2

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

8
        "github.com/btcsuite/btcd/chaincfg"
9
        "github.com/btcsuite/btcd/chaincfg/chainhash"
10
        "github.com/lightningnetwork/lnd/tlv"
11
)
12

13
const (
14
        defaultCltvExpiryDelta           = uint16(80)
15
        defaultHtlcMinMsat               = MilliSatoshi(1)
16
        defaultFeeBaseMsat               = uint32(1000)
17
        defaultFeeProportionalMillionths = uint32(1)
18
)
19

20
// ChannelUpdate2 message is used after taproot channel has been initially
21
// announced. Each side independently announces its fees and minimum expiry for
22
// HTLCs and other parameters. This message is also used to redeclare initially
23
// set channel parameters.
24
type ChannelUpdate2 struct {
25
        // Signature is used to validate the announced data and prove the
26
        // ownership of node id.
27
        Signature Sig
28

29
        // ChainHash denotes the target chain that this channel was opened
30
        // within. This value should be the genesis hash of the target chain.
31
        // Along with the short channel ID, this uniquely identifies the
32
        // channel globally in a blockchain.
33
        ChainHash tlv.RecordT[tlv.TlvType0, chainhash.Hash]
34

35
        // ShortChannelID is the unique description of the funding transaction.
36
        ShortChannelID tlv.RecordT[tlv.TlvType2, ShortChannelID]
37

38
        // BlockHeight allows ordering in the case of multiple announcements. We
39
        // should ignore the message if block height is not greater than the
40
        // last-received. The block height must always be greater or equal to
41
        // the block height that the channel funding transaction was confirmed
42
        // in.
43
        BlockHeight tlv.RecordT[tlv.TlvType4, uint32]
44

45
        // DisabledFlags is an optional bitfield that describes various reasons
46
        // that the node is communicating that the channel should be considered
47
        // disabled.
48
        DisabledFlags tlv.RecordT[tlv.TlvType6, ChanUpdateDisableFlags]
49

50
        // SecondPeer is used to indicate which node the channel node has
51
        // created and signed this message. If this field is present, it was
52
        // node 2 otherwise it was node 1.
53
        SecondPeer tlv.OptionalRecordT[tlv.TlvType8, TrueBoolean]
54

55
        // CLTVExpiryDelta is the minimum number of blocks this node requires to
56
        // be added to the expiry of HTLCs. This is a security parameter
57
        // determined by the node operator. This value represents the required
58
        // gap between the time locks of the incoming and outgoing HTLC's set
59
        // to this node.
60
        CLTVExpiryDelta tlv.RecordT[tlv.TlvType10, uint16]
61

62
        // HTLCMinimumMsat is the minimum HTLC value which will be accepted.
63
        HTLCMinimumMsat tlv.RecordT[tlv.TlvType12, MilliSatoshi]
64

65
        // HtlcMaximumMsat is the maximum HTLC value which will be accepted.
66
        HTLCMaximumMsat tlv.RecordT[tlv.TlvType14, MilliSatoshi]
67

68
        // FeeBaseMsat is the base fee that must be used for incoming HTLC's to
69
        // this particular channel. This value will be tacked onto the required
70
        // for a payment independent of the size of the payment.
71
        FeeBaseMsat tlv.RecordT[tlv.TlvType16, uint32]
72

73
        // FeeProportionalMillionths is the fee rate that will be charged per
74
        // millionth of a satoshi.
75
        FeeProportionalMillionths tlv.RecordT[tlv.TlvType18, uint32]
76

77
        // ExtraOpaqueData is the set of data that was appended to this message
78
        // to fill out the full maximum transport message size. These fields can
79
        // be used to specify optional data such as custom TLV fields.
80
        ExtraOpaqueData ExtraOpaqueData
81
}
82

83
// Decode deserializes a serialized ChannelUpdate2 stored in the passed
84
// io.Reader observing the specified protocol version.
85
//
86
// This is part of the lnwire.Message interface.
UNCOV
87
func (c *ChannelUpdate2) Decode(r io.Reader, _ uint32) error {
×
UNCOV
88
        err := ReadElement(r, &c.Signature)
×
UNCOV
89
        if err != nil {
×
UNCOV
90
                return err
×
UNCOV
91
        }
×
UNCOV
92
        c.Signature.ForceSchnorr()
×
UNCOV
93

×
UNCOV
94
        return c.DecodeTLVRecords(r)
×
95
}
96

97
// DecodeTLVRecords decodes only the TLV section of the message.
UNCOV
98
func (c *ChannelUpdate2) DecodeTLVRecords(r io.Reader) error {
×
UNCOV
99
        // First extract into extra opaque data.
×
UNCOV
100
        var tlvRecords ExtraOpaqueData
×
UNCOV
101
        if err := ReadElements(r, &tlvRecords); err != nil {
×
102
                return err
×
103
        }
×
104

UNCOV
105
        var (
×
UNCOV
106
                chainHash  = tlv.ZeroRecordT[tlv.TlvType0, [32]byte]()
×
UNCOV
107
                secondPeer = tlv.ZeroRecordT[tlv.TlvType8, TrueBoolean]()
×
UNCOV
108
        )
×
UNCOV
109
        typeMap, err := tlvRecords.ExtractRecords(
×
UNCOV
110
                &chainHash, &c.ShortChannelID, &c.BlockHeight, &c.DisabledFlags,
×
UNCOV
111
                &secondPeer, &c.CLTVExpiryDelta, &c.HTLCMinimumMsat,
×
UNCOV
112
                &c.HTLCMaximumMsat, &c.FeeBaseMsat,
×
UNCOV
113
                &c.FeeProportionalMillionths,
×
UNCOV
114
        )
×
UNCOV
115
        if err != nil {
×
UNCOV
116
                return err
×
UNCOV
117
        }
×
118

119
        // By default, the chain-hash is the bitcoin mainnet genesis block hash.
UNCOV
120
        c.ChainHash.Val = *chaincfg.MainNetParams.GenesisHash
×
UNCOV
121
        if _, ok := typeMap[c.ChainHash.TlvType()]; ok {
×
UNCOV
122
                c.ChainHash.Val = chainHash.Val
×
UNCOV
123
        }
×
124

125
        // The presence of the second_peer tlv type indicates "true".
UNCOV
126
        if _, ok := typeMap[c.SecondPeer.TlvType()]; ok {
×
UNCOV
127
                c.SecondPeer = tlv.SomeRecordT(secondPeer)
×
UNCOV
128
        }
×
129

130
        // If the CLTV expiry delta was not encoded, then set it to the default
131
        // value.
UNCOV
132
        if _, ok := typeMap[c.CLTVExpiryDelta.TlvType()]; !ok {
×
UNCOV
133
                c.CLTVExpiryDelta.Val = defaultCltvExpiryDelta
×
UNCOV
134
        }
×
135

136
        // If the HTLC Minimum msat was not encoded, then set it to the default
137
        // value.
UNCOV
138
        if _, ok := typeMap[c.HTLCMinimumMsat.TlvType()]; !ok {
×
UNCOV
139
                c.HTLCMinimumMsat.Val = defaultHtlcMinMsat
×
UNCOV
140
        }
×
141

142
        // If the base fee was not encoded, then set it to the default value.
UNCOV
143
        if _, ok := typeMap[c.FeeBaseMsat.TlvType()]; !ok {
×
UNCOV
144
                c.FeeBaseMsat.Val = defaultFeeBaseMsat
×
UNCOV
145
        }
×
146

147
        // If the proportional fee was not encoded, then set it to the default
148
        // value.
UNCOV
149
        if _, ok := typeMap[c.FeeProportionalMillionths.TlvType()]; !ok {
×
UNCOV
150
                c.FeeProportionalMillionths.Val = defaultFeeProportionalMillionths //nolint:ll
×
UNCOV
151
        }
×
152

UNCOV
153
        if len(tlvRecords) != 0 {
×
UNCOV
154
                c.ExtraOpaqueData = tlvRecords
×
UNCOV
155
        }
×
156

UNCOV
157
        return c.ExtraOpaqueData.ValidateTLV()
×
158
}
159

160
// Encode serializes the target ChannelUpdate2 into the passed io.Writer
161
// observing the protocol version specified.
162
//
163
// This is part of the lnwire.Message interface.
UNCOV
164
func (c *ChannelUpdate2) Encode(w *bytes.Buffer, _ uint32) error {
×
UNCOV
165
        _, err := w.Write(c.Signature.RawBytes())
×
UNCOV
166
        if err != nil {
×
167
                return err
×
168
        }
×
169

UNCOV
170
        _, err = c.DataToSign()
×
UNCOV
171
        if err != nil {
×
172
                return err
×
173
        }
×
174

UNCOV
175
        return WriteBytes(w, c.ExtraOpaqueData)
×
176
}
177

178
// DataToSign is used to retrieve part of the announcement message which should
179
// be signed. For the ChannelUpdate2 message, this includes the serialised TLV
180
// records.
UNCOV
181
func (c *ChannelUpdate2) DataToSign() ([]byte, error) {
×
UNCOV
182
        // The chain-hash record is only included if it is _not_ equal to the
×
UNCOV
183
        // bitcoin mainnet genisis block hash.
×
UNCOV
184
        var recordProducers []tlv.RecordProducer
×
UNCOV
185
        if !c.ChainHash.Val.IsEqual(chaincfg.MainNetParams.GenesisHash) {
×
UNCOV
186
                hash := tlv.ZeroRecordT[tlv.TlvType0, [32]byte]()
×
UNCOV
187
                hash.Val = c.ChainHash.Val
×
UNCOV
188

×
UNCOV
189
                recordProducers = append(recordProducers, &hash)
×
UNCOV
190
        }
×
191

UNCOV
192
        recordProducers = append(recordProducers,
×
UNCOV
193
                &c.ShortChannelID, &c.BlockHeight,
×
UNCOV
194
        )
×
UNCOV
195

×
UNCOV
196
        // Only include the disable flags if any bit is set.
×
UNCOV
197
        if !c.DisabledFlags.Val.IsEnabled() {
×
UNCOV
198
                recordProducers = append(recordProducers, &c.DisabledFlags)
×
UNCOV
199
        }
×
200

201
        // We only need to encode the second peer boolean if it is true
UNCOV
202
        c.SecondPeer.WhenSome(func(r tlv.RecordT[tlv.TlvType8, TrueBoolean]) {
×
UNCOV
203
                recordProducers = append(recordProducers, &r)
×
UNCOV
204
        })
×
205

206
        // We only encode the cltv expiry delta if it is not equal to the
207
        // default.
UNCOV
208
        if c.CLTVExpiryDelta.Val != defaultCltvExpiryDelta {
×
UNCOV
209
                recordProducers = append(recordProducers, &c.CLTVExpiryDelta)
×
UNCOV
210
        }
×
211

UNCOV
212
        if c.HTLCMinimumMsat.Val != defaultHtlcMinMsat {
×
UNCOV
213
                recordProducers = append(recordProducers, &c.HTLCMinimumMsat)
×
UNCOV
214
        }
×
215

UNCOV
216
        recordProducers = append(recordProducers, &c.HTLCMaximumMsat)
×
UNCOV
217

×
UNCOV
218
        if c.FeeBaseMsat.Val != defaultFeeBaseMsat {
×
UNCOV
219
                recordProducers = append(recordProducers, &c.FeeBaseMsat)
×
UNCOV
220
        }
×
221

UNCOV
222
        if c.FeeProportionalMillionths.Val != defaultFeeProportionalMillionths {
×
UNCOV
223
                recordProducers = append(
×
UNCOV
224
                        recordProducers, &c.FeeProportionalMillionths,
×
UNCOV
225
                )
×
UNCOV
226
        }
×
227

UNCOV
228
        err := EncodeMessageExtraData(&c.ExtraOpaqueData, recordProducers...)
×
UNCOV
229
        if err != nil {
×
230
                return nil, err
×
231
        }
×
232

UNCOV
233
        return c.ExtraOpaqueData, nil
×
234
}
235

236
// MsgType returns the integer uniquely identifying this message type on the
237
// wire.
238
//
239
// This is part of the lnwire.Message interface.
UNCOV
240
func (c *ChannelUpdate2) MsgType() MessageType {
×
UNCOV
241
        return MsgChannelUpdate2
×
UNCOV
242
}
×
243

244
// SerializedSize returns the serialized size of the message in bytes.
245
//
246
// This is part of the lnwire.SizeableMessage interface.
247
func (c *ChannelUpdate2) SerializedSize() (uint32, error) {
×
248
        return MessageSerializedSize(c)
×
249
}
×
250

251
func (c *ChannelUpdate2) ExtraData() ExtraOpaqueData {
×
252
        return c.ExtraOpaqueData
×
253
}
×
254

255
// A compile time check to ensure ChannelUpdate2 implements the
256
// lnwire.Message interface.
257
var _ Message = (*ChannelUpdate2)(nil)
258

259
// SCID returns the ShortChannelID of the channel that the update applies to.
260
//
261
// NOTE: this is part of the ChannelUpdate interface.
262
func (c *ChannelUpdate2) SCID() ShortChannelID {
×
263
        return c.ShortChannelID.Val
×
264
}
×
265

266
// IsNode1 is true if the update was produced by node 1 of the channel peers.
267
// Node 1 is the node with the lexicographically smaller public key.
268
//
269
// NOTE: this is part of the ChannelUpdate interface.
270
func (c *ChannelUpdate2) IsNode1() bool {
×
271
        return c.SecondPeer.IsNone()
×
272
}
×
273

274
// IsDisabled is true if the update is announcing that the channel should be
275
// considered disabled.
276
//
277
// NOTE: this is part of the ChannelUpdate interface.
278
func (c *ChannelUpdate2) IsDisabled() bool {
×
279
        return !c.DisabledFlags.Val.IsEnabled()
×
280
}
×
281

282
// GetChainHash returns the hash of the chain that the message is referring to.
283
//
284
// NOTE: this is part of the ChannelUpdate interface.
285
func (c *ChannelUpdate2) GetChainHash() chainhash.Hash {
×
286
        return c.ChainHash.Val
×
287
}
×
288

289
// ForwardingPolicy returns the set of forwarding constraints of the update.
290
//
291
// NOTE: this is part of the ChannelUpdate interface.
292
func (c *ChannelUpdate2) ForwardingPolicy() *ForwardingPolicy {
×
293
        return &ForwardingPolicy{
×
294
                TimeLockDelta: c.CLTVExpiryDelta.Val,
×
295
                BaseFee:       MilliSatoshi(c.FeeBaseMsat.Val),
×
296
                FeeRate:       MilliSatoshi(c.FeeProportionalMillionths.Val),
×
297
                MinHTLC:       c.HTLCMinimumMsat.Val,
×
298
                HasMaxHTLC:    true,
×
299
                MaxHTLC:       c.HTLCMaximumMsat.Val,
×
300
        }
×
301
}
×
302

303
// CmpAge can be used to determine if the update is older or newer than the
304
// passed update. It returns 1 if this update is newer, -1 if it is older, and
305
// 0 if they are the same age.
306
//
307
// NOTE: this is part of the ChannelUpdate interface.
308
func (c *ChannelUpdate2) CmpAge(update ChannelUpdate) (CompareResult, error) {
×
309
        other, ok := update.(*ChannelUpdate2)
×
310
        if !ok {
×
311
                return 0, fmt.Errorf("expected *ChannelUpdate2, got: %T",
×
312
                        update)
×
313
        }
×
314

315
        switch {
×
316
        case c.BlockHeight.Val > other.BlockHeight.Val:
×
317
                return GreaterThan, nil
×
318
        case c.BlockHeight.Val < other.BlockHeight.Val:
×
319
                return LessThan, nil
×
320
        default:
×
321
                return EqualTo, nil
×
322
        }
323
}
324

325
// SetDisabledFlag can be used to adjust the disabled flag of an update.
326
//
327
// NOTE: this is part of the ChannelUpdate interface.
328
func (c *ChannelUpdate2) SetDisabledFlag(disabled bool) {
×
329
        if disabled {
×
330
                c.DisabledFlags.Val |= ChanUpdateDisableIncoming
×
331
                c.DisabledFlags.Val |= ChanUpdateDisableOutgoing
×
332
        } else {
×
333
                c.DisabledFlags.Val &^= ChanUpdateDisableIncoming
×
334
                c.DisabledFlags.Val &^= ChanUpdateDisableOutgoing
×
335
        }
×
336
}
337

338
// SetSCID can be used to overwrite the SCID of the update.
339
//
340
// NOTE: this is part of the ChannelUpdate interface.
341
func (c *ChannelUpdate2) SetSCID(scid ShortChannelID) {
×
342
        c.ShortChannelID.Val = scid
×
343
}
×
344

345
// A compile time check to ensure ChannelUpdate2 implements the
346
// lnwire.ChannelUpdate interface.
347
var _ ChannelUpdate = (*ChannelUpdate2)(nil)
348

349
// ChanUpdateDisableFlags is a bit vector that can be used to indicate various
350
// reasons for the channel being marked as disabled.
351
type ChanUpdateDisableFlags uint8
352

353
const (
354
        // ChanUpdateDisableIncoming is a bit indicates that a channel is
355
        // disabled in the inbound direction meaning that the node broadcasting
356
        // the update is communicating that they cannot receive funds.
357
        ChanUpdateDisableIncoming ChanUpdateDisableFlags = 1 << iota
358

359
        // ChanUpdateDisableOutgoing is a bit indicates that a channel is
360
        // disabled in the outbound direction meaning that the node broadcasting
361
        // the update is communicating that they cannot send or route funds.
362
        ChanUpdateDisableOutgoing = 2
363
)
364

365
// IncomingDisabled returns true if the ChanUpdateDisableIncoming bit is set.
366
func (c ChanUpdateDisableFlags) IncomingDisabled() bool {
×
367
        return c&ChanUpdateDisableIncoming == ChanUpdateDisableIncoming
×
368
}
×
369

370
// OutgoingDisabled returns true if the ChanUpdateDisableOutgoing bit is set.
371
func (c ChanUpdateDisableFlags) OutgoingDisabled() bool {
×
372
        return c&ChanUpdateDisableOutgoing == ChanUpdateDisableOutgoing
×
373
}
×
374

375
// IsEnabled returns true if none of the disable bits are set.
UNCOV
376
func (c ChanUpdateDisableFlags) IsEnabled() bool {
×
UNCOV
377
        return c == 0
×
UNCOV
378
}
×
379

380
// String returns the bitfield flags as a string.
381
func (c ChanUpdateDisableFlags) String() string {
×
382
        return fmt.Sprintf("%08b", c)
×
383
}
×
384

385
// Record returns the tlv record for the disable flags.
UNCOV
386
func (c *ChanUpdateDisableFlags) Record() tlv.Record {
×
UNCOV
387
        return tlv.MakeStaticRecord(0, c, 1, encodeDisableFlags,
×
UNCOV
388
                decodeDisableFlags)
×
UNCOV
389
}
×
390

UNCOV
391
func encodeDisableFlags(w io.Writer, val interface{}, buf *[8]byte) error {
×
UNCOV
392
        if v, ok := val.(*ChanUpdateDisableFlags); ok {
×
UNCOV
393
                flagsInt := uint8(*v)
×
UNCOV
394

×
UNCOV
395
                return tlv.EUint8(w, &flagsInt, buf)
×
UNCOV
396
        }
×
397

398
        return tlv.NewTypeForEncodingErr(val, "lnwire.ChanUpdateDisableFlags")
×
399
}
400

401
func decodeDisableFlags(r io.Reader, val interface{}, buf *[8]byte,
UNCOV
402
        l uint64) error {
×
UNCOV
403

×
UNCOV
404
        if v, ok := val.(*ChanUpdateDisableFlags); ok {
×
UNCOV
405
                var flagsInt uint8
×
UNCOV
406
                err := tlv.DUint8(r, &flagsInt, buf, l)
×
UNCOV
407
                if err != nil {
×
UNCOV
408
                        return err
×
UNCOV
409
                }
×
410

UNCOV
411
                *v = ChanUpdateDisableFlags(flagsInt)
×
UNCOV
412

×
UNCOV
413
                return nil
×
414
        }
415

416
        return tlv.NewTypeForDecodingErr(val, "lnwire.ChanUpdateDisableFlags",
×
417
                l, l)
×
418
}
419

420
// TrueBoolean is a record that indicates true or false using the presence of
421
// the record. If the record is absent, it indicates false. If it is present,
422
// it indicates true.
423
type TrueBoolean struct{}
424

425
// Record returns the tlv record for the boolean entry.
426
func (b *TrueBoolean) Record() tlv.Record {
3✔
427
        return tlv.MakeStaticRecord(
3✔
428
                0, b, 0, booleanEncoder, booleanDecoder,
3✔
429
        )
3✔
430
}
3✔
431

432
func booleanEncoder(_ io.Writer, val interface{}, _ *[8]byte) error {
3✔
433
        if _, ok := val.(*TrueBoolean); ok {
6✔
434
                return nil
3✔
435
        }
3✔
436

437
        return tlv.NewTypeForEncodingErr(val, "TrueBoolean")
×
438
}
439

440
func booleanDecoder(_ io.Reader, val interface{}, _ *[8]byte,
441
        l uint64) error {
3✔
442

3✔
443
        if _, ok := val.(*TrueBoolean); ok && (l == 0 || l == 1) {
6✔
444
                return nil
3✔
445
        }
3✔
446

UNCOV
447
        return tlv.NewTypeForEncodingErr(val, "TrueBoolean")
×
448
}
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