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

lightningnetwork / lnd / 14994910928

13 May 2025 11:00AM UTC coverage: 68.991% (+10.4%) from 58.559%
14994910928

Pull #9752

github

web-flow
Merge ca77283bc into 1db6c31e2
Pull Request #9752: routerrpc: reject payment to invoice that don't have payment secret or blinded paths

6 of 7 new or added lines in 1 file covered. (85.71%)

959 existing lines in 12 files now uncovered.

133922 of 194116 relevant lines covered (68.99%)

22091.33 hits per line

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

86.11
/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/lnwire"
16
        "github.com/lightningnetwork/lnd/routing/route"
17
)
18

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

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

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

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

44
        // cacheMu guards any writes to the graphCache. It should be held
45
        // across the DB write call and the graphCache update to make the
46
        // two updates as atomic as possible.
47
        cacheMu sync.Mutex
48

49
        graphCache *GraphCache
50

51
        *KVStore
52
        *topologyManager
53

54
        quit chan struct{}
55
        wg   sync.WaitGroup
177✔
56
}
177✔
57

177✔
58
// NewChannelGraph creates a new ChannelGraph instance with the given backend.
282✔
59
func NewChannelGraph(cfg *Config, options ...ChanGraphOption) (*ChannelGraph,
105✔
60
        error) {
105✔
61

62
        opts := defaultChanGraphOptions()
177✔
63
        for _, o := range options {
177✔
UNCOV
64
                o(opts)
×
UNCOV
65
        }
×
66

67
        store, err := NewKVStore(cfg.KVDB, cfg.KVStoreOpts...)
177✔
68
        if err != nil {
177✔
69
                return nil, err
177✔
70
        }
177✔
71

177✔
72
        g := &ChannelGraph{
177✔
73
                KVStore:         store,
177✔
74
                topologyManager: newTopologyManager(),
177✔
75
                quit:            make(chan struct{}),
321✔
76
        }
144✔
77

144✔
78
        // The graph cache can be turned off (e.g. for mobile users) for a
79
        // speed/memory usage tradeoff.
177✔
80
        if opts.useGraphCache {
81
                g.graphCache = NewGraphCache(opts.preAllocCacheNumNodes)
82
        }
83

84
        return g, nil
85
}
177✔
86

177✔
UNCOV
87
// Start kicks off any goroutines required for the ChannelGraph to function.
×
UNCOV
88
// If the graph cache is enabled, then it will be populated with the contents of
×
89
// the database.
177✔
90
func (c *ChannelGraph) Start() error {
177✔
91
        if !c.started.CompareAndSwap(false, true) {
177✔
92
                return nil
321✔
93
        }
144✔
UNCOV
94
        log.Debugf("ChannelGraph starting")
×
UNCOV
95
        defer log.Debug("ChannelGraph started")
×
UNCOV
96

×
97
        if c.graphCache != nil {
98
                if err := c.populateCache(); err != nil {
99
                        return fmt.Errorf("could not populate the graph "+
177✔
100
                                "cache: %w", err)
177✔
101
                }
177✔
102
        }
177✔
103

104
        c.wg.Add(1)
105
        go c.handleTopologySubscriptions()
106

177✔
107
        return nil
177✔
UNCOV
108
}
×
UNCOV
109

×
110
// Stop signals any active goroutines for a graceful closure.
111
func (c *ChannelGraph) Stop() error {
177✔
112
        if !c.stopped.CompareAndSwap(false, true) {
177✔
113
                return nil
177✔
114
        }
177✔
115

177✔
116
        log.Debugf("ChannelGraph shutting down...")
177✔
117
        defer log.Debug("ChannelGraph shutdown complete")
177✔
118

119
        close(c.quit)
120
        c.wg.Wait()
121

122
        return nil
123
}
124

