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

lightningnetwork / lnd / 13541633202

26 Feb 2025 10:16AM UTC coverage: 58.834% (-0.001%) from 58.835%
13541633202

Pull #9549

github

yyforyongyu
routing: fix flake in `TestFilteredChainView/bitcoind_polling`
Pull Request #9549: Fix unit test flake `TestHistoricalConfDetailsTxIndex`

104 of 124 new or added lines in 3 files covered. (83.87%)

75 existing lines in 19 files now uncovered.

136424 of 231878 relevant lines covered (58.83%)

19208.82 hits per line

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

66.48
/netann/channel_update.go
1
package netann
2

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

8
        "github.com/btcsuite/btcd/btcec/v2"
9
        "github.com/btcsuite/btcd/btcutil"
10
        "github.com/btcsuite/btcd/chaincfg/chainhash"
11
        "github.com/davecgh/go-spew/spew"
12
        "github.com/lightningnetwork/lnd/graph/db/models"
13
        "github.com/lightningnetwork/lnd/keychain"
14
        "github.com/lightningnetwork/lnd/lnwallet"
15
        "github.com/lightningnetwork/lnd/lnwire"
16
        "github.com/pkg/errors"
17
)
18

19
const (
20
        // chanUpdate2MsgName is a string representing the name of the
21
        // ChannelUpdate2 message. This string will be used during the
22
        // construction of the tagged hash message to be signed when producing
23
        // the signature for the ChannelUpdate2 message.
24
        chanUpdate2MsgName = "channel_update_2"
25

26
        // chanUpdate2SigField is the name of the signature field of the
27
        // ChannelUpdate2 message. This string will be used during the
28
        // construction of the tagged hash message to be signed when producing
29
        // the signature for the ChannelUpdate2 message.
30
        chanUpdate2SigField = "signature"
31
)
32

33
// ErrUnableToExtractChanUpdate is returned when a channel update cannot be
34
// found for one of our active channels.
35
var ErrUnableToExtractChanUpdate = fmt.Errorf("unable to extract ChannelUpdate")
36

37
// ChannelUpdateModifier is a closure that makes in-place modifications to an
38
// lnwire.ChannelUpdate.
39
type ChannelUpdateModifier func(*lnwire.ChannelUpdate1)
40

41
// ChanUpdSetDisable is a functional option that sets the disabled channel flag
42
// if disabled is true, and clears the bit otherwise.
43
func ChanUpdSetDisable(disabled bool) ChannelUpdateModifier {
105✔
44
        return func(update *lnwire.ChannelUpdate1) {
210✔
45
                if disabled {
166✔
46
                        // Set the bit responsible for marking a channel as
61✔
47
                        // disabled.
61✔
48
                        update.ChannelFlags |= lnwire.ChanUpdateDisabled
61✔
49
                } else {
108✔
50
                        // Clear the bit responsible for marking a channel as
47✔
51
                        // disabled.
47✔
52
                        update.ChannelFlags &= ^lnwire.ChanUpdateDisabled
47✔
53
                }
47✔
54
        }
55
}
56

57
// ChanUpdSetTimestamp is a functional option that sets the timestamp of the
58
// update to the current time, or increments it if the timestamp is already in
59
// the future.
60
func ChanUpdSetTimestamp(update *lnwire.ChannelUpdate1) {
109✔
61
        newTimestamp := uint32(time.Now().Unix())
109✔
62
        if newTimestamp <= update.Timestamp {
179✔
63
                // Increment the prior value to ensure the timestamp
70✔
64
                // monotonically increases, otherwise the update won't
70✔
65
                // propagate.
70✔
66
                newTimestamp = update.Timestamp + 1
70✔
67
        }
70✔
68
        update.Timestamp = newTimestamp
109✔
69
}
70

