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

lightningnetwork / lnd / 13416360603

19 Feb 2025 03:34PM UTC coverage: 58.686% (-0.1%) from 58.794%
13416360603

Pull #9529

github

ellemouton
graph/db: move Topology client management to ChannelGraph
Pull Request #9529: [Concept ACK 🙏 ] graph: move graph cache out of CRUD layer & move topology change subscription

2732 of 3486 new or added lines in 9 files covered. (78.37%)

358 existing lines in 29 files now uncovered.

135967 of 231686 relevant lines covered (58.69%)

19334.46 hits per line

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

86.24
/graph/db/graph.go
1
package graphdb
2

3
import (
4
        "errors"
5
        "fmt"
6
        "sync"
7
        "sync/atomic"
8
        "time"
9

10
        "github.com/btcsuite/btcd/chaincfg/chainhash"
11
        "github.com/btcsuite/btcd/wire"
12
        "github.com/lightningnetwork/lnd/batch"
13
        "github.com/lightningnetwork/lnd/graph/db/models"
14
        "github.com/lightningnetwork/lnd/kvdb"
15
        "github.com/lightningnetwork/lnd/lnutils"
16
        "github.com/lightningnetwork/lnd/lnwire"
17
        "github.com/lightningnetwork/lnd/routing/route"
18
)
19

20
// ErrChanGraphShuttingDown indicates that the ChannelGraph has shutdown or is
21
// busy shutting down.
22
var ErrChanGraphShuttingDown = fmt.Errorf("ChannelGraph shutting down")
23

24
// Config is a struct that holds all the necessary dependencies for a
25
// ChannelGraph.
26
type Config struct {
27
        // KVDB is the kvdb.Backend that will be used for initializing the
28
        // KVStore CRUD layer.
29
        KVDB kvdb.Backend
30

31
        // KVStoreOpts is a list of functional options that will be used when
32
        // initializing the KVStore.
33
        KVStoreOpts []KVStoreOptionModifier
34
}
35

36
// ChannelGraph is a layer above the graph's CRUD layer.
37
//
38
// NOTE: currently, this is purely a pass-through layer directly to the backing
39
// KVStore. Upcoming commits will move the graph cache out of the KVStore and
40
// into this layer so that the KVStore is only responsible for CRUD operations.
41
type ChannelGraph struct {
42
        started atomic.Bool
43
        stopped atomic.Bool
44

45
        graphCache *GraphCache
46

47
        *KVStore
48

49
        ntfnClientCounter atomic.Uint64
50

51
        // topologyUpdate is a channel that carries new topology updates
52
        // messages from outside the ChannelGraph to be processed by the
53
        // networkHandler.
54
        topologyUpdate chan any
55

56
        // topologyClients maps a client's unique notification ID to a
57
        // topologyClient client that contains its notification dispatch
58
        // channel.
59
        topologyClients *lnutils.SyncMap[uint64, *topologyClient]
60

61
        // ntfnClientUpdates is a channel that's used to send new updates to
62
        // topology notification clients to the ChannelGraph. Updates either
63
        // add a new notification client, or cancel notifications for an
64
        // existing client.
65
        ntfnClientUpdates chan *topologyClientUpdate
66

67
        quit chan struct{}
68
        wg   sync.WaitGroup
69
}
70

71
// NewChannelGraph creates a new ChannelGraph instance with the given backend.
72
func NewChannelGraph(cfg *Config, options ...ChanGraphOption) (*ChannelGraph,
73
        error) {
176✔
74

176✔
75
        opts := defaultChanGraphOptions()
176✔
76
        for _, o := range options {
280✔
77
                o(opts)
104✔
78
        }
104✔
79

80
        store, err := NewKVStore(cfg.KVDB, cfg.KVStoreOpts...)
176✔
81
        if err != nil {
176✔
NEW
82
                return nil, err
×
UNCOV
83
        }
×
84

85
        g := &ChannelGraph{
176✔
86
                KVStore:           store,
176✔
87
                topologyUpdate:    make(chan any),
176✔
88
                topologyClients:   &lnutils.SyncMap[uint64, *topologyClient]{},
176✔
89
                ntfnClientUpdates: make(chan *topologyClientUpdate),
176✔
90
                quit:              make(chan struct{}),
176✔
91
        }
176✔
92

176✔
93
        // The graph cache can be turned off (e.g. for mobile users) for a
176✔
94
        // speed/memory usage tradeoff.
176✔
95
        if opts.useGraphCache {
319✔
96
                g.graphCache = NewGraphCache(opts.preAllocCacheNumNodes)
143✔
97
        }
143✔
98

99
        return g, nil
176✔
100
}
101

