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

lightningnetwork / lnd / 12118348650

02 Dec 2024 11:25AM UTC coverage: 58.552% (-0.4%) from 58.977%
12118348650

Pull #9175

github

ellemouton
lnwire: add NodeAnnouncement2
Pull Request #9175: lnwire+netann: update structure of g175 messages to be pure TLV

405 of 571 new or added lines in 11 files covered. (70.93%)

1754 existing lines in 33 files now uncovered.

133774 of 228469 relevant lines covered (58.55%)

19422.52 hits per line

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

63.32
/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
        // ChainHash denotes the target chain that this channel was opened
26
        // within. This value should be the genesis hash of the target chain.
27
        // Along with the short channel ID, this uniquely identifies the
28
        // channel globally in a blockchain.
29
        ChainHash tlv.RecordT[tlv.TlvType0, chainhash.Hash]
30

31
        // ShortChannelID is the unique description of the funding transaction.
32
        ShortChannelID tlv.RecordT[tlv.TlvType2, ShortChannelID]
33

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

41
        // DisabledFlags is an optional bitfield that describes various reasons
42
        // that the node is communicating that the channel should be considered
43
        // disabled.
44
        DisabledFlags tlv.RecordT[tlv.TlvType6, ChanUpdateDisableFlags]
45

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

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

58
        // HTLCMinimumMsat is the minimum HTLC value which will be accepted.
59
        HTLCMinimumMsat tlv.RecordT[tlv.TlvType12, MilliSatoshi]
60

61
        // HtlcMaximumMsat is the maximum HTLC value which will be accepted.
62
        HTLCMaximumMsat tlv.RecordT[tlv.TlvType14, MilliSatoshi]
63

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

69
        // FeeProportionalMillionths is the fee rate that will be charged per
70
        // millionth of a satoshi.
71
        FeeProportionalMillionths tlv.RecordT[tlv.TlvType18, uint32]
72

73
        // Signature is used to validate the announced data and prove the
74
        // ownership of node id.
75
        Signature tlv.RecordT[tlv.TlvType160, Sig]
76

77
        // Any extra fields in the signed range that we do not yet know about,
78
        // but we need to keep them for signature validation and to produce a
79
        // valid message.
80
        ExtraSignedFields
81
}
82

83
// Encode serializes the target ChannelUpdate2 into the passed io.Writer
84
// observing the protocol version specified.
85
//
86
// This is part of the lnwire.Message interface.
87
func (c *ChannelUpdate2) Encode(w *bytes.Buffer, _ uint32) error {
100✔
88
        return EncodePureTLVMessage(c, w)
100✔
89
}
100✔
90

91
// Decode deserializes a serialized ChannelUpdate2 stored in the passed
92
// io.Reader observing the specified protocol version.
93
//
94
// This is part of the lnwire.Message interface.
95
func (c *ChannelUpdate2) Decode(r io.Reader, _ uint32) error {
100✔
96
        // First extract into extra opaque data.
100✔
97
        var tlvRecords ExtraOpaqueData
100✔
98
        if err := ReadElements(r, &tlvRecords); err != nil {
100✔
99
                return err
×
100
        }
×
101

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

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

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

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

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

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

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

152
        c.ExtraSignedFields = ExtraSignedFieldsFromTypeMap(typeMap)
100✔
153

100✔
154
        return nil
100✔
155
}
156

