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

lightningnetwork / lnd / 16982438758

15 Aug 2025 03:47AM UTC coverage: 66.748% (-0.03%) from 66.776%
16982438758

Pull #9455

github

web-flow
Merge 9a33d5e7b into 31fc55650
Pull Request #9455: [1/2] discovery+lnwire: add support for DNS host name in NodeAnnouncement msg

209 of 304 new or added lines in 8 files covered. (68.75%)

1268 existing lines in 30 files now uncovered.

136026 of 203789 relevant lines covered (66.75%)

21540.12 hits per line

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

80.61
/discovery/chan_series.go
1
package discovery
2

3
import (
4
        "context"
5
        "time"
6

7
        "github.com/btcsuite/btcd/chaincfg/chainhash"
8
        graphdb "github.com/lightningnetwork/lnd/graph/db"
9
        "github.com/lightningnetwork/lnd/lnwire"
10
        "github.com/lightningnetwork/lnd/netann"
11
        "github.com/lightningnetwork/lnd/routing/route"
12
)
13

14
// ChannelGraphTimeSeries is an interface that provides time and block based
15
// querying into our view of the channel graph. New channels will have
16
// monotonically increasing block heights, and new channel updates will have
17
// increasing timestamps. Once we connect to a peer, we'll use the methods in
18
// this interface to determine if we're already in sync, or need to request
19
// some new information from them.
20
type ChannelGraphTimeSeries interface {
21
        // HighestChanID should return the channel ID of the channel we know of
22
        // that's furthest in the target chain. This channel will have a block
23
        // height that's close to the current tip of the main chain as we
24
        // know it.  We'll use this to start our QueryChannelRange dance with
25
        // the remote node.
26
        HighestChanID(ctx context.Context,
27
                chain chainhash.Hash) (*lnwire.ShortChannelID, error)
28

29
        // UpdatesInHorizon returns all known channel and node updates with an
30
        // update timestamp between the start time and end time. We'll use this
31
        // to catch up a remote node to the set of channel updates that they
32
        // may have missed out on within the target chain.
33
        UpdatesInHorizon(chain chainhash.Hash,
34
                startTime time.Time, endTime time.Time) ([]lnwire.Message, error)
35

36
        // FilterKnownChanIDs takes a target chain, and a set of channel ID's,
37
        // and returns a filtered set of chan ID's. This filtered set of chan
38
        // ID's represents the ID's that we don't know of which were in the
39
        // passed superSet.
40
        FilterKnownChanIDs(chain chainhash.Hash,
41
                superSet []graphdb.ChannelUpdateInfo,
42
                isZombieChan func(time.Time, time.Time) bool) (
43
                []lnwire.ShortChannelID, error)
44

45
        // FilterChannelRange returns the set of channels that we created
46
        // between the start height and the end height. The channel IDs are
47
        // grouped by their common block height. We'll use this to to a remote
48
        // peer's QueryChannelRange message.
49
        FilterChannelRange(chain chainhash.Hash, startHeight, endHeight uint32,
50
                withTimestamps bool) ([]graphdb.BlockChannelRange, error)
51

52
        // FetchChanAnns returns a full set of channel announcements as well as
53
        // their updates that match the set of specified short channel ID's.
54
        // We'll use this to reply to a QueryShortChanIDs message sent by a
55
        // remote peer. The response will contain a unique set of
56
        // ChannelAnnouncements, the latest ChannelUpdate for each of the
57
        // announcements, and a unique set of NodeAnnouncements.
58
        FetchChanAnns(chain chainhash.Hash,
59
                shortChanIDs []lnwire.ShortChannelID) ([]lnwire.Message, error)
60

61
        // FetchChanUpdates returns the latest channel update messages for the
62
        // specified short channel ID. If no channel updates are known for the
63
        // channel, then an empty slice will be returned.
64
        FetchChanUpdates(chain chainhash.Hash,
65
                shortChanID lnwire.ShortChannelID) ([]*lnwire.ChannelUpdate1,
66
                error)
67
}
68

69
// ChanSeries is an implementation of the ChannelGraphTimeSeries
70
// interface backed by the channeldb ChannelGraph database. We'll provide this
71
// implementation to the AuthenticatedGossiper so it can properly use the
72
// in-protocol channel range queries to quickly and efficiently synchronize our
73
// channel state with all peers.
74
type ChanSeries struct {
75
        graph *graphdb.ChannelGraph
76
}
77