71
// SignChannelUpdate applies the given modifiers to the passed
72
// lnwire.ChannelUpdate, then signs the resulting update. The provided update
73
// should be the most recent, valid update, otherwise the timestamp may not
74
// monotonically increase from the prior.
75
//
76
// NOTE: This method modifies the given update.
77
func SignChannelUpdate(signer lnwallet.MessageSigner, keyLoc keychain.KeyLocator,
78
        update *lnwire.ChannelUpdate1, mods ...ChannelUpdateModifier) error {
109✔
79

109✔
80
        // Apply the requested changes to the channel update.
109✔
81
        for _, modifier := range mods {
320✔
82
                modifier(update)
211✔
83
        }
211✔
84

85
        // Create the DER-encoded ECDSA signature over the message digest.
86
        sig, err := SignAnnouncement(signer, keyLoc, update)
109✔
87
        if err != nil {
110✔
88
                return err
1✔
89
        }
1✔
90

91
        // Parse the DER-encoded signature into a fixed-size 64-byte array.
92
        update.Signature, err = lnwire.NewSigFromSignature(sig)
108✔
93
        if err != nil {
109✔
94
                return err
1✔
95
        }
1✔
96

97
        return nil
107✔
98
}
99

100
// ExtractChannelUpdate attempts to retrieve a lnwire.ChannelUpdate message from
101
// an edge's info and a set of routing policies.
102
//
103
// NOTE: The passed policies can be nil.
104
func ExtractChannelUpdate(ownerPubKey []byte,
105
        info *models.ChannelEdgeInfo,
106
        policies ...*models.ChannelEdgePolicy) (
107
        *lnwire.ChannelUpdate1, error) {
316✔
108

316✔
109
        // Helper function to extract the owner of the given policy.
316✔
110
        owner := func(edge *models.ChannelEdgePolicy) []byte {
769✔
111
                var pubKey *btcec.PublicKey
453✔
112
                if edge.ChannelFlags&lnwire.ChanUpdateDirection == 0 {
769✔
113
                        pubKey, _ = info.NodeKey1()
316✔
114
                } else {
456✔
115
                        pubKey, _ = info.NodeKey2()
140✔
116
                }
140✔
117

118
                // If pubKey was not found, just return nil.
119
                if pubKey == nil {
453✔
120
                        return nil
×
121
                }
×
122

123
                return pubKey.SerializeCompressed()
453✔
124
        }
125

126
        // Extract the channel update from the policy we own, if any.
127
        for _, edge := range policies {
769✔
128
                if edge != nil && bytes.Equal(ownerPubKey, owner(edge)) {
769✔
129
                        return ChannelUpdateFromEdge(info, edge)
316✔
130
                }
316✔
131
        }
132

UNCOV
133
        return nil, ErrUnableToExtractChanUpdate
×
134
}
135

136
// UnsignedChannelUpdateFromEdge reconstructs an unsigned ChannelUpdate from the
137
// given edge info and policy.
138
func UnsignedChannelUpdateFromEdge(info *models.ChannelEdgeInfo,
139
        policy *models.ChannelEdgePolicy) *lnwire.ChannelUpdate1 {
339✔
140

339✔
141
        return &lnwire.ChannelUpdate1{
339✔
142
                ChainHash:       info.ChainHash,
339✔
143
                ShortChannelID:  lnwire.NewShortChanIDFromInt(policy.ChannelID),
339✔
144
                Timestamp:       uint32(policy.LastUpdate.Unix()),
339✔
145
                ChannelFlags:    policy.ChannelFlags,
339✔
146
                MessageFlags:    policy.MessageFlags,
339✔
147
                TimeLockDelta:   policy.TimeLockDelta,
339✔
148
                HtlcMinimumMsat: policy.MinHTLC,
339✔
149
                HtlcMaximumMsat: policy.MaxHTLC,
339✔
150
                BaseFee:         uint32(policy.FeeBaseMSat),
339✔
151
                FeeRate:         uint32(policy.FeeProportionalMillionths),
339✔
152
                ExtraOpaqueData: policy.ExtraOpaqueData,
339✔
153
        }
339✔
154
}
339✔
155

