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

lightningnetwork / lnd / 14471480810

15 Apr 2025 02:05PM UTC coverage: 58.611% (-10.5%) from 69.088%
14471480810

Pull #9702

github

web-flow
Merge 811aac3b1 into 014706cc3
Pull Request #9702: multi: make payment address mandatory

2 of 4 new or added lines in 1 file covered. (50.0%)

28451 existing lines in 450 files now uncovered.

97194 of 165828 relevant lines covered (58.61%)

1.82 hits per line

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

66.57
/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
56
}
57

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

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

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

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

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

84
        return g, nil
3✔
85
}
86

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

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

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

3✔
107
        return nil
3✔
108
}
109

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

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

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

3✔
122
        return nil
3✔
123
}
124

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

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

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

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

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

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

165
                                continue
3✔
166
                        }
167

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

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

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

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

3✔
190
                c.graphCache.AddNodeFeatures(node, features)
3✔
191

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

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

3✔
201
                c.graphCache.AddChannel(info, policy1, policy2)
3✔
202

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

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

3✔
212
        return nil
3✔
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
//
222
// Unknown policies are passed into the callback as nil values.
223
//
224
// NOTE: this is part of the graphdb.NodeTraverser interface.
225
func (c *ChannelGraph) ForEachNodeDirectedChannel(node route.Vertex,
226
        cb func(channel *DirectedChannel) error) error {
3✔
227

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

232
        return c.KVStore.ForEachNodeDirectedChannel(node, cb)
3✔
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
238
// features instead of the database.
239
//
240
// NOTE: this is part of the graphdb.NodeTraverser interface.
241
func (c *ChannelGraph) FetchNodeFeatures(node route.Vertex) (
242
        *lnwire.FeatureVector, error) {
3✔
243

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

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

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

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

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

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

UNCOV
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
280
// information. Note that this method is expected to only be called to update an
281
// already present node from a node announcement, or to insert a node found in a
282
// channel update.
283
func (c *ChannelGraph) AddLightningNode(node *models.LightningNode,
284
        op ...batch.SchedulerOption) error {
3✔
285

3✔
286
        c.cacheMu.Lock()
3✔
287
        defer c.cacheMu.Unlock()
3✔
288

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

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

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

306
        return nil
3✔
307
}
308

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

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

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

UNCOV
324
        return nil
×
325
}
326

327
// AddChannelEdge adds a new (undirected, blank) edge to the graph database. An
328
// undirected edge from the two target nodes are created. The information stored
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
331
// supports. The chanPoint and chanID are used to uniquely identify the edge
332
// globally within the database.
333
func (c *ChannelGraph) AddChannelEdge(edge *models.ChannelEdgeInfo,
334
        op ...batch.SchedulerOption) error {
3✔
335

3✔
336
        c.cacheMu.Lock()
3✔
337
        defer c.cacheMu.Unlock()
3✔
338

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

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

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

354
        return nil
3✔
355
}
356

357
// MarkEdgeLive clears an edge from our zombie index, deeming it as live.
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.
UNCOV
360
func (c *ChannelGraph) MarkEdgeLive(chanID uint64) error {
×
UNCOV
361
        c.cacheMu.Lock()
×
UNCOV
362
        defer c.cacheMu.Unlock()
×
UNCOV
363

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

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

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

381
                info := infos[0]
×
382

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

386
        return nil
×
387
}
388

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
391
// it to our database once again. If an edge does not exist within the
392
// database, then ErrEdgeNotFound will be returned. If strictZombiePruning is
393
// true, then when we mark these edges as zombies, we'll set up the keys such
394
// that we require the node that failed to send the fresh update to be the one
395
// that resurrects the channel from its zombie state. The markZombie bool
396
// denotes whether to mark the channel as a zombie.
397
func (c *ChannelGraph) DeleteChannelEdges(strictZombiePruning, markZombie bool,
398
        chanIDs ...uint64) error {
3✔
399

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

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

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

419
        return err
3✔
420
}
421

422
// DisconnectBlockAtHeight is used to indicate that the block specified
423
// by the passed height has been disconnected from the main chain. This
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.
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) {
2✔
431

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

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

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

449
        return edges, nil
2✔
450
}
451

452
// PruneGraph prunes newly closed channels from the channel graph in response
453
// to a new block being solved on the network. Any transactions which spend the
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
456
// prune the graph is stored so callers can ensure the graph is fully in sync
457
// with the current UTXO state. A slice of channels that have been closed by
458
// the target block are returned if the function succeeds without error.
459
func (c *ChannelGraph) PruneGraph(spentOutputs []*wire.OutPoint,
460
        blockHash *chainhash.Hash, blockHeight uint32) (
461
        []*models.ChannelEdgeInfo, error) {
3✔
462

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

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

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

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

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

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

500
        return edges, nil
3✔
501
}
502

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

3✔
511
        nodes, err := c.KVStore.PruneGraphNodes()
3✔
512
        if err != nil {
3✔
513
                return err
×
514
        }
×
515

516
        if c.graphCache != nil {
6✔
517
                for _, node := range nodes {
3✔
UNCOV
518
                        c.graphCache.RemoveNode(node)
×
UNCOV
519
                }
×
520
        }
521

522
        return nil
3✔
523
}
524

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

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

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

×
UNCOV
554
                if isStillZombie {
×
UNCOV
555
                        continue
×
556
                }
557

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

574
        return unknown, nil
3✔
575
}
576

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

×
UNCOV
583
        c.cacheMu.Lock()
×
UNCOV
584
        defer c.cacheMu.Unlock()
×
UNCOV
585

×
UNCOV
586
        err := c.KVStore.MarkEdgeZombie(chanID, pubKey1, pubKey2)
×
UNCOV
587
        if err != nil {
×
588
                return err
×
589
        }
×
590

UNCOV
591
        if c.graphCache != nil {
×
UNCOV
592
                c.graphCache.RemoveChannel(pubKey1, pubKey2, chanID)
×
UNCOV
593
        }
×
594

UNCOV
595
        return nil
×
596
}
597

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

3✔
608
        c.cacheMu.Lock()
3✔
609
        defer c.cacheMu.Unlock()
3✔
610

3✔
611
        from, to, err := c.KVStore.UpdateEdgePolicy(edge, op...)
3✔
612
        if err != nil {
3✔
UNCOV
613
                return err
×
UNCOV
614
        }
×
615

616
        if c.graphCache != nil {
6✔
617
                var isUpdate1 bool
3✔
618
                if edge.ChannelFlags&lnwire.ChanUpdateDirection == 0 {
6✔
619
                        isUpdate1 = true
3✔
620
                }
3✔
621

622
                c.graphCache.UpdatePolicy(edge, from, to, isUpdate1)
3✔
623
        }
624

625
        select {
3✔
626
        case c.topologyUpdate <- edge:
3✔
627
        case <-c.quit:
×
628
                return ErrChanGraphShuttingDown
×
629
        }
630

631
        return nil
3✔
632
}
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