102
// Start kicks off any goroutines required for the ChannelGraph to function.
103
// If the graph cache is enabled, then it will be populated with the contents of
104
// the database.
105
func (c *ChannelGraph) Start() error {
176✔
106
        if !c.started.CompareAndSwap(false, true) {
176✔
UNCOV
107
                return nil
×
UNCOV
108
        }
×
109
        log.Debugf("ChannelGraph starting")
176✔
110
        defer log.Debug("ChannelGraph started")
176✔
111

176✔
112
        if c.graphCache != nil {
319✔
113
                if err := c.populateCache(); err != nil {
143✔
NEW
114
                        return fmt.Errorf("could not populate the graph "+
×
NEW
115
                                "cache: %w", err)
×
116
                }
×
117
        }
118

119
        c.wg.Add(1)
176✔
120
        go c.handleTopologySubscriptions()
176✔
121

176✔
122
        return nil
176✔
123
}
124

125
// Stop signals any active goroutines for a graceful closure.
126
func (c *ChannelGraph) Stop() error {
176✔
127
        if !c.stopped.CompareAndSwap(false, true) {
176✔
NEW
128
                return nil
×
UNCOV
129
        }
×
130

131
        log.Debugf("ChannelGraph shutting down...")
176✔
132
        defer log.Debug("Builder shutdown complete")
176✔
133

176✔
134
        close(c.quit)
176✔
135
        c.wg.Wait()
176✔
136

176✔
137
        return nil
176✔
138
}
139

140
// handleTopologySubscriptions ensures that topology client subscriptions,
141
// subscription cancellations and topology notifications are handled
142
// synchronously.
143
//
144
// NOTE: this MUST be run in a goroutine.
145
func (c *ChannelGraph) handleTopologySubscriptions() {
176✔
146
        defer c.wg.Done()
176✔
147

176✔
148
        for {
5,296✔
149
                select {
5,120✔
150
                // A new fully validated topology update has just arrived.
151
                // We'll notify any registered clients.
152
                case update := <-c.topologyUpdate:
4,941✔
153
                        c.wg.Add(1)
4,941✔
154
                        go c.handleTopologyUpdate(update)
4,941✔
155

156
                        // TODO(roasbeef): remove all unconnected vertexes
157
                        // after N blocks pass with no corresponding
158
                        // announcements.
159

160
                // A new notification client update has arrived. We're either
161
                // gaining a new client, or cancelling notifications for an
162
                // existing client.
163
                case ntfnUpdate := <-c.ntfnClientUpdates:
7✔
164
                        clientID := ntfnUpdate.clientID
7✔
165

7✔
166
                        if ntfnUpdate.cancel {
10✔
167
                                client, ok := c.topologyClients.LoadAndDelete(
3✔
168
                                        clientID,
3✔
169
                                )
3✔
170
                                if ok {
6✔
171
                                        close(client.exit)
3✔
172
                                        client.wg.Wait()
3✔
173

3✔
174
                                        close(client.ntfnChan)
3✔
175
                                }
3✔
176

177
                                continue
3✔
178
                        }
179

180
                        c.topologyClients.Store(clientID, &topologyClient{
6✔
181
                                ntfnChan: ntfnUpdate.ntfnChan,
6✔
182
                                exit:     make(chan struct{}),
6✔
183
                        })
6✔
184

185
                case <-c.quit:
176✔
186
                        return
176✔
187
                }
188
        }
189
}
190

191
// populateCache loads the entire channel graph into the in-memory graph cache.
192
//
193
// NOTE: This should only be called if the graphCache has been constructed.
194
func (c *ChannelGraph) populateCache() error {
143✔
195
        startTime := time.Now()
143✔
196
        log.Debugf("Populating in-memory channel graph, this might take a " +
143✔
197
                "while...")
143✔
198

143✔
199
        err := c.KVStore.ForEachNodeCacheable(func(node route.Vertex,
143✔
200
                features *lnwire.FeatureVector) error {
245✔
201

102✔
202
                c.graphCache.AddNodeFeatures(node, features)
102✔
203

102✔
204
                return nil
102✔
205
        })
102✔
206
        if err != nil {
143✔
207
                return err
×
208
        }
×
209

210
        err = c.KVStore.ForEachChannel(func(info *models.ChannelEdgeInfo,
143✔
211
                policy1, policy2 *models.ChannelEdgePolicy) error {
541✔
212

398✔
213
                c.graphCache.AddChannel(info, policy1, policy2)
398✔
214

398✔
215
                return nil
398✔
216
        })
398✔
217
        if err != nil {
143✔
NEW
218
                return err
×
UNCOV
219
        }
×
220

221
        log.Debugf("Finished populating in-memory channel graph (took %v, %s)",
143✔
222
                time.Since(startTime), c.graphCache.Stats())
143✔
223

143✔
224
        return nil
143✔
225
}
226