78
// NewChanSeries constructs a new ChanSeries backed by a channeldb.ChannelGraph.
79
// The returned ChanSeries implements the ChannelGraphTimeSeries interface.
80
func NewChanSeries(graph *graphdb.ChannelGraph) *ChanSeries {
3✔
81
        return &ChanSeries{
3✔
82
                graph: graph,
3✔
83
        }
3✔
84
}
3✔
85

86
// HighestChanID should return is the channel ID of the channel we know of
87
// that's furthest in the target chain. This channel will have a block height
88
// that's close to the current tip of the main chain as we know it.  We'll use
89
// this to start our QueryChannelRange dance with the remote node.
90
//
91
// NOTE: This is part of the ChannelGraphTimeSeries interface.
92
func (c *ChanSeries) HighestChanID(ctx context.Context,
93
        _ chainhash.Hash) (*lnwire.ShortChannelID, error) {
3✔
94

3✔
95
        chanID, err := c.graph.HighestChanID(ctx)
3✔
96
        if err != nil {
3✔
97
                return nil, err
×
98
        }
×
99

100
        shortChanID := lnwire.NewShortChanIDFromInt(chanID)
3✔
101
        return &shortChanID, nil
3✔
102
}
103

104
// UpdatesInHorizon returns all known channel and node updates with an update
105
// timestamp between the start time and end time. We'll use this to catch up a
106
// remote node to the set of channel updates that they may have missed out on
107
// within the target chain.
108
//
109
// NOTE: This is part of the ChannelGraphTimeSeries interface.
110
func (c *ChanSeries) UpdatesInHorizon(chain chainhash.Hash,
111
        startTime time.Time, endTime time.Time) ([]lnwire.Message, error) {
3✔
112

3✔
113
        var updates []lnwire.Message
3✔
114

3✔
115
        // First, we'll query for all the set of channels that have an update
3✔
116
        // that falls within the specified horizon.
3✔
117
        chansInHorizon, err := c.graph.ChanUpdatesInHorizon(
3✔
118
                startTime, endTime,
3✔
119
        )
3✔
120
        if err != nil {
3✔
121
                return nil, err
×
122
        }
×
123
        for _, channel := range chansInHorizon {
6✔
124
                // If the channel hasn't been fully advertised yet, or is a
3✔
125
                // private channel, then we'll skip it as we can't construct a
3✔
126
                // full authentication proof if one is requested.
3✔
127
                if channel.Info.AuthProof == nil {
5✔
128
                        continue
2✔
129
                }
130

131
                chanAnn, edge1, edge2, err := netann.CreateChanAnnouncement(
3✔
132
                        channel.Info.AuthProof, channel.Info, channel.Policy1,
3✔
133
                        channel.Policy2,
3✔
134
                )
3✔
135
                if err != nil {
3✔
136
                        return nil, err
×
137
                }
×
138

139
                updates = append(updates, chanAnn)
3✔
140
                if edge1 != nil {
6✔
141
                        // We don't want to send channel updates that don't
3✔
142
                        // conform to the spec (anymore).
3✔
143
                        err := netann.ValidateChannelUpdateFields(0, edge1)
3✔
144
                        if err != nil {
3✔
145
                                log.Errorf("not sending invalid channel "+
×
146
                                        "update %v: %v", edge1, err)
×
147
                        } else {
3✔
148
                                updates = append(updates, edge1)
3✔
149
                        }
3✔
150
                }
151
                if edge2 != nil {
6✔
152
                        err := netann.ValidateChannelUpdateFields(0, edge2)
3✔
153
                        if err != nil {
3✔
154
                                log.Errorf("not sending invalid channel "+
×
155
                                        "update %v: %v", edge2, err)
×
156
                        } else {
3✔
157
                                updates = append(updates, edge2)
3✔
158
                        }
3✔
159
                }
160
        }
161

162
        // Next, we'll send out all the node announcements that have an update
163
        // within the horizon as well. We send these second to ensure that they
164
        // follow any active channels they have.
165
        nodeAnnsInHorizon, err := c.graph.NodeUpdatesInHorizon(
3✔
166
                startTime, endTime,
3✔
167
        )
3✔
168
        if err != nil {
3✔
169
                return nil, err
×
170
        }
×
171
        for _, nodeAnn := range nodeAnnsInHorizon {
6✔
172
                nodeAnn := nodeAnn
3✔
173

3✔
174
                // Ensure we only forward nodes that are publicly advertised to
3✔
175
                // prevent leaking information about nodes.
3✔
176
                isNodePublic, err := c.graph.IsPublicNode(nodeAnn.PubKeyBytes)
3✔
177
                if err != nil {
3✔
178
                        log.Errorf("Unable to determine if node %x is "+
×
179
                                "advertised: %v", nodeAnn.PubKeyBytes, err)
×
180
                        continue
×
181
                }
182

183
                if !isNodePublic {
6✔
184
                        log.Tracef("Skipping forwarding announcement for "+
3✔
185
                                "node %x due to being unadvertised",
3✔
186
                                nodeAnn.PubKeyBytes)
3✔
187
                        continue
3✔
188
                }
189

190
                nodeUpdate, err := nodeAnn.NodeAnnouncement(true)
3✔
191
                if err != nil {
3✔
192
                        return nil, err
×
193
                }
×
194

195
                if err := netann.ValidateNodeAnnFields(nodeUpdate); err != nil {
3✔
NEW
196
                        log.Debugf("Skipping forwarding invalid node "+
×
NEW
197
                                "announcement %x: %v", nodeAnn.PubKeyBytes, err)
×
NEW
198

×
NEW
199
                        continue
×
200
                }
201

202
                updates = append(updates, nodeUpdate)
3✔
203
        }
204

205
        return updates, nil
3✔
206
}
207