157
// AllRecords returns all the TLV records for the message. This will include all
158
// the records we know about along with any that we don't know about but that
159
// fall in the signed TLV range.
160
//
161
// NOTE: this is part of the PureTLVMessage interface.
162
func (c *ChannelUpdate2) AllRecords() []tlv.Record {
100✔
163
        var recordProducers []tlv.RecordProducer
100✔
164

100✔
165
        // The chain-hash record is only included if it is _not_ equal to the
100✔
166
        // bitcoin mainnet genisis block hash.
100✔
167
        if !c.ChainHash.Val.IsEqual(chaincfg.MainNetParams.GenesisHash) {
143✔
168
                hash := tlv.ZeroRecordT[tlv.TlvType0, [32]byte]()
43✔
169
                hash.Val = c.ChainHash.Val
43✔
170

43✔
171
                recordProducers = append(recordProducers, &hash)
43✔
172
        }
43✔
173

174
        recordProducers = append(recordProducers,
100✔
175
                &c.ShortChannelID, &c.BlockHeight, &c.Signature,
100✔
176
        )
100✔
177

100✔
178
        // Only include the disable flags if any bit is set.
100✔
179
        if !c.DisabledFlags.Val.IsEnabled() {
173✔
180
                recordProducers = append(recordProducers, &c.DisabledFlags)
73✔
181
        }
73✔
182

183
        // We only need to encode the second peer boolean if it is true
184
        c.SecondPeer.WhenSome(func(r tlv.RecordT[tlv.TlvType8, TrueBoolean]) {
148✔
185
                recordProducers = append(recordProducers, &r)
48✔
186
        })
48✔
187

188
        // We only encode the cltv expiry delta if it is not equal to the
189
        // default.
190
        if c.CLTVExpiryDelta.Val != defaultCltvExpiryDelta {
143✔
191
                recordProducers = append(recordProducers, &c.CLTVExpiryDelta)
43✔
192
        }
43✔
193

194
        if c.HTLCMinimumMsat.Val != defaultHtlcMinMsat {
149✔
195
                recordProducers = append(recordProducers, &c.HTLCMinimumMsat)
49✔
196
        }
49✔
197

198
        recordProducers = append(recordProducers, &c.HTLCMaximumMsat)
100✔
199

100✔
200
        if c.FeeBaseMsat.Val != defaultFeeBaseMsat {
151✔
201
                recordProducers = append(recordProducers, &c.FeeBaseMsat)
51✔
202
        }
51✔
203

204
        if c.FeeProportionalMillionths.Val != defaultFeeProportionalMillionths {
152✔
205
                recordProducers = append(
52✔
206
                        recordProducers, &c.FeeProportionalMillionths,
52✔
207
                )
52✔
208
        }
52✔
209

210
        recordProducers = append(recordProducers, RecordsAsProducers(
100✔
211
                tlv.MapToRecords(c.ExtraSignedFields),
100✔
212
        )...)
100✔
213

100✔
214
        return ProduceRecordsSorted(recordProducers...)
100✔
215
}
216

217
// MsgType returns the integer uniquely identifying this message type on the
218
// wire.
219
//
220
// This is part of the lnwire.Message interface.
221
func (c *ChannelUpdate2) MsgType() MessageType {
100✔
222
        return MsgChannelUpdate2
100✔
223
}
100✔
224

NEW
225
func (c *ChannelUpdate2) ExtraData() (ExtraOpaqueData, error) {
×
NEW
226
        var buf *bytes.Buffer
×
NEW
227
        err := EncodeRecordsTo(buf, tlv.MapToRecords(c.ExtraSignedFields))
×
NEW
228
        if err != nil {
×
NEW
229
                return nil, err
×
NEW
230
        }
×
231

NEW
232
        return buf.Bytes(), nil
×
233
}
234

235
// A compile time check to ensure ChannelUpdate2 implements the
236
// lnwire.Message interface.
237
var _ Message = (*ChannelUpdate2)(nil)
238

239
// SCID returns the ShortChannelID of the channel that the update applies to.
240
//
241
// NOTE: this is part of the ChannelUpdate interface.
242
func (c *ChannelUpdate2) SCID() ShortChannelID {
×
243
        return c.ShortChannelID.Val
×
244
}
×
245

246
// IsNode1 is true if the update was produced by node 1 of the channel peers.
247
// Node 1 is the node with the lexicographically smaller public key.
248
//
249
// NOTE: this is part of the ChannelUpdate interface.
250
func (c *ChannelUpdate2) IsNode1() bool {
×
251
        return c.SecondPeer.IsNone()
×
252
}
×
253

