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

lightningnetwork / lnd / 12012751795

25 Nov 2024 02:40PM UTC coverage: 49.835% (-9.2%) from 59.013%
12012751795

Pull #9303

github

yyforyongyu
lnwallet: add debug logs
Pull Request #9303: htlcswitch+routing: handle nil pointer dereference properly

20 of 23 new or added lines in 4 files covered. (86.96%)

25467 existing lines in 425 files now uncovered.

99835 of 200331 relevant lines covered (49.84%)

2.07 hits per line

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

1.29
/autopilot/graph.go
1
package autopilot
2

3
import (
4
        "bytes"
5
        "encoding/hex"
6
        "net"
7
        "sort"
8
        "sync/atomic"
9
        "time"
10

11
        "github.com/btcsuite/btcd/btcec/v2"
12
        "github.com/btcsuite/btcd/btcec/v2/ecdsa"
13
        "github.com/btcsuite/btcd/btcutil"
14
        "github.com/lightningnetwork/lnd/channeldb"
15
        "github.com/lightningnetwork/lnd/channeldb/models"
16
        "github.com/lightningnetwork/lnd/kvdb"
17
        "github.com/lightningnetwork/lnd/lnwire"
18
        "github.com/lightningnetwork/lnd/routing/route"
19
)
20

21
var (
22
        testRBytes, _ = hex.DecodeString("8ce2bc69281ce27da07e6683571319d18e949ddfa2965fb6caa1bf0314f882d7")
23
        testSBytes, _ = hex.DecodeString("299105481d63e0f4bc2a88121167221b6700d72a0ead154c03be696a292d24ae")
24
        testRScalar   = new(btcec.ModNScalar)
25
        testSScalar   = new(btcec.ModNScalar)
26
        _             = testRScalar.SetByteSlice(testRBytes)
27
        _             = testSScalar.SetByteSlice(testSBytes)
28
        testSig       = ecdsa.NewSignature(testRScalar, testSScalar)
29

30
        chanIDCounter uint64 // To be used atomically.
31
)
32

33
// databaseChannelGraph wraps a channeldb.ChannelGraph instance with the
34
// necessary API to properly implement the autopilot.ChannelGraph interface.
35
//
36
// TODO(roasbeef): move inmpl to main package?
37
type databaseChannelGraph struct {
38
        db *channeldb.ChannelGraph
39
}
40

41
// A compile time assertion to ensure databaseChannelGraph meets the
42
// autopilot.ChannelGraph interface.
43
var _ ChannelGraph = (*databaseChannelGraph)(nil)
44

45
// ChannelGraphFromDatabase returns an instance of the autopilot.ChannelGraph
46
// backed by a live, open channeldb instance.
47
func ChannelGraphFromDatabase(db *channeldb.ChannelGraph) ChannelGraph {
4✔
48
        return &databaseChannelGraph{
4✔
49
                db: db,
4✔
50
        }
4✔
51
}
4✔
52

53
// type dbNode is a wrapper struct around a database transaction an
54
// channeldb.LightningNode. The wrapper method implement the autopilot.Node
55
// interface.
56
type dbNode struct {
57
        db *channeldb.ChannelGraph
58

59
        tx kvdb.RTx
60

61
        node *channeldb.LightningNode
62
}
63

64
// A compile time assertion to ensure dbNode meets the autopilot.Node
65
// interface.
66
var _ Node = (*dbNode)(nil)
67

68
// PubKey is the identity public key of the node. This will be used to attempt
69
// to target a node for channel opening by the main autopilot agent. The key
70
// will be returned in serialized compressed format.
71
//
72
// NOTE: Part of the autopilot.Node interface.
UNCOV
73
func (d *dbNode) PubKey() [33]byte {
×
UNCOV
74
        return d.node.PubKeyBytes
×
UNCOV
75
}
×
76

77
// Addrs returns a slice of publicly reachable public TCP addresses that the
78
// peer is known to be listening on.
79
//
80
// NOTE: Part of the autopilot.Node interface.
81
func (d *dbNode) Addrs() []net.Addr {
×
82
        return d.node.Addresses
×
83
}
×
84