208
// FilterKnownChanIDs takes a target chain, and a set of channel ID's, and
209
// returns a filtered set of chan ID's. This filtered set of chan ID's
210
// represents the ID's that we don't know of which were in the passed superSet.
211
//
212
// NOTE: This is part of the ChannelGraphTimeSeries interface.
213
func (c *ChanSeries) FilterKnownChanIDs(_ chainhash.Hash,
214
        superSet []graphdb.ChannelUpdateInfo,
215
        isZombieChan func(time.Time, time.Time) bool) (
216
        []lnwire.ShortChannelID, error) {
3✔
217

3✔
218
        newChanIDs, err := c.graph.FilterKnownChanIDs(superSet, isZombieChan)
3✔
219
        if err != nil {
3✔
220
                return nil, err
×
221
        }
×
222

223
        filteredIDs := make([]lnwire.ShortChannelID, 0, len(newChanIDs))
3✔
224
        for _, chanID := range newChanIDs {
6✔
225
                filteredIDs = append(
3✔
226
                        filteredIDs, lnwire.NewShortChanIDFromInt(chanID),
3✔
227
                )
3✔
228
        }
3✔
229

230
        return filteredIDs, nil
3✔
231
}
232

233
// FilterChannelRange returns the set of channels that we created between the
234
// start height and the end height. The channel IDs are grouped by their common
235
// block height. We'll use this respond to a remote peer's QueryChannelRange
236
// message.
237
//
238
// NOTE: This is part of the ChannelGraphTimeSeries interface.
239
func (c *ChanSeries) FilterChannelRange(_ chainhash.Hash, startHeight,
240
        endHeight uint32, withTimestamps bool) ([]graphdb.BlockChannelRange,
241
        error) {
3✔
242

3✔
243
        return c.graph.FilterChannelRange(
3✔
244
                startHeight, endHeight, withTimestamps,
3✔
245
        )
3✔
246
}
3✔
247