254
// IsDisabled is true if the update is announcing that the channel should be
255
// considered disabled.
256
//
257
// NOTE: this is part of the ChannelUpdate interface.
258
func (c *ChannelUpdate2) IsDisabled() bool {
×
259
        return !c.DisabledFlags.Val.IsEnabled()
×
260
}
×
261

262
// GetChainHash returns the hash of the chain that the message is referring to.
263
//
264
// NOTE: this is part of the ChannelUpdate interface.
265
func (c *ChannelUpdate2) GetChainHash() chainhash.Hash {
×
266
        return c.ChainHash.Val
×
267
}
×
268

269
// ForwardingPolicy returns the set of forwarding constraints of the update.
270
//
271
// NOTE: this is part of the ChannelUpdate interface.
272
func (c *ChannelUpdate2) ForwardingPolicy() *ForwardingPolicy {
×
273
        return &ForwardingPolicy{
×
274
                TimeLockDelta: c.CLTVExpiryDelta.Val,
×
275
                BaseFee:       MilliSatoshi(c.FeeBaseMsat.Val),
×
276
                FeeRate:       MilliSatoshi(c.FeeProportionalMillionths.Val),
×
277
                MinHTLC:       c.HTLCMinimumMsat.Val,
×
278
                HasMaxHTLC:    true,
×
279
                MaxHTLC:       c.HTLCMaximumMsat.Val,
×
280
        }
×
281
}
×
282

283
// CmpAge can be used to determine if the update is older or newer than the
284
// passed update. It returns 1 if this update is newer, -1 if it is older, and
285
// 0 if they are the same age.
286
//
287
// NOTE: this is part of the ChannelUpdate interface.
288
func (c *ChannelUpdate2) CmpAge(update ChannelUpdate) (CompareResult, error) {
×
289
        other, ok := update.(*ChannelUpdate2)
×
290
        if !ok {
×
291
                return 0, fmt.Errorf("expected *ChannelUpdate2, got: %T",
×
292
                        update)
×
293
        }
×
294

295
        switch {
×
296
        case c.BlockHeight.Val > other.BlockHeight.Val:
×
297
                return GreaterThan, nil
×
298
        case c.BlockHeight.Val < other.BlockHeight.Val:
×
299
                return LessThan, nil
×
300
        default:
×
301
                return EqualTo, nil
×
302
        }
303
}
304

305
// SetDisabledFlag can be used to adjust the disabled flag of an update.
306
//
307
// NOTE: this is part of the ChannelUpdate interface.
308
func (c *ChannelUpdate2) SetDisabledFlag(disabled bool) {
×
309
        if disabled {
×
310
                c.DisabledFlags.Val |= ChanUpdateDisableIncoming
×
311
                c.DisabledFlags.Val |= ChanUpdateDisableOutgoing
×
312
        } else {
×
313
                c.DisabledFlags.Val &^= ChanUpdateDisableIncoming
×
314
                c.DisabledFlags.Val &^= ChanUpdateDisableOutgoing
×
315
        }
×
316
}
317

318
// SetSCID can be used to overwrite the SCID of the update.
319
//
320
// NOTE: this is part of the ChannelUpdate interface.
321
func (c *ChannelUpdate2) SetSCID(scid ShortChannelID) {
×
322
        c.ShortChannelID.Val = scid
×
323
}
×
324

325
// A compile time check to ensure ChannelUpdate2 implements the
326
// lnwire.ChannelUpdate interface.
327
var _ ChannelUpdate = (*ChannelUpdate2)(nil)
328

329
// ChanUpdateDisableFlags is a bit vector that can be used to indicate various
330
// reasons for the channel being marked as disabled.
331
type ChanUpdateDisableFlags uint8
332