227
// ForEachNodeDirectedChannel iterates through all channels of a given node,
228
// executing the passed callback on the directed edge representing the channel
229
// and its incoming policy. If the callback returns an error, then the iteration
230
// is halted with the error propagated back up to the caller. If the graphCache
231
// is available, then it will be used to retrieve the node's channels instead
232
// of the database.
233
//
234
// Unknown policies are passed into the callback as nil values.
235
//
236
// NOTE: this is part of the graphdb.NodeTraverser interface.
237
func (c *ChannelGraph) ForEachNodeDirectedChannel(node route.Vertex,
238
        cb func(channel *DirectedChannel) error) error {
466✔
239

466✔
240
        if c.graphCache != nil {
929✔
241
                return c.graphCache.ForEachChannel(node, cb)
463✔
242
        }
463✔
243

244
        return c.KVStore.ForEachNodeDirectedChannel(node, cb)
5✔
245
}
246

247
// FetchNodeFeatures returns the features of the given node. If no features are
248
// known for the node, an empty feature vector is returned.
249
// If the graphCache is available, then it will be used to retrieve the node's
250
// features instead of the database.
251
//
252
// NOTE: this is part of the graphdb.NodeTraverser interface.
253
func (c *ChannelGraph) FetchNodeFeatures(node route.Vertex) (
254
        *lnwire.FeatureVector, error) {
455✔
255

455✔
256
        if c.graphCache != nil {
910✔
257
                return c.graphCache.GetFeatures(node), nil
455✔
258
        }
455✔
259

260
        return c.KVStore.FetchNodeFeatures(node)
2✔
261
}
262

263
// GraphSession will provide the call-back with access to a NodeTraverser
264
// instance which can be used to perform queries against the channel graph. If
265
// the graph cache is not enabled, then the call-back will  be provided with
266
// access to the graph via a consistent read-only transaction.
267
func (c *ChannelGraph) GraphSession(cb func(graph NodeTraverser) error) error {
135✔
268
        if c.graphCache != nil {
216✔
269
                return cb(c)
81✔
270
        }
81✔
271

272
        return c.KVStore.GraphSession(cb)
54✔
273
}
274

275
// ForEachNodeCached iterates through all the stored vertices/nodes in the
276
// graph, executing the passed callback with each node encountered.
277
//
278
// NOTE: The callback contents MUST not be modified.
279
func (c *ChannelGraph) ForEachNodeCached(cb func(node route.Vertex,
280
        chans map[uint64]*DirectedChannel) error) error {
1✔
281

1✔
282
        if c.graphCache != nil {
1✔
283
                return c.graphCache.ForEachNode(cb)
×
284
        }
×
285

286
        return c.KVStore.ForEachNodeCached(cb)
1✔
287
}
288

289
// AddLightningNode adds a vertex/node to the graph database. If the node is not
290
// in the database from before, this will add a new, unconnected one to the
291
// graph. If it is present from before, this will update that node's
292
// information. Note that this method is expected to only be called to update an
293
// already present node from a node announcement, or to insert a node found in a
294
// channel update.
295
func (c *ChannelGraph) AddLightningNode(node *models.LightningNode,
296
        op ...batch.SchedulerOption) error {
802✔
297

802✔
298
        err := c.KVStore.AddLightningNode(node, op...)
802✔
299
        if err != nil {
802✔
NEW
300
                return err
×
NEW
301
        }
×
302

303
        if c.graphCache != nil {
1,417✔
304
                c.graphCache.AddNodeFeatures(
615✔
305
                        node.PubKeyBytes, node.Features,
615✔
306
                )
615✔
307
        }
615✔
308

309
        // No need to send topology updates for shell nodes.
310
        if !node.HaveNodeAnnouncement {
803✔
311
                return nil
1✔
312
        }
1✔
313

314
        select {
801✔
315
        case c.topologyUpdate <- node:
801✔
NEW
316
        case <-c.quit:
×
NEW
317
                return ErrChanGraphShuttingDown
×
318
        }
319

320
        return nil
801✔
321
}
322