248
// FetchChanAnns returns a full set of channel announcements as well as their
249
// updates that match the set of specified short channel ID's.  We'll use this
250
// to reply to a QueryShortChanIDs message sent by a remote peer. The response
251
// will contain a unique set of ChannelAnnouncements, the latest ChannelUpdate
252
// for each of the announcements, and a unique set of NodeAnnouncements.
253
//
254
// NOTE: This is part of the ChannelGraphTimeSeries interface.
255
func (c *ChanSeries) FetchChanAnns(chain chainhash.Hash,
256
        shortChanIDs []lnwire.ShortChannelID) ([]lnwire.Message, error) {
3✔
257

3✔
258
        chanIDs := make([]uint64, 0, len(shortChanIDs))
3✔
259
        for _, chanID := range shortChanIDs {
6✔
260
                chanIDs = append(chanIDs, chanID.ToUint64())
3✔
261
        }
3✔
262

263
        channels, err := c.graph.FetchChanInfos(chanIDs)
3✔
264
        if err != nil {
3✔
265
                return nil, err
×
266
        }
×
267

268
        // We'll use this map to ensure we don't send the same node
269
        // announcement more than one time as one node may have many channel
270
        // anns we'll need to send.
271
        nodePubsSent := make(map[route.Vertex]struct{})
3✔
272

3✔
273
        chanAnns := make([]lnwire.Message, 0, len(channels)*3)
3✔
274
        for _, channel := range channels {
6✔
275
                // If the channel doesn't have an authentication proof, then we
3✔
276
                // won't send it over as it may not yet be finalized, or be a
3✔
277
                // non-advertised channel.
3✔
278
                if channel.Info.AuthProof == nil {
3✔
279
                        continue
×
280
                }
281

282
                chanAnn, edge1, edge2, err := netann.CreateChanAnnouncement(
3✔
283
                        channel.Info.AuthProof, channel.Info, channel.Policy1,
3✔
284
                        channel.Policy2,
3✔
285
                )
3✔
286
                if err != nil {
3✔
287
                        return nil, err
×
288
                }
×
289

290
                chanAnns = append(chanAnns, chanAnn)
3✔
291
                if edge1 != nil {
6✔
292
                        chanAnns = append(chanAnns, edge1)
3✔
293

3✔
294
                        // If this edge has a validated node announcement, that
3✔
295
                        // we haven't yet sent, then we'll send that as well.
3✔
296
                        nodePub := channel.Node2.PubKeyBytes
3✔
297
                        hasNodeAnn := channel.Node2.HaveNodeAnnouncement
3✔
298
                        if _, ok := nodePubsSent[nodePub]; !ok && hasNodeAnn {
6✔
299
                                nodeAnn, err := channel.Node2.NodeAnnouncement(
3✔
300
                                        true,
3✔
301
                                )
3✔
302
                                if err != nil {
3✔
303
                                        return nil, err
×
304
                                }
×
305

306
                                err = netann.ValidateNodeAnnFields(nodeAnn)
3✔
307
                                if err == nil {
6✔
308
                                        chanAnns = append(chanAnns, nodeAnn)
3✔
309
                                        nodePubsSent[nodePub] = struct{}{}
3✔
310
                                }
3✔
311
                        }
312
                }
313
                if edge2 != nil {
6✔
314
                        chanAnns = append(chanAnns, edge2)
3✔
315

3✔
316
                        // If this edge has a validated node announcement, that
3✔
317
                        // we haven't yet sent, then we'll send that as well.
3✔
318
                        nodePub := channel.Node1.PubKeyBytes
3✔
319
                        hasNodeAnn := channel.Node1.HaveNodeAnnouncement
3✔
320
                        if _, ok := nodePubsSent[nodePub]; !ok && hasNodeAnn {
6✔
321
                                nodeAnn, err := channel.Node1.NodeAnnouncement(
3✔
322
                                        true,
3✔
323
                                )
3✔
324
                                if err != nil {
3✔
325
                                        return nil, err
×
326
                                }
×
327

328
                                err = netann.ValidateNodeAnnFields(nodeAnn)
3✔
329
                                if err == nil {
6✔
330
                                        chanAnns = append(chanAnns, nodeAnn)
3✔
331
                                        nodePubsSent[nodePub] = struct{}{}
3✔
332
                                }
3✔
333
                        }
334
                }
335
        }
336

337
        return chanAnns, nil
3✔
338
}
339

340
// FetchChanUpdates returns the latest channel update messages for the
341
// specified short channel ID. If no channel updates are known for the channel,
342
// then an empty slice will be returned.
343
//
344
// NOTE: This is part of the ChannelGraphTimeSeries interface.
345
func (c *ChanSeries) FetchChanUpdates(chain chainhash.Hash,
346
        shortChanID lnwire.ShortChannelID) ([]*lnwire.ChannelUpdate1, error) {
3✔
347

3✔
348
        chanInfo, e1, e2, err := c.graph.FetchChannelEdgesByID(
3✔
349
                shortChanID.ToUint64(),
3✔
350
        )
3✔
351
        if err != nil {
3✔
352
                return nil, err
×
353
        }
×
354

355
        chanUpdates := make([]*lnwire.ChannelUpdate1, 0, 2)
3✔
356
        if e1 != nil {
6✔
357
                chanUpdate, err := netann.ChannelUpdateFromEdge(chanInfo, e1)
3✔
358
                if err != nil {
3✔
359
                        return nil, err
×
360
                }
×
361

362
                chanUpdates = append(chanUpdates, chanUpdate)
3✔
363
        }
364
        if e2 != nil {
6✔
365
                chanUpdate, err := netann.ChannelUpdateFromEdge(chanInfo, e2)
3✔
366
                if err != nil {
3✔
367
                        return nil, err
×
368
                }
×
369

370
                chanUpdates = append(chanUpdates, chanUpdate)
3✔
371
        }
372

373
        return chanUpdates, nil
3✔
374
}
375

376
// A compile-time assertion to ensure that ChanSeries meets the
377
// ChannelGraphTimeSeries interface.
378
var _ ChannelGraphTimeSeries = (*ChanSeries)(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