125
// handleTopologySubscriptions ensures that topology client subscriptions,
177✔
126
// subscription cancellations and topology notifications are handled
177✔
127
// synchronously.
177✔
128
//
5,314✔
129
// NOTE: this MUST be run in a goroutine.
5,137✔
130
func (c *ChannelGraph) handleTopologySubscriptions() {
131
        defer c.wg.Done()
132

4,958✔
133
        for {
4,958✔
134
                select {
4,958✔
135
                // A new fully validated topology update has just arrived.
4,958✔
136
                // We'll notify any registered clients.
4,958✔
137
                case update := <-c.topologyUpdate:
4,958✔
138
                        // TODO(elle): change topology handling to be handled
139
                        // synchronously so that we can guarantee the order of
140
                        // notification delivery.
141
                        c.wg.Add(1)
142
                        go c.handleTopologyUpdate(update)
143

144
                        // TODO(roasbeef): remove all unconnected vertexes
145
                        // after N blocks pass with no corresponding
146
                        // announcements.
8✔
147

8✔
148
                // A new notification client update has arrived. We're either
8✔
149
                // gaining a new client, or cancelling notifications for an
12✔
150
                // existing client.
4✔
151
                case ntfnUpdate := <-c.ntfnClientUpdates:
4✔
152
                        clientID := ntfnUpdate.clientID
4✔
153

8✔
154
                        if ntfnUpdate.cancel {
4✔
155
                                client, ok := c.topologyClients.LoadAndDelete(
4✔
156
                                        clientID,
4✔
157
                                )
4✔
158
                                if ok {
4✔
159
                                        close(client.exit)
160
                                        client.wg.Wait()
4✔
161

162
                                        close(client.ntfnChan)
163
                                }
7✔
164

7✔
165
                                continue
7✔
166
                        }
7✔
167

168
                        c.topologyClients.Store(clientID, &topologyClient{
177✔
169
                                ntfnChan: ntfnUpdate.ntfnChan,
177✔
170
                                exit:     make(chan struct{}),
171
                        })
172

173
                case <-c.quit:
174
                        return
175
                }
176
        }
177
}
144✔
178