85
// ForEachChannel is a higher-order function that will be used to iterate
86
// through all edges emanating from/to the target node. For each active
87
// channel, this function should be called with the populated ChannelEdge that
88
// describes the active channel.
89
//
90
// NOTE: Part of the autopilot.Node interface.
UNCOV
91
func (d *dbNode) ForEachChannel(cb func(ChannelEdge) error) error {
×
UNCOV
92
        return d.db.ForEachNodeChannelTx(d.tx, d.node.PubKeyBytes,
×
UNCOV
93
                func(tx kvdb.RTx, ei *models.ChannelEdgeInfo, ep,
×
UNCOV
94
                        _ *models.ChannelEdgePolicy) error {
×
UNCOV
95

×
UNCOV
96
                        // Skip channels for which no outgoing edge policy is
×
UNCOV
97
                        // available.
×
UNCOV
98
                        //
×
UNCOV
99
                        // TODO(joostjager): Ideally the case where channels
×
UNCOV
100
                        // have a nil policy should be supported, as autopilot
×
UNCOV
101
                        // is not looking at the policies. For now, it is not
×
UNCOV
102
                        // easily possible to get a reference to the other end
×
UNCOV
103
                        // LightningNode object without retrieving the policy.
×
UNCOV
104
                        if ep == nil {
×
105
                                return nil
×
106
                        }
×
107

UNCOV
108
                        node, err := d.db.FetchLightningNodeTx(
×
UNCOV
109
                                tx, ep.ToNode,
×
UNCOV
110
                        )
×
UNCOV
111
                        if err != nil {
×
112
                                return err
×
113
                        }
×
114

UNCOV
115
                        edge := ChannelEdge{
×
UNCOV
116
                                ChanID: lnwire.NewShortChanIDFromInt(
×
UNCOV
117
                                        ep.ChannelID,
×
UNCOV
118
                                ),
×
UNCOV
119
                                Capacity: ei.Capacity,
×
UNCOV
120
                                Peer: &dbNode{
×
UNCOV
121
                                        tx:   tx,
×
UNCOV
122
                                        db:   d.db,
×
UNCOV
123
                                        node: node,
×
UNCOV
124
                                },
×
UNCOV
125
                        }
×
UNCOV
126

×
UNCOV
127
                        return cb(edge)
×
128
                })
129
}
130

131
// ForEachNode is a higher-order function that should be called once for each
132
// connected node within the channel graph. If the passed callback returns an
133
// error, then execution should be terminated.
134
//
135
// NOTE: Part of the autopilot.ChannelGraph interface.
UNCOV
136
func (d *databaseChannelGraph) ForEachNode(cb func(Node) error) error {
×
UNCOV
137
        return d.db.ForEachNode(func(tx kvdb.RTx, n *channeldb.LightningNode) error {
×
UNCOV
138
                // We'll skip over any node that doesn't have any advertised
×
UNCOV
139
                // addresses. As we won't be able to reach them to actually
×
UNCOV
140
                // open any channels.
×
UNCOV
141
                if len(n.Addresses) == 0 {
×
142
                        return nil
×
143
                }
×
144

UNCOV
145
                node := &dbNode{
×
UNCOV
146
                        db:   d.db,
×
UNCOV
147
                        tx:   tx,
×
UNCOV
148
                        node: n,
×
UNCOV
149
                }
×
UNCOV
150
                return cb(node)
×
151
        })
152
}
153