333
const (
334
        // ChanUpdateDisableIncoming is a bit indicates that a channel is
335
        // disabled in the inbound direction meaning that the node broadcasting
336
        // the update is communicating that they cannot receive funds.
337
        ChanUpdateDisableIncoming ChanUpdateDisableFlags = 1 << iota
338

339
        // ChanUpdateDisableOutgoing is a bit indicates that a channel is
340
        // disabled in the outbound direction meaning that the node broadcasting
341
        // the update is communicating that they cannot send or route funds.
342
        ChanUpdateDisableOutgoing = 2
343
)
344

345
// IncomingDisabled returns true if the ChanUpdateDisableIncoming bit is set.
346
func (c ChanUpdateDisableFlags) IncomingDisabled() bool {
×
347
        return c&ChanUpdateDisableIncoming == ChanUpdateDisableIncoming
×
348
}
×
349

350
// OutgoingDisabled returns true if the ChanUpdateDisableOutgoing bit is set.
351
func (c ChanUpdateDisableFlags) OutgoingDisabled() bool {
×
352
        return c&ChanUpdateDisableOutgoing == ChanUpdateDisableOutgoing
×
353
}
×
354

355
// IsEnabled returns true if none of the disable bits are set.
356
func (c ChanUpdateDisableFlags) IsEnabled() bool {
100✔
357
        return c == 0
100✔
358
}
100✔
359

360
// String returns the bitfield flags as a string.
361
func (c ChanUpdateDisableFlags) String() string {
×
362
        return fmt.Sprintf("%08b", c)
×
363
}
×
364

365
// Record returns the tlv record for the disable flags.
366
func (c *ChanUpdateDisableFlags) Record() tlv.Record {
173✔
367
        return tlv.MakeStaticRecord(0, c, 1, encodeDisableFlags,
173✔
368
                decodeDisableFlags)
173✔
369
}
173✔
370

371
func encodeDisableFlags(w io.Writer, val interface{}, buf *[8]byte) error {
73✔
372
        if v, ok := val.(*ChanUpdateDisableFlags); ok {
146✔
373
                flagsInt := uint8(*v)
73✔
374

73✔
375
                return tlv.EUint8(w, &flagsInt, buf)
73✔
376
        }
73✔
377

378
        return tlv.NewTypeForEncodingErr(val, "lnwire.ChanUpdateDisableFlags")
×
379
}
380

381
func decodeDisableFlags(r io.Reader, val interface{}, buf *[8]byte,
382
        l uint64) error {
73✔
383

73✔
384
        if v, ok := val.(*ChanUpdateDisableFlags); ok {
146✔
385
                var flagsInt uint8
73✔
386
                err := tlv.DUint8(r, &flagsInt, buf, l)
73✔
387
                if err != nil {
73✔
388
                        return err
×
389
                }
×
390

391
                *v = ChanUpdateDisableFlags(flagsInt)
73✔
392

73✔
393
                return nil
73✔
394
        }
395

396
        return tlv.NewTypeForDecodingErr(val, "lnwire.ChanUpdateDisableFlags",
×
397
                l, l)
×
398
}
399

400
// TrueBoolean is a record that indicates true or false using the presence of
401
// the record. If the record is absent, it indicates false. If it is present,
402
// it indicates true.
403
type TrueBoolean struct{}
404

405
// Record returns the tlv record for the boolean entry.
406
func (b *TrueBoolean) Record() tlv.Record {
246✔
407
        return tlv.MakeStaticRecord(
246✔
408
                0, b, 0, booleanEncoder, booleanDecoder,
246✔
409
        )
246✔
410
}
246✔
411

412
func booleanEncoder(_ io.Writer, val interface{}, _ *[8]byte) error {
91✔
413
        if _, ok := val.(*TrueBoolean); ok {
182✔
414
                return nil
91✔
415
        }
91✔
416

417
        return tlv.NewTypeForEncodingErr(val, "TrueBoolean")
×
418
}
419

420
func booleanDecoder(_ io.Reader, val interface{}, _ *[8]byte,
421
        l uint64) error {
72✔
422

72✔
423
        if _, ok := val.(*TrueBoolean); ok && (l == 0 || l == 1) {
144✔
424
                return nil
72✔
425
        }
72✔
426

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