323
// DeleteLightningNode starts a new database transaction to remove a vertex/node
324
// from the database according to the node's public key.
325
func (c *ChannelGraph) DeleteLightningNode(nodePub route.Vertex) error {
3✔
326
        err := c.KVStore.DeleteLightningNode(nodePub)
3✔
327
        if err != nil {
3✔
NEW
328
                return err
×
329
        }
×
330

331
        if c.graphCache != nil {
6✔
332
                c.graphCache.RemoveNode(nodePub)
3✔
333
        }
3✔
334

335
        return nil
3✔
336
}
337

338
// AddChannelEdge adds a new (undirected, blank) edge to the graph database. An
339
// undirected edge from the two target nodes are created. The information stored
340
// denotes the static attributes of the channel, such as the channelID, the keys
341
// involved in creation of the channel, and the set of features that the channel
342
// supports. The chanPoint and chanID are used to uniquely identify the edge
343
// globally within the database.
344
func (c *ChannelGraph) AddChannelEdge(edge *models.ChannelEdgeInfo,
345
        op ...batch.SchedulerOption) error {
1,716✔
346

1,716✔
347
        err := c.KVStore.AddChannelEdge(edge, op...)
1,716✔
348
        if err != nil {
1,950✔
349
                return err
234✔
350
        }
234✔
351

352
        if c.graphCache != nil {
2,774✔
353
                c.graphCache.AddChannel(edge, nil, nil)
1,292✔
354
        }
1,292✔
355

356
        select {
1,482✔
357
        case c.topologyUpdate <- edge:
1,482✔
NEW
358
        case <-c.quit:
×
NEW
359
                return ErrChanGraphShuttingDown
×
360
        }
361

362
        return nil
1,482✔
363
}
364

365
// MarkEdgeLive clears an edge from our zombie index, deeming it as live.
366
// If the cache is enabled, the edge will be added back to the graph cache if
367
// we still have a record of this channel in the DB.
368
func (c *ChannelGraph) MarkEdgeLive(chanID uint64) error {
2✔
369
        err := c.KVStore.MarkEdgeLive(chanID)
2✔
370
        if err != nil {
3✔
371
                return err
1✔
372
        }
1✔
373

374
        if c.graphCache != nil {
2✔
375
                // We need to add the channel back into our graph cache,
1✔
376
                // otherwise we won't use it for path finding.
1✔
377
                infos, err := c.KVStore.FetchChanInfos([]uint64{chanID})
1✔
378
                if err != nil {
1✔
379
                        return err
×
380
                }
×
381

382
                if len(infos) == 0 {
2✔
383
                        return nil
1✔
384
                }
1✔
385

NEW
386
                info := infos[0]
×
387

×
NEW
388
                c.graphCache.AddChannel(info.Info, info.Policy1, info.Policy2)
×
389
        }
390

NEW
391
        return nil
×
392
}
393

394
// DeleteChannelEdges removes edges with the given channel IDs from the
395
// database and marks them as zombies. This ensures that we're unable to re-add
396
// it to our database once again. If an edge does not exist within the
397
// database, then ErrEdgeNotFound will be returned. If strictZombiePruning is
398
// true, then when we mark these edges as zombies, we'll set up the keys such
399
// that we require the node that failed to send the fresh update to be the one
400
// that resurrects the channel from its zombie state. The markZombie bool
401
// denotes whether or not to mark the channel as a zombie.
402
func (c *ChannelGraph) DeleteChannelEdges(strictZombiePruning, markZombie bool,
403
        chanIDs ...uint64) error {
142✔
404

142✔
405
        infos, err := c.KVStore.DeleteChannelEdges(
142✔
406
                strictZombiePruning, markZombie, chanIDs...,
142✔
407
        )
142✔
408
        if err != nil {
202✔
409
                return err
60✔
410
        }
60✔
411

412
        if c.graphCache != nil {
164✔
413
                for _, info := range infos {
109✔
414
                        c.graphCache.RemoveChannel(
27✔
415
                                info.NodeKey1Bytes, info.NodeKey2Bytes,
27✔
416
                                info.ChannelID,
27✔
417
                        )
27✔
418
                }
27✔
419
        }
420

421
        return err
82✔
422
}
423