154
// addRandChannel creates a new channel two target nodes. This function is
155
// meant to aide in the generation of random graphs for use within test cases
156
// the exercise the autopilot package.
157
func (d *databaseChannelGraph) addRandChannel(node1, node2 *btcec.PublicKey,
UNCOV
158
        capacity btcutil.Amount) (*ChannelEdge, *ChannelEdge, error) {
×
UNCOV
159

×
UNCOV
160
        fetchNode := func(pub *btcec.PublicKey) (*channeldb.LightningNode, error) {
×
UNCOV
161
                if pub != nil {
×
UNCOV
162
                        vertex, err := route.NewVertexFromBytes(
×
UNCOV
163
                                pub.SerializeCompressed(),
×
UNCOV
164
                        )
×
UNCOV
165
                        if err != nil {
×
166
                                return nil, err
×
167
                        }
×
168

UNCOV
169
                        dbNode, err := d.db.FetchLightningNode(vertex)
×
UNCOV
170
                        switch {
×
171
                        case err == channeldb.ErrGraphNodeNotFound:
×
172
                                fallthrough
×
173
                        case err == channeldb.ErrGraphNotFound:
×
174
                                graphNode := &channeldb.LightningNode{
×
175
                                        HaveNodeAnnouncement: true,
×
176
                                        Addresses: []net.Addr{
×
177
                                                &net.TCPAddr{
×
178
                                                        IP: bytes.Repeat([]byte("a"), 16),
×
179
                                                },
×
180
                                        },
×
181
                                        Features: lnwire.NewFeatureVector(
×
182
                                                nil, lnwire.Features,
×
183
                                        ),
×
184
                                        AuthSigBytes: testSig.Serialize(),
×
185
                                }
×
186
                                graphNode.AddPubKey(pub)
×
187
                                if err := d.db.AddLightningNode(graphNode); err != nil {
×
188
                                        return nil, err
×
189
                                }
×
190
                        case err != nil:
×
191
                                return nil, err
×
192
                        }
193

UNCOV
194
                        return dbNode, nil
×
195
                }
196

UNCOV
197
                nodeKey, err := randKey()
×
UNCOV
198
                if err != nil {
×
199
                        return nil, err
×
200
                }
×
UNCOV
201
                dbNode := &channeldb.LightningNode{
×
UNCOV
202
                        HaveNodeAnnouncement: true,
×
UNCOV
203
                        Addresses: []net.Addr{
×
UNCOV
204
                                &net.TCPAddr{
×
UNCOV
205
                                        IP: bytes.Repeat([]byte("a"), 16),
×
UNCOV
206
                                },
×
UNCOV
207
                        },
×
UNCOV
208
                        Features: lnwire.NewFeatureVector(
×
UNCOV
209
                                nil, lnwire.Features,
×
UNCOV
210
                        ),
×
UNCOV
211
                        AuthSigBytes: testSig.Serialize(),
×
UNCOV
212
                }
×
UNCOV
213
                dbNode.AddPubKey(nodeKey)
×
UNCOV
214
                if err := d.db.AddLightningNode(dbNode); err != nil {
×
215
                        return nil, err
×
216
                }
×
217

UNCOV
218
                return dbNode, nil
×
219
        }
220

UNCOV
221
        vertex1, err := fetchNode(node1)
×
UNCOV
222
        if err != nil {
×
223
                return nil, nil, err
×
224
        }
×
225

UNCOV
226
        vertex2, err := fetchNode(node2)
×
UNCOV
227
        if err != nil {
×
228
                return nil, nil, err
×
229
        }
×
230

UNCOV
231
        var lnNode1, lnNode2 *btcec.PublicKey
×
UNCOV
232
        if bytes.Compare(vertex1.PubKeyBytes[:], vertex2.PubKeyBytes[:]) == -1 {
×
UNCOV
233
                lnNode1, _ = vertex1.PubKey()
×
UNCOV
234
                lnNode2, _ = vertex2.PubKey()
×
UNCOV
235
        } else {
×
UNCOV
236
                lnNode1, _ = vertex2.PubKey()
×
UNCOV
237
                lnNode2, _ = vertex1.PubKey()
×
UNCOV
238
        }
×
239

UNCOV
240
        chanID := randChanID()
×
UNCOV
241
        edge := &models.ChannelEdgeInfo{
×
UNCOV
242
                ChannelID: chanID.ToUint64(),
×
UNCOV
243
                Capacity:  capacity,
×
UNCOV
244
        }
×
UNCOV
245
        edge.AddNodeKeys(lnNode1, lnNode2, lnNode1, lnNode2)
×
UNCOV
246
        if err := d.db.AddChannelEdge(edge); err != nil {
×
247
                return nil, nil, err
×
248
        }
×
UNCOV
249
        edgePolicy := &models.ChannelEdgePolicy{
×
UNCOV
250
                SigBytes:                  testSig.Serialize(),
×
UNCOV
251
                ChannelID:                 chanID.ToUint64(),
×
UNCOV
252
                LastUpdate:                time.Now(),
×
UNCOV
253
                TimeLockDelta:             10,
×
UNCOV
254
                MinHTLC:                   1,
×
UNCOV
255
                MaxHTLC:                   lnwire.NewMSatFromSatoshis(capacity),
×
UNCOV
256
                FeeBaseMSat:               10,
×
UNCOV
257
                FeeProportionalMillionths: 10000,
×
UNCOV
258
                MessageFlags:              1,
×
UNCOV
259
                ChannelFlags:              0,
×
UNCOV
260
        }
×
UNCOV
261

×
UNCOV
262
        if err := d.db.UpdateEdgePolicy(edgePolicy); err != nil {
×
263
                return nil, nil, err
×
264
        }
×
UNCOV
265
        edgePolicy = &models.ChannelEdgePolicy{
×
UNCOV
266
                SigBytes:                  testSig.Serialize(),
×
UNCOV
267
                ChannelID:                 chanID.ToUint64(),
×
UNCOV
268
                LastUpdate:                time.Now(),
×
UNCOV
269
                TimeLockDelta:             10,
×
UNCOV
270
                MinHTLC:                   1,
×
UNCOV
271
                MaxHTLC:                   lnwire.NewMSatFromSatoshis(capacity),
×
UNCOV
272
                FeeBaseMSat:               10,
×
UNCOV
273
                FeeProportionalMillionths: 10000,
×
UNCOV
274
                MessageFlags:              1,
×
UNCOV
275
                ChannelFlags:              1,
×
UNCOV
276
        }
×
UNCOV
277
        if err := d.db.UpdateEdgePolicy(edgePolicy); err != nil {
×
278
                return nil, nil, err
×
279
        }
×
280

UNCOV
281
        return &ChannelEdge{
×
UNCOV
282
                        ChanID:   chanID,
×
UNCOV
283
                        Capacity: capacity,
×
UNCOV
284
                        Peer: &dbNode{
×
UNCOV
285
                                db:   d.db,
×
UNCOV
286
                                node: vertex1,
×
UNCOV
287
                        },
×
UNCOV
288
                },
×
UNCOV
289
                &ChannelEdge{
×
UNCOV
290
                        ChanID:   chanID,
×
UNCOV
291
                        Capacity: capacity,
×
UNCOV
292
                        Peer: &dbNode{
×
UNCOV
293
                                db:   d.db,
×
UNCOV
294
                                node: vertex2,
×
UNCOV
295
                        },
×
UNCOV
296
                },
×
UNCOV
297
                nil
×
298
}
299

