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

lightningnetwork / lnd / 13414831183

19 Feb 2025 02:22PM UTC coverage: 58.821% (+0.03%) from 58.794%
13414831183

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

2730 of 3482 new or added lines in 9 files covered. (78.4%)

43 existing lines in 11 files now uncovered.

136278 of 231682 relevant lines covered (58.82%)

19276.58 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) {
177✔
74

177✔
75
        opts := defaultChanGraphOptions()
177✔
76
        for _, o := range options {
282✔
77
                o(opts)
105✔
78
        }
105✔
79

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

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

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

99
        return g, nil
177✔
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 {
177✔
106
        if !c.started.CompareAndSwap(false, true) {
177✔
UNCOV
107
                return nil
×
UNCOV
108
        }
×
109
        log.Debugf("ChannelGraph starting")
177✔
110
        defer log.Debug("ChannelGraph started")
177✔
111

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

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

177✔
122
        return nil
177✔
123
}
124

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

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

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

177✔
137
        return nil
177✔
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() {
177✔
146
        defer c.wg.Done()
177✔
147

177✔
148
        for {
5,300✔
149
                select {
5,123✔
150
                // A new fully validated topology update has just arrived.
151
                // We'll notify any registered clients.
152
                case update := <-c.topologyUpdate:
4,944✔
153
                        c.wg.Add(1)
4,944✔
154
                        go c.handleTopologyUpdate(update)
4,944✔
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:
8✔
164
                        clientID := ntfnUpdate.clientID
8✔
165

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

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

177
                                continue
4✔
178
                        }
179

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

185
                case <-c.quit:
177✔
186
                        return
177✔
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 {
144✔
195
        startTime := time.Now()
144✔
196
        log.Debugf("Populating in-memory channel graph, this might take a " +
144✔
197
                "while...")
144✔
198

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

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

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

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

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

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

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

144✔
224
        return nil
144✔
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 {
467✔
239

467✔
240
        if c.graphCache != nil {
931✔
241
                return c.graphCache.ForEachChannel(node, cb)
464✔
242
        }
464✔
243

244
        return c.KVStore.ForEachNodeDirectedChannel(node, cb)
6✔
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) {
456✔
255

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

260
        return c.KVStore.FetchNodeFeatures(node)
3✔
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 {
136✔
268
        if c.graphCache != nil {
218✔
269
                return cb(c)
82✔
270
        }
82✔
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 {
803✔
297

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

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

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

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

320
        return nil
802✔
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,719✔
346

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

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

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

362
        return nil
1,485✔
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 {
151✔
404

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

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

421
        return err
83✔
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) {
152✔
433

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

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

448
        return edges, nil
152✔
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) {
234✔
461

234✔
462
        edges, err := c.KVStore.PruneGraph(spentOutputs, blockHash, blockHeight)
234✔
463
        if err != nil {
234✔
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()
234✔
471
        if err != nil {
234✔
NEW
472
                return nil, err
×
473
        }
×
474

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

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

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

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

502
        return edges, nil
234✔
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 {
26✔
510
        nodes, err := c.KVStore.PruneGraphNodes()
26✔
511
        if err != nil {
26✔
512
                return err
×
513
        }
×
514

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

521
        return nil
26✔
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) {
130✔
531

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

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

40✔
553
                if isStillZombie {
67✔
554
                        continue
27✔
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(
13✔
562
                        info.ShortChannelID.ToUint64(),
13✔
563
                )
13✔
564
                // Since there is a chance that the edge could have been marked
13✔
565
                // as "live" between the FilterKnownChanIDs call and the
13✔
566
                // MarkEdgeLive call, we ignore the error if the edge is already
13✔
567
                // marked as live.
13✔
568
                if err != nil && !errors.Is(err, ErrZombieEdgeNotFound) {
13✔
NEW
569
                        return nil, err
×
NEW
570
                }
×
571
        }
572

573
        return unknown, nil
130✔
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,666✔
603

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

609
        if c.graphCache != nil {
4,940✔
610
                var isUpdate1 bool
2,277✔
611
                if edge.ChannelFlags&lnwire.ChanUpdateDirection == 0 {
3,419✔
612
                        isUpdate1 = true
1,142✔
613
                }
1,142✔
614

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

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

624
        return nil
2,663✔
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