144✔
179
// populateCache loads the entire channel graph into the in-memory graph cache.
144✔
180
//
144✔
181
// NOTE: This should only be called if the graphCache has been constructed.
144✔
182
func (c *ChannelGraph) populateCache() error {
144✔
183
        startTime := time.Now()
247✔
184
        log.Info("Populating in-memory channel graph, this might take a " +
103✔
185
                "while...")
103✔
186

103✔
187
        err := c.KVStore.ForEachNodeCacheable(func(node route.Vertex,
103✔
188
                features *lnwire.FeatureVector) error {
103✔
189

144✔
UNCOV
190
                c.graphCache.AddNodeFeatures(node, features)
×
UNCOV
191

×
192
                return nil
193
        })
144✔
194
        if err != nil {
543✔
195
                return err
399✔
196
        }
399✔
197

399✔
198
        err = c.KVStore.ForEachChannel(func(info *models.ChannelEdgeInfo,
399✔
199
                policy1, policy2 *models.ChannelEdgePolicy) error {
399✔
200

144✔
UNCOV
201
                c.graphCache.AddChannel(info, policy1, policy2)
×
UNCOV
202

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

209
        log.Infof("Finished populating in-memory channel graph (took %v, %s)",
210
                time.Since(startTime), c.graphCache.Stats())
211

212
        return nil
213
}
214

215
// ForEachNodeDirectedChannel iterates through all channels of a given node,
216
// executing the passed callback on the directed edge representing the channel
217
// and its incoming policy. If the callback returns an error, then the iteration
218
// is halted with the error propagated back up to the caller. If the graphCache
219
// is available, then it will be used to retrieve the node's channels instead
220
// of the database.
221
//
467✔
222
// Unknown policies are passed into the callback as nil values.
467✔
223
//
931✔
224
// NOTE: this is part of the graphdb.NodeTraverser interface.
464✔
225
func (c *ChannelGraph) ForEachNodeDirectedChannel(node route.Vertex,
464✔
226
        cb func(channel *DirectedChannel) error) error {
227

6✔
228
        if c.graphCache != nil {
229
                return c.graphCache.ForEachChannel(node, cb)
230
        }
231

232
        return c.KVStore.ForEachNodeDirectedChannel(node, cb)
233
}
234

235
// FetchNodeFeatures returns the features of the given node. If no features are
236
// known for the node, an empty feature vector is returned.
237
// If the graphCache is available, then it will be used to retrieve the node's
456✔
238
// features instead of the database.
456✔
239
//
912✔
240
// NOTE: this is part of the graphdb.NodeTraverser interface.
456✔
241
func (c *ChannelGraph) FetchNodeFeatures(node route.Vertex) (
456✔
242
        *lnwire.FeatureVector, error) {
243

3✔
244
        if c.graphCache != nil {
245
                return c.graphCache.GetFeatures(node), nil
246
        }
247

248
        return c.KVStore.FetchNodeFeatures(node)
249
}
250

136✔
251
// GraphSession will provide the call-back with access to a NodeTraverser
218✔
252
// instance which can be used to perform queries against the channel graph. If
82✔
253
// the graph cache is not enabled, then the call-back will be provided with
82✔
254
// access to the graph via a consistent read-only transaction.
255
func (c *ChannelGraph) GraphSession(cb func(graph NodeTraverser) error) error {
54✔
256
        if c.graphCache != nil {
257
                return cb(c)
258
        }
259

260
        return c.KVStore.GraphSession(cb)
261
}
262

263
// ForEachNodeCached iterates through all the stored vertices/nodes in the
1✔
264
// graph, executing the passed callback with each node encountered.
1✔
265
//
1✔
UNCOV
266
// NOTE: The callback contents MUST not be modified.
×
UNCOV
267
func (c *ChannelGraph) ForEachNodeCached(cb func(node route.Vertex,
×
268
        chans map[uint64]*DirectedChannel) error) error {
269

1✔
270
        if c.graphCache != nil {
271
                return c.graphCache.ForEachNode(cb)
272
        }
273

274
        return c.KVStore.ForEachNodeCached(cb)
275
}
276

277
// AddLightningNode adds a vertex/node to the graph database. If the node is not
278
// in the database from before, this will add a new, unconnected one to the
279
// graph. If it is present from before, this will update that node's
802✔
280
// information. Note that this method is expected to only be called to update an
802✔
281
// already present node from a node announcement, or to insert a node found in a
802✔
282
// channel update.
802✔
UNCOV
283
func (c *ChannelGraph) AddLightningNode(node *models.LightningNode,
×
UNCOV
284
        op ...batch.SchedulerOption) error {
×
285

286
        c.cacheMu.Lock()
1,417✔
287
        defer c.cacheMu.Unlock()
615✔
288

615✔
289
        err := c.KVStore.AddLightningNode(node, op...)
615✔
290
        if err != nil {
615✔
291
                return err
292
        }
802✔
293

802✔
UNCOV
294
        if c.graphCache != nil {
×
UNCOV
295
                c.graphCache.AddNodeFeatures(
×
296
                        node.PubKeyBytes, node.Features,
297
                )
298
        }
802✔
299

300
        select {
301
        case c.topologyUpdate <- node:
302
        case <-c.quit:
303
                return ErrChanGraphShuttingDown
3✔
304
        }
3✔
305

3✔
UNCOV
306
        return nil
×
UNCOV
307
}
×
308

309
// DeleteLightningNode starts a new database transaction to remove a vertex/node
6✔
310
// from the database according to the node's public key.
3✔
311
func (c *ChannelGraph) DeleteLightningNode(nodePub route.Vertex) error {
3✔
312
        c.cacheMu.Lock()
313
        defer c.cacheMu.Unlock()
3✔
314

315
        err := c.KVStore.DeleteLightningNode(nodePub)
316
        if err != nil {
317
                return err
318
        }
319

320
        if c.graphCache != nil {
321
                c.graphCache.RemoveNode(nodePub)
322
        }
323

1,716✔
324
        return nil
1,716✔
325
}
1,716✔
326

1,950✔
327
// AddChannelEdge adds a new (undirected, blank) edge to the graph database. An
234✔
328
// undirected edge from the two target nodes are created. The information stored
234✔
329
// denotes the static attributes of the channel, such as the channelID, the keys
330
// involved in creation of the channel, and the set of features that the channel
2,774✔
331
// supports. The chanPoint and chanID are used to uniquely identify the edge
1,292✔
332
// globally within the database.
1,292✔
333
func (c *ChannelGraph) AddChannelEdge(edge *models.ChannelEdgeInfo,
334
        op ...batch.SchedulerOption) error {
1,482✔
335

1,482✔
UNCOV
336
        c.cacheMu.Lock()
×
UNCOV
337
        defer c.cacheMu.Unlock()
×
338

339
        err := c.KVStore.AddChannelEdge(edge, op...)
340
        if err != nil {
1,482✔
341
                return err
342
        }
343

344
        if c.graphCache != nil {
345
                c.graphCache.AddChannel(edge, nil, nil)
346
        }
2✔
347

2✔
348
        select {
3✔
349
        case c.topologyUpdate <- edge:
1✔
350
        case <-c.quit:
1✔
351
                return ErrChanGraphShuttingDown
352
        }
2✔
353

1✔
354
        return nil
1✔
355
}
1✔
356

1✔
UNCOV
357
// MarkEdgeLive clears an edge from our zombie index, deeming it as live.
×
UNCOV
358
// If the cache is enabled, the edge will be added back to the graph cache if
×
359
// we still have a record of this channel in the DB.
360
func (c *ChannelGraph) MarkEdgeLive(chanID uint64) error {
2✔
361
        c.cacheMu.Lock()
1✔
362
        defer c.cacheMu.Unlock()
1✔
363

364
        err := c.KVStore.MarkEdgeLive(chanID)
×
365
        if err != nil {
×
366
                return err
×
367
        }
368

369
        if c.graphCache != nil {
×
370
                // We need to add the channel back into our graph cache,
371
                // otherwise we won't use it for path finding.
372
                infos, err := c.KVStore.FetchChanInfos([]uint64{chanID})
373
                if err != nil {
374
                        return err
375
                }
376

377
                if len(infos) == 0 {
378
                        return nil
379
                }
380

381
                info := infos[0]
149✔
382

149✔
383
                c.graphCache.AddChannel(info.Info, info.Policy1, info.Policy2)
149✔
384
        }
149✔
385

149✔
386
        return nil
215✔
387
}
66✔
388

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

83✔
400
        c.cacheMu.Lock()
401
        defer c.cacheMu.Unlock()
402

403
        infos, err := c.KVStore.DeleteChannelEdges(
404
                strictZombiePruning, markZombie, chanIDs...,
405
        )
406
        if err != nil {
407
                return err
408
        }
409

410
        if c.graphCache != nil {
158✔
411
                for _, info := range infos {
158✔
412
                        c.graphCache.RemoveChannel(
158✔
413
                                info.NodeKey1Bytes, info.NodeKey2Bytes,
158✔
UNCOV
414
                                info.ChannelID,
×
UNCOV
415
                        )
×
416
                }
417
        }
316✔
418

249✔
419
        return err
91✔
420
}
91✔
421

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

432
        c.cacheMu.Lock()
433
        defer c.cacheMu.Unlock()
434

435
        edges, err := c.KVStore.DisconnectBlockAtHeight(height)
436
        if err != nil {
437
                return nil, err
438
        }
248✔
439

248✔
440
        if c.graphCache != nil {
248✔
441
                for _, edge := range edges {
248✔
442
                        c.graphCache.RemoveChannel(
248✔
443
                                edge.NodeKey1Bytes, edge.NodeKey2Bytes,
248✔
UNCOV
444
                                edge.ChannelID,
×
UNCOV
445
                        )
×
446
                }
447
        }
496✔
448

273✔
449
        return edges, nil
25✔
450
}
25✔
451

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