UNCOV
300
func (d *databaseChannelGraph) addRandNode() (*btcec.PublicKey, error) {
×
UNCOV
301
        nodeKey, err := randKey()
×
UNCOV
302
        if err != nil {
×
303
                return nil, err
×
304
        }
×
UNCOV
305
        dbNode := &channeldb.LightningNode{
×
UNCOV
306
                HaveNodeAnnouncement: true,
×
UNCOV
307
                Addresses: []net.Addr{
×
UNCOV
308
                        &net.TCPAddr{
×
UNCOV
309
                                IP: bytes.Repeat([]byte("a"), 16),
×
UNCOV
310
                        },
×
UNCOV
311
                },
×
UNCOV
312
                Features: lnwire.NewFeatureVector(
×
UNCOV
313
                        nil, lnwire.Features,
×
UNCOV
314
                ),
×
UNCOV
315
                AuthSigBytes: testSig.Serialize(),
×
UNCOV
316
        }
×
UNCOV
317
        dbNode.AddPubKey(nodeKey)
×
UNCOV
318
        if err := d.db.AddLightningNode(dbNode); err != nil {
×
319
                return nil, err
×
320
        }
×
321

UNCOV
322
        return nodeKey, nil
×
323

324
}
325

326
// memChannelGraph is an implementation of the autopilot.ChannelGraph backed by
327
// an in-memory graph.
328
type memChannelGraph struct {
329
        graph map[NodeID]*memNode
330
}
331

332
// A compile time assertion to ensure memChannelGraph meets the
333
// autopilot.ChannelGraph interface.
334
var _ ChannelGraph = (*memChannelGraph)(nil)
335