424
// DisconnectBlockAtHeight is used to indicate that the block specified
425
// by the passed height has been disconnected from the main chain. This
426
// will "rewind" the graph back to the height below, deleting channels
427
// that are no longer confirmed from the graph. The prune log will be
428
// set to the last prune height valid for the remaining chain.
429
// Channels that were removed from the graph resulting from the
430
// disconnected block are returned.
431
func (c *ChannelGraph) DisconnectBlockAtHeight(height uint32) (
432
        []*models.ChannelEdgeInfo, error) {
155✔
433

155✔
434
        edges, err := c.KVStore.DisconnectBlockAtHeight(height)
155✔
435
        if err != nil {
155✔
NEW
436
                return nil, err
×
UNCOV
437
        }
×
438

439
        if c.graphCache != nil {
310✔
440
                for _, edge := range edges {
250✔
441
                        c.graphCache.RemoveChannel(
95✔
442
                                edge.NodeKey1Bytes, edge.NodeKey2Bytes,
95✔
443
                                edge.ChannelID,
95✔
444
                        )
95✔
445
                }
95✔
446
        }
447

448
        return edges, nil
155✔
449
}
450

451
// PruneGraph prunes newly closed channels from the channel graph in response
452
// to a new block being solved on the network. Any transactions which spend the
453
// funding output of any known channels within he graph will be deleted.
454
// Additionally, the "prune tip", or the last block which has been used to
455
// prune the graph is stored so callers can ensure the graph is fully in sync
456
// with the current UTXO state. A slice of channels that have been closed by
457
// the target block are returned if the function succeeds without error.
458
func (c *ChannelGraph) PruneGraph(spentOutputs []*wire.OutPoint,
459
        blockHash *chainhash.Hash, blockHeight uint32) (
460
        []*models.ChannelEdgeInfo, error) {
241✔
461

241✔
462
        edges, err := c.KVStore.PruneGraph(spentOutputs, blockHash, blockHeight)
241✔
463
        if err != nil {
241✔
NEW
464
                return nil, err
×
465
        }
×
466

467
        // Now that the graph has been pruned, we'll also attempt to
468
        // prune any nodes that have had a channel closed within the
469
        // latest block.
470
        nodes, err := c.KVStore.PruneGraphNodes()
241✔
471
        if err != nil {
241✔
NEW
472
                return nil, err
×
473
        }
×
474

475
        if c.graphCache != nil {
482✔
476
                for _, edge := range edges {
263✔
477
                        c.graphCache.RemoveChannel(
22✔
478
                                edge.NodeKey1Bytes, edge.NodeKey2Bytes,
22✔
479
                                edge.ChannelID,
22✔
480
                        )
22✔
481
                }
22✔
482

483
                for _, node := range nodes {
296✔
484
                        c.graphCache.RemoveNode(node)
55✔
485
                }
55✔
486

487
                log.Debugf("Pruned graph, cache now has %s",
241✔
488
                        c.graphCache.Stats())
241✔
489
        }
490

491
        if len(edges) != 0 {
260✔
492
                // Notify all currently registered clients of the newly closed
19✔
493
                // channels.
19✔
494
                closeSummaries := createCloseSummaries(
19✔
495
                        blockHeight, edges...,
19✔
496
                )
19✔
497
                c.notifyTopologyChange(&TopologyChange{
19✔
498
                        ClosedChannels: closeSummaries,
19✔
499
                })
19✔
500
        }
19✔
501

502
        return edges, nil
241✔
503
}
504

505
// PruneGraphNodes is a garbage collection method which attempts to prune out
506
// any nodes from the channel graph that are currently unconnected. This ensure
507
// that we only maintain a graph of reachable nodes. In the event that a pruned
508
// node gains more channels, it will be re-added back to the graph.
509
func (c *ChannelGraph) PruneGraphNodes() error {
25✔
510
        nodes, err := c.KVStore.PruneGraphNodes()
25✔
511
        if err != nil {
25✔
512
                return err
×
513
        }
×
514

515
        if c.graphCache != nil {
50✔
516
                for _, node := range nodes {
32✔
517
                        c.graphCache.RemoveNode(node)
7✔
518
                }
7✔
519
        }
520

521
        return nil
25✔
522
}
523