156
// ChannelUpdateFromEdge reconstructs a signed ChannelUpdate from the given edge
157
// info and policy.
158
func ChannelUpdateFromEdge(info *models.ChannelEdgeInfo,
159
        policy *models.ChannelEdgePolicy) (*lnwire.ChannelUpdate1, error) {
335✔
160

335✔
161
        update := UnsignedChannelUpdateFromEdge(info, policy)
335✔
162

335✔
163
        var err error
335✔
164
        update.Signature, err = lnwire.NewSigFromECDSARawSignature(
335✔
165
                policy.SigBytes,
335✔
166
        )
335✔
167
        if err != nil {
335✔
168
                return nil, err
×
169
        }
×
170

171
        return update, nil
335✔
172
}
173

174
// ValidateChannelUpdateAnn validates the channel update announcement by
175
// checking (1) that the included signature covers the announcement and has been
176
// signed by the node's private key, and (2) that the announcement's message
177
// flags and optional fields are sane.
178
func ValidateChannelUpdateAnn(pubKey *btcec.PublicKey, capacity btcutil.Amount,
179
        a lnwire.ChannelUpdate) error {
56✔
180

56✔
181
        if err := ValidateChannelUpdateFields(capacity, a); err != nil {
60✔
182
                return err
4✔
183
        }
4✔
184

185
        return VerifyChannelUpdateSignature(a, pubKey)
52✔
186
}
187

188
// VerifyChannelUpdateSignature verifies that the channel update message was
189
// signed by the party with the given node public key.
190
func VerifyChannelUpdateSignature(msg lnwire.ChannelUpdate,
191
        pubKey *btcec.PublicKey) error {
62✔
192

62✔
193
        switch u := msg.(type) {
62✔
194
        case *lnwire.ChannelUpdate1:
62✔
195
                return verifyChannelUpdate1Signature(u, pubKey)
62✔
196
        case *lnwire.ChannelUpdate2:
×
197
                return verifyChannelUpdate2Signature(u, pubKey)
×
198
        default:
×
199
                return fmt.Errorf("unhandled implementation of "+
×
200
                        "lnwire.ChannelUpdate: %T", msg)
×
201
        }
202
}
203

204
// verifyChannelUpdateSignature1 verifies that the channel update message was
205
// signed by the party with the given node public key.
206
func verifyChannelUpdate1Signature(msg *lnwire.ChannelUpdate1,
207
        pubKey *btcec.PublicKey) error {
62✔
208

62✔
209
        data, err := msg.DataToSign()
62✔
210
        if err != nil {
62✔
211
                return fmt.Errorf("unable to reconstruct message data: %w", err)
×
212
        }
×
213
        dataHash := chainhash.DoubleHashB(data)
62✔
214

62✔
215
        nodeSig, err := msg.Signature.ToSignature()
62✔
216
        if err != nil {
62✔
217
                return err
×
218
        }
×
219

220
        if !nodeSig.Verify(dataHash, pubKey) {
63✔
221
                return fmt.Errorf("invalid signature for channel update %v",
1✔
222
                        spew.Sdump(msg))
1✔
223
        }
1✔
224

225
        return nil
61✔
226
}
227

228
// verifyChannelUpdateSignature2 verifies that the channel update message was
229
// signed by the party with the given node public key.
230
func verifyChannelUpdate2Signature(c *lnwire.ChannelUpdate2,
231
        pubKey *btcec.PublicKey) error {
×
232

×
233
        digest, err := chanUpdate2DigestToSign(c)
×
234
        if err != nil {
×
235
                return fmt.Errorf("unable to reconstruct message data: %w", err)
×
236
        }
×
237

238
        nodeSig, err := c.Signature.ToSignature()
×
239
        if err != nil {
×
240
                return err
×
241
        }
×
242

243
        if !nodeSig.Verify(digest, pubKey) {
×
244
                return fmt.Errorf("invalid signature for channel update %v",
×
245
                        spew.Sdump(c))
×
246
        }
×
247

248
        return nil
×
249
}
250