463
        c.cacheMu.Lock()
268✔
464
        defer c.cacheMu.Unlock()
20✔
465

20✔
466
        edges, nodes, err := c.KVStore.PruneGraph(
20✔
467
                spentOutputs, blockHash, blockHeight,
20✔
468
        )
20✔
469
        if err != nil {
20✔
470
                return nil, err
20✔
471
        }
20✔
UNCOV
472

×
UNCOV
473
        if c.graphCache != nil {
×
474
                for _, edge := range edges {
475
                        c.graphCache.RemoveChannel(
476
                                edge.NodeKey1Bytes, edge.NodeKey2Bytes,
477
                                edge.ChannelID,
248✔
478
                        )
479
                }
480

481
                for _, node := range nodes {
482
                        c.graphCache.RemoveNode(node)
483
                }
484

26✔
485
                log.Debugf("Pruned graph, cache now has %s",
26✔
486
                        c.graphCache.Stats())
26✔
UNCOV
487
        }
×
UNCOV
488

×
489
        if len(edges) != 0 {
490
                // Notify all currently registered clients of the newly closed
52✔
491
                // channels.
33✔
492
                closeSummaries := createCloseSummaries(
7✔
493
                        blockHeight, edges...,
7✔
494
                )
495

496
                select {
26✔
497
                case c.topologyUpdate <- closeSummaries:
498
                case <-c.quit:
499
                        return nil, ErrChanGraphShuttingDown
500
                }
501
        }