524
// FilterKnownChanIDs takes a set of channel IDs and return the subset of chan
525
// ID's that we don't know and are not known zombies of the passed set. In other
526
// words, we perform a set difference of our set of chan ID's and the ones
527
// passed in. This method can be used by callers to determine the set of
528
// channels another peer knows of that we don't.
529
func (c *ChannelGraph) FilterKnownChanIDs(chansInfo []ChannelUpdateInfo,
530
        isZombieChan func(time.Time, time.Time) bool) ([]uint64, error) {
121✔
531

121✔
532
        unknown, knownZombies, err := c.KVStore.FilterKnownChanIDs(chansInfo)
121✔
533
        if err != nil {
121✔
534
                return nil, err
×
535
        }
×
536

537
        for _, info := range knownZombies {
166✔
538
                // TODO(ziggie): Make sure that for the strict pruning case we
45✔
539
                // compare the pubkeys and whether the right timestamp is not
45✔
540
                // older than the `ChannelPruneExpiry`.
45✔
541
                //
45✔
542
                // NOTE: The timestamp data has no verification attached to it
45✔
543
                // in the `ReplyChannelRange` msg so we are trusting this data
45✔
544
                // at this point. However it is not critical because we are just
45✔
545
                // removing the channel from the db when the timestamps are more
45✔
546
                // recent. During the querying of the gossip msg verification
45✔
547
                // happens as usual. However we should start punishing peers
45✔
548
                // when they don't provide us honest data ?
45✔
549
                isStillZombie := isZombieChan(
45✔
550
                        info.Node1UpdateTimestamp, info.Node2UpdateTimestamp,
45✔
551
                )
45✔
552

45✔
553
                if isStillZombie {
70✔
554
                        continue
25✔
555
                }
556

557
                // If we have marked it as a zombie but the latest update
558
                // timestamps could bring it back from the dead, then we mark it
559
                // alive, and we let it be added to the set of IDs to query our
560
                // peer for.
561
                err := c.KVStore.MarkEdgeLive(
20✔
562
                        info.ShortChannelID.ToUint64(),
20✔
563
                )
20✔
564
                // Since there is a chance that the edge could have been marked
20✔
565
                // as "live" between the FilterKnownChanIDs call and the
20✔
566
                // MarkEdgeLive call, we ignore the error if the edge is already
20✔
567
                // marked as live.
20✔
568
                if err != nil && !errors.Is(err, ErrZombieEdgeNotFound) {
20✔
NEW
569
                        return nil, err
×
NEW
570
                }
×
571
        }
572

573
        return unknown, nil
121✔
574
}
575

576
// MarkEdgeZombie attempts to mark a channel identified by its channel ID as a
577
// zombie. This method is used on an ad-hoc basis, when channels need to be
578
// marked as zombies outside the normal pruning cycle.
579
func (c *ChannelGraph) MarkEdgeZombie(chanID uint64,
580
        pubKey1, pubKey2 [33]byte) error {
133✔
581

133✔
582
        err := c.KVStore.MarkEdgeZombie(chanID, pubKey1, pubKey2)
133✔
583
        if err != nil {
133✔
NEW
584
                return err
×
585
        }
×
586

587
        if c.graphCache != nil {
266✔
588
                c.graphCache.RemoveChannel(pubKey1, pubKey2, chanID)
133✔
589
        }
133✔
590

591
        return nil
133✔
592
}
593

594
// UpdateEdgePolicy updates the edge routing policy for a single directed edge
595
// within the database for the referenced channel. The `flags` attribute within
596
// the ChannelEdgePolicy determines which of the directed edges are being
597
// updated. If the flag is 1, then the first node's information is being
598
// updated, otherwise it's the second node's information. The node ordering is
599
// determined by the lexicographical ordering of the identity public keys of the
600
// nodes on either side of the channel.
601
func (c *ChannelGraph) UpdateEdgePolicy(edge *models.ChannelEdgePolicy,
602
        op ...batch.SchedulerOption) error {
2,665✔
603

2,665✔
604
        from, to, err := c.KVStore.UpdateEdgePolicy(edge, op...)
2,665✔
605
        if err != nil {
2,668✔
606
                return err
3✔
607
        }
3✔
608

609
        if c.graphCache != nil {
4,938✔
610
                var isUpdate1 bool
2,276✔
611
                if edge.ChannelFlags&lnwire.ChanUpdateDirection == 0 {
3,417✔
612
                        isUpdate1 = true
1,141✔
613
                }
1,141✔
614

615
                c.graphCache.UpdatePolicy(edge, from, to, isUpdate1)
2,276✔
616
        }
617

618
        select {
2,662✔
619
        case c.topologyUpdate <- edge:
2,662✔
NEW
620
        case <-c.quit:
×
NEW
621
                return ErrChanGraphShuttingDown
×
622
        }
623

624
        return nil
2,662✔
625
}
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