251
// ValidateChannelUpdateFields validates a channel update's message flags and
252
// corresponding update fields.
253
func ValidateChannelUpdateFields(capacity btcutil.Amount,
254
        msg lnwire.ChannelUpdate) error {
56✔
255

56✔
256
        switch u := msg.(type) {
56✔
257
        case *lnwire.ChannelUpdate1:
56✔
258
                return validateChannelUpdate1Fields(capacity, u)
56✔
259
        case *lnwire.ChannelUpdate2:
×
260
                return validateChannelUpdate2Fields(capacity, u)
×
261
        default:
×
262
                return fmt.Errorf("unhandled implementation of "+
×
263
                        "lnwire.ChannelUpdate: %T", msg)
×
264
        }
265
}
266

267
// validateChannelUpdate1Fields validates a channel update's message flags and
268
// corresponding update fields.
269
func validateChannelUpdate1Fields(capacity btcutil.Amount,
270
        msg *lnwire.ChannelUpdate1) error {
56✔
271

56✔
272
        // The maxHTLC flag is mandatory.
56✔
273
        if !msg.MessageFlags.HasMaxHtlc() {
58✔
274
                return errors.Errorf("max htlc flag not set for channel "+
2✔
275
                        "update %v", spew.Sdump(msg))
2✔
276
        }
2✔
277

278
        maxHtlc := msg.HtlcMaximumMsat
54✔
279
        if maxHtlc == 0 || maxHtlc < msg.HtlcMinimumMsat {
56✔
280
                return errors.Errorf("invalid max htlc for channel "+
2✔
281
                        "update %v", spew.Sdump(msg))
2✔
282
        }
2✔
283

284
        // For light clients, the capacity will not be set so we'll skip
285
        // checking whether the MaxHTLC value respects the channel's
286
        // capacity.
287
        capacityMsat := lnwire.NewMSatFromSatoshis(capacity)
52✔
288
        if capacityMsat != 0 && maxHtlc > capacityMsat {
52✔
289
                return errors.Errorf("max_htlc (%v) for channel update "+
×
290
                        "greater than capacity (%v)", maxHtlc, capacityMsat)
×
291
        }
×
292

293
        return nil
52✔
294
}
295

296
// validateChannelUpdate2Fields validates a channel update's message flags and
297
// corresponding update fields.
298
func validateChannelUpdate2Fields(capacity btcutil.Amount,
299
        c *lnwire.ChannelUpdate2) error {
×
300

×
301
        maxHtlc := c.HTLCMaximumMsat.Val
×
302
        if maxHtlc == 0 || maxHtlc < c.HTLCMinimumMsat.Val {
×
303
                return fmt.Errorf("invalid max htlc for channel update %v",
×
304
                        spew.Sdump(c))
×
305
        }
×
306

307
        // Checking whether the MaxHTLC value respects the channel's capacity.
308
        capacityMsat := lnwire.NewMSatFromSatoshis(capacity)
×
309
        if maxHtlc > capacityMsat {
×
310
                return fmt.Errorf("max_htlc (%v) for channel update greater "+
×
311
                        "than capacity (%v)", maxHtlc, capacityMsat)
×
312
        }
×
313

314
        return nil
×
315
}
316

317
// ChanUpdate2DigestTag returns the tag to be used when signing the digest of
318
// a channel_update_2 message.
319
func ChanUpdate2DigestTag() []byte {
×
320
        return MsgTag(chanUpdate2MsgName, chanUpdate2SigField)
×
321
}
×
322

323
// chanUpdate2DigestToSign computes the digest of the ChannelUpdate2 message to
324
// be signed.
325
func chanUpdate2DigestToSign(c *lnwire.ChannelUpdate2) ([]byte, error) {
×
326
        data, err := c.DataToSign()
×
327
        if err != nil {
×
328
                return nil, err
×
329
        }
×
330

331
        hash := MsgHash(chanUpdate2MsgName, chanUpdate2SigField, data)
×
332

×
333
        return hash[:], nil
×
334
}
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