336
// newMemChannelGraph creates a new blank in-memory channel graph
337
// implementation.
UNCOV
338
func newMemChannelGraph() *memChannelGraph {
×
UNCOV
339
        return &memChannelGraph{
×
UNCOV
340
                graph: make(map[NodeID]*memNode),
×
UNCOV
341
        }
×
UNCOV
342
}
×
343

344
// ForEachNode is a higher-order function that should be called once for each
345
// connected node within the channel graph. If the passed callback returns an
346
// error, then execution should be terminated.
347
//
348
// NOTE: Part of the autopilot.ChannelGraph interface.
UNCOV
349
func (m memChannelGraph) ForEachNode(cb func(Node) error) error {
×
UNCOV
350
        for _, node := range m.graph {
×
UNCOV
351
                if err := cb(node); err != nil {
×
352
                        return err
×
353
                }
×
354
        }
355

UNCOV
356
        return nil
×
357
}
358

359
// randChanID generates a new random channel ID.
UNCOV
360
func randChanID() lnwire.ShortChannelID {
×
UNCOV
361
        id := atomic.AddUint64(&chanIDCounter, 1)
×
UNCOV
362
        return lnwire.NewShortChanIDFromInt(id)
×
UNCOV
363
}
×
364

365
// randKey returns a random public key.
UNCOV
366
func randKey() (*btcec.PublicKey, error) {
×
UNCOV
367
        priv, err := btcec.NewPrivateKey()
×
UNCOV
368
        if err != nil {
×
369
                return nil, err
×
370
        }
×
371

UNCOV
372
        return priv.PubKey(), nil
×
373
}
374

375
// addRandChannel creates a new channel two target nodes. This function is
376
// meant to aide in the generation of random graphs for use within test cases
377
// the exercise the autopilot package.
378
func (m *memChannelGraph) addRandChannel(node1, node2 *btcec.PublicKey,
UNCOV
379
        capacity btcutil.Amount) (*ChannelEdge, *ChannelEdge, error) {
×
UNCOV
380

×
UNCOV
381
        var (
×
UNCOV
382
                vertex1, vertex2 *memNode
×
UNCOV
383
                ok               bool
×
UNCOV
384
        )
×
UNCOV
385

×
UNCOV
386
        if node1 != nil {
×
UNCOV
387
                vertex1, ok = m.graph[NewNodeID(node1)]
×
UNCOV
388
                if !ok {
×
389
                        vertex1 = &memNode{
×
390
                                pub: node1,
×
391
                                addrs: []net.Addr{
×
392
                                        &net.TCPAddr{
×
393
                                                IP: bytes.Repeat([]byte("a"), 16),
×
394
                                        },
×
395
                                },
×
396
                        }
×
397
                }
×
UNCOV
398
        } else {
×
UNCOV
399
                newPub, err := randKey()
×
UNCOV
400
                if err != nil {
×
401
                        return nil, nil, err
×
402
                }
×
UNCOV
403
                vertex1 = &memNode{
×
UNCOV
404
                        pub: newPub,
×
UNCOV
405
                        addrs: []net.Addr{
×
UNCOV
406
                                &net.TCPAddr{
×
UNCOV
407
                                        IP: bytes.Repeat([]byte("a"), 16),
×
UNCOV
408
                                },
×
UNCOV
409
                        },
×
UNCOV
410
                }
×
411
        }
412

UNCOV
413
        if node2 != nil {
×
UNCOV
414
                vertex2, ok = m.graph[NewNodeID(node2)]
×
UNCOV
415
                if !ok {
×
416
                        vertex2 = &memNode{
×
417
                                pub: node2,
×
418
                                addrs: []net.Addr{
×
419
                                        &net.TCPAddr{
×
420
                                                IP: bytes.Repeat([]byte("a"), 16),
×
421
                                        },
×
422
                                },
×
423
                        }
×
424
                }
×
UNCOV
425
        } else {
×
UNCOV
426
                newPub, err := randKey()
×
UNCOV
427
                if err != nil {
×
428
                        return nil, nil, err
×
429
                }
×
UNCOV
430
                vertex2 = &memNode{
×
UNCOV
431
                        pub: newPub,
×
UNCOV
432
                        addrs: []net.Addr{
×
UNCOV
433
                                &net.TCPAddr{
×
UNCOV
434
                                        IP: bytes.Repeat([]byte("a"), 16),
×
UNCOV
435
                                },
×
UNCOV
436
                        },
×
UNCOV
437
                }
×
438
        }
439

UNCOV
440
        edge1 := ChannelEdge{
×
UNCOV
441
                ChanID:   randChanID(),
×
UNCOV
442
                Capacity: capacity,
×
UNCOV
443
                Peer:     vertex2,
×
UNCOV
444
        }
×
UNCOV
445
        vertex1.chans = append(vertex1.chans, edge1)
×
UNCOV
446

×
UNCOV
447
        edge2 := ChannelEdge{
×
UNCOV
448
                ChanID:   randChanID(),
×
UNCOV
449
                Capacity: capacity,
×
UNCOV
450
                Peer:     vertex1,
×
UNCOV
451
        }
×
UNCOV
452
        vertex2.chans = append(vertex2.chans, edge2)
×
UNCOV
453

×
UNCOV
454
        m.graph[NewNodeID(vertex1.pub)] = vertex1
×
UNCOV
455
        m.graph[NewNodeID(vertex2.pub)] = vertex2
×
UNCOV
456

×
UNCOV
457
        return &edge1, &edge2, nil
×
458
}
459