502

503
        return edges, nil
504
}
505

124✔
506
// PruneGraphNodes is a garbage collection method which attempts to prune out
124✔
507
// any nodes from the channel graph that are currently unconnected. This ensure
124✔
508
// that we only maintain a graph of reachable nodes. In the event that a pruned
124✔
UNCOV
509
// node gains more channels, it will be re-added back to the graph.
×
UNCOV
510
func (c *ChannelGraph) PruneGraphNodes() error {
×
511
        c.cacheMu.Lock()
512
        defer c.cacheMu.Unlock()
170✔
513

46✔
514
        nodes, err := c.KVStore.PruneGraphNodes()
46✔
515
        if err != nil {
46✔
516
                return err
46✔
517
        }
46✔
518

46✔
519
        if c.graphCache != nil {
46✔
520
                for _, node := range nodes {
46✔
521
                        c.graphCache.RemoveNode(node)
46✔
522
                }
46✔
523
        }
46✔
524

46✔
525
        return nil
46✔
526
}
46✔
527

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

536
        unknown, knownZombies, err := c.KVStore.FilterKnownChanIDs(chansInfo)
18✔
537
        if err != nil {
18✔
538
                return nil, err
18✔
539
        }
18✔
540

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

129✔
557
                if isStillZombie {
129✔
558
                        continue
129✔
UNCOV
559
                }
×
UNCOV
560

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

577
        return unknown, nil
2,666✔
578
}
2,666✔
579

2,666✔
580
// MarkEdgeZombie attempts to mark a channel identified by its channel ID as a
2,669✔
581
// zombie. This method is used on an ad-hoc basis, when channels need to be
3✔
582
// marked as zombies outside the normal pruning cycle.
3✔
583
func (c *ChannelGraph) MarkEdgeZombie(chanID uint64,
584
        pubKey1, pubKey2 [33]byte) error {
4,940✔
585

2,277✔
586
        c.cacheMu.Lock()
3,419✔
587
        defer c.cacheMu.Unlock()
1,142✔
588

1,142✔
589
        err := c.KVStore.MarkEdgeZombie(chanID, pubKey1, pubKey2)
590
        if err != nil {
2,277✔
591
                return err
592
        }
593

2,663✔
594
        if c.graphCache != nil {
2,663✔
595
                c.graphCache.RemoveChannel(pubKey1, pubKey2, chanID)
×
596
        }
×
597

598
        return nil
599
}
2,663✔
600

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

611
        c.cacheMu.Lock()
612
        defer c.cacheMu.Unlock()
613

614
        from, to, err := c.KVStore.UpdateEdgePolicy(edge, op...)
615
        if err != nil {
616
                return err
617
        }
618

619
        if c.graphCache != nil {
620
                var isUpdate1 bool
621
                if edge.ChannelFlags&lnwire.ChanUpdateDirection == 0 {
622
                        isUpdate1 = true
623
                }
624

625
                c.graphCache.UpdatePolicy(edge, from, to, isUpdate1)
626
        }
627

628
        select {
629
        case c.topologyUpdate <- edge:
630
        case <-c.quit:
631
                return ErrChanGraphShuttingDown
632
        }
633

634
        return nil
635
}
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