UNCOV
460
func (m *memChannelGraph) addRandNode() (*btcec.PublicKey, error) {
×
UNCOV
461
        newPub, err := randKey()
×
UNCOV
462
        if err != nil {
×
463
                return nil, err
×
464
        }
×
UNCOV
465
        vertex := &memNode{
×
UNCOV
466
                pub: newPub,
×
UNCOV
467
                addrs: []net.Addr{
×
UNCOV
468
                        &net.TCPAddr{
×
UNCOV
469
                                IP: bytes.Repeat([]byte("a"), 16),
×
UNCOV
470
                        },
×
UNCOV
471
                },
×
UNCOV
472
        }
×
UNCOV
473
        m.graph[NewNodeID(newPub)] = vertex
×
UNCOV
474

×
UNCOV
475
        return newPub, nil
×
476
}
477

478
// databaseChannelGraphCached wraps a channeldb.ChannelGraph instance with the
479
// necessary API to properly implement the autopilot.ChannelGraph interface.
480
type databaseChannelGraphCached struct {
481
        db *channeldb.ChannelGraph
482
}
483

484
// A compile time assertion to ensure databaseChannelGraphCached meets the
485
// autopilot.ChannelGraph interface.
486
var _ ChannelGraph = (*databaseChannelGraphCached)(nil)
487

488
// ChannelGraphFromCachedDatabase returns an instance of the
489
// autopilot.ChannelGraph backed by a live, open channeldb instance.
490
func ChannelGraphFromCachedDatabase(db *channeldb.ChannelGraph) ChannelGraph {
×
491
        return &databaseChannelGraphCached{
×
492
                db: db,
×
493
        }
×
494
}
×
495

496
// dbNodeCached is a wrapper struct around a database transaction for a
497
// channeldb.LightningNode. The wrapper methods implement the autopilot.Node
498
// interface.
499
type dbNodeCached struct {
500
        node     route.Vertex
501
        channels map[uint64]*channeldb.DirectedChannel
502
}
503

504
// A compile time assertion to ensure dbNodeCached meets the autopilot.Node
505
// interface.
506
var _ Node = (*dbNodeCached)(nil)
507

508
// PubKey is the identity public key of the node.
509
//
510
// NOTE: Part of the autopilot.Node interface.
511
func (nc dbNodeCached) PubKey() [33]byte {
×
512
        return nc.node
×
513
}
×
514

515
// Addrs returns a slice of publicly reachable public TCP addresses that the
516
// peer is known to be listening on.
517
//
518
// NOTE: Part of the autopilot.Node interface.
519
func (nc dbNodeCached) Addrs() []net.Addr {
×
520
        // TODO: Add addresses to be usable by autopilot.
×
521
        return []net.Addr{}
×
522
}
×
523

524
// ForEachChannel is a higher-order function that will be used to iterate
525
// through all edges emanating from/to the target node. For each active
526
// channel, this function should be called with the populated ChannelEdge that
527
// describes the active channel.
528
//
529
// NOTE: Part of the autopilot.Node interface.
530
func (nc dbNodeCached) ForEachChannel(cb func(ChannelEdge) error) error {
×
531
        for cid, channel := range nc.channels {
×
532
                edge := ChannelEdge{
×
533
                        ChanID:   lnwire.NewShortChanIDFromInt(cid),
×
534
                        Capacity: channel.Capacity,
×
535
                        Peer: dbNodeCached{
×
536
                                node: channel.OtherNode,
×
537
                        },
×
538
                }
×
539

×
540
                if err := cb(edge); err != nil {
×
541
                        return err
×
542
                }
×
543
        }
544

545
        return nil
×
546
}
547

548
// ForEachNode is a higher-order function that should be called once for each
549
// connected node within the channel graph. If the passed callback returns an
550
// error, then execution should be terminated.
551
//
552
// NOTE: Part of the autopilot.ChannelGraph interface.
553
func (dc *databaseChannelGraphCached) ForEachNode(cb func(Node) error) error {
×
554
        return dc.db.ForEachNodeCached(func(n route.Vertex,
×
555
                channels map[uint64]*channeldb.DirectedChannel) error {
×
556

×
557
                if len(channels) > 0 {
×
558
                        node := dbNodeCached{
×
559
                                node:     n,
×
560
                                channels: channels,
×
561
                        }
×
562
                        return cb(node)
×
563
                }
×
564
                return nil
×
565
        })
566
}
567

568
// memNode is a purely in-memory implementation of the autopilot.Node
569
// interface.
570
type memNode struct {
571
        pub *btcec.PublicKey
572

573
        chans []ChannelEdge
574

575
        addrs []net.Addr
576
}
577

578
// A compile time assertion to ensure memNode meets the autopilot.Node
579
// interface.
580
var _ Node = (*memNode)(nil)
581

582
// PubKey is the identity public key of the node. This will be used to attempt
583
// to target a node for channel opening by the main autopilot agent.
584
//
585
// NOTE: Part of the autopilot.Node interface.
UNCOV
586
func (m memNode) PubKey() [33]byte {
×
UNCOV
587
        var n [33]byte
×
UNCOV
588
        copy(n[:], m.pub.SerializeCompressed())
×
UNCOV
589

×
UNCOV
590
        return n
×
UNCOV
591
}
×
592

593
// Addrs returns a slice of publicly reachable public TCP addresses that the
594
// peer is known to be listening on.
595
//
596
// NOTE: Part of the autopilot.Node interface.
UNCOV
597
func (m memNode) Addrs() []net.Addr {
×
UNCOV
598
        return m.addrs
×
UNCOV
599
}
×
600

601
// ForEachChannel is a higher-order function that will be used to iterate
602
// through all edges emanating from/to the target node. For each active
603
// channel, this function should be called with the populated ChannelEdge that
604
// describes the active channel.
605
//
606
// NOTE: Part of the autopilot.Node interface.
UNCOV
607
func (m memNode) ForEachChannel(cb func(ChannelEdge) error) error {
×
UNCOV
608
        for _, channel := range m.chans {
×
UNCOV
609
                if err := cb(channel); err != nil {
×
610
                        return err
×
611
                }
×
612
        }
613

UNCOV
614
        return nil
×
615
}
616

617
// Median returns the median value in the slice of Amounts.
UNCOV
618
func Median(vals []btcutil.Amount) btcutil.Amount {
×
UNCOV
619
        sort.Slice(vals, func(i, j int) bool {
×
UNCOV
620
                return vals[i] < vals[j]
×
UNCOV
621
        })
×
622

UNCOV
623
        num := len(vals)
×
UNCOV
624
        switch {
×
UNCOV
625
        case num == 0:
×
UNCOV
626
                return 0
×
627

UNCOV
628
        case num%2 == 0:
×
UNCOV
629
                return (vals[num/2-1] + vals[num/2]) / 2
×
630

UNCOV
631
        default:
×
UNCOV
632
                return vals[num/2]
×
633
        }
634
}
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