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

lightningnetwork / lnd / 12190156236

05 Dec 2024 11:33PM UTC coverage: 49.833% (-9.1%) from 58.933%
12190156236

Pull #9242

github

aakselrod
docs: update release-notes for 0.19.0
Pull Request #9242: Reapply #8644

6 of 27 new or added lines in 2 files covered. (22.22%)

25353 existing lines in 422 files now uncovered.

100197 of 201066 relevant lines covered (49.83%)

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
        "errors"
7
        "net"
8
        "sort"
9
        "sync/atomic"
10
        "time"
11

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

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

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

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

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

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

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

60
        tx kvdb.RTx
61

62
        node *models.LightningNode
63
}
64

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

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

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

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

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

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

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

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

132
// ForEachNode is a higher-order function that should be called once for each
133
// connected node within the channel graph. If the passed callback returns an
134
// error, then execution should be terminated.
135
//
136
// NOTE: Part of the autopilot.ChannelGraph interface.
UNCOV
137
func (d *databaseChannelGraph) ForEachNode(cb func(Node) error) error {
×
UNCOV
138
        return d.db.ForEachNode(func(tx kvdb.RTx,
×
UNCOV
139
                n *models.LightningNode) error {
×
UNCOV
140

×
UNCOV
141
                // We'll skip over any node that doesn't have any advertised
×
UNCOV
142
                // addresses. As we won't be able to reach them to actually
×
UNCOV
143
                // open any channels.
×
UNCOV
144
                if len(n.Addresses) == 0 {
×
145
                        return nil
×
146
                }
×
147

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

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

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

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

UNCOV
197
                        return dbNode, nil
×
198
                }
199

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

UNCOV
221
                return dbNode, nil
×
222
        }
223

UNCOV
224
        vertex1, err := fetchNode(node1)
×
UNCOV
225
        if err != nil {
×
226
                return nil, nil, err
×
227
        }
×
228

UNCOV
229
        vertex2, err := fetchNode(node2)
×
UNCOV
230
        if err != nil {
×
231
                return nil, nil, err
×
232
        }
×
233

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

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

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

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

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

UNCOV
325
        return nodeKey, nil
×
326

327
}
328

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

335
// A compile time assertion to ensure memChannelGraph meets the
336
// autopilot.ChannelGraph interface.
337
var _ ChannelGraph = (*memChannelGraph)(nil)
338

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

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

UNCOV
359
        return nil
×
360
}
361

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

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

UNCOV
375
        return priv.PubKey(), nil
×
376
}
377

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

×
UNCOV
384
        var (
×
UNCOV
385
                vertex1, vertex2 *memNode
×
UNCOV
386
                ok               bool
×
UNCOV
387
        )
×
UNCOV
388

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

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

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

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

×
UNCOV
457
        m.graph[NewNodeID(vertex1.pub)] = vertex1
×
UNCOV
458
        m.graph[NewNodeID(vertex2.pub)] = vertex2
×
UNCOV
459

×
UNCOV
460
        return &edge1, &edge2, nil
×
461
}
462

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

×
UNCOV
478
        return newPub, nil
×
479
}
480

481
// databaseChannelGraphCached wraps a channeldb.ChannelGraph instance with the
482
// necessary API to properly implement the autopilot.ChannelGraph interface.
483
type databaseChannelGraphCached struct {
484
        db *graphdb.ChannelGraph
485
}
486

487
// A compile time assertion to ensure databaseChannelGraphCached meets the
488
// autopilot.ChannelGraph interface.
489
var _ ChannelGraph = (*databaseChannelGraphCached)(nil)
490

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

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

507
// A compile time assertion to ensure dbNodeCached meets the autopilot.Node
508
// interface.
509
var _ Node = (*dbNodeCached)(nil)
510

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

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

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

×
543
                if err := cb(edge); err != nil {
×
544
                        return err
×
545
                }
×
546
        }
547

548
        return nil
×
549
}
550

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

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

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

576
        chans []ChannelEdge
577

578
        addrs []net.Addr
579
}
580

581
// A compile time assertion to ensure memNode meets the autopilot.Node
582
// interface.
583
var _ Node = (*memNode)(nil)
584

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

×
UNCOV
593
        return n
×
UNCOV
594
}
×
595

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

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

UNCOV
617
        return nil
×
618
}
619

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

UNCOV
626
        num := len(vals)
×
UNCOV
627
        switch {
×
UNCOV
628
        case num == 0:
×
UNCOV
629
                return 0
×
630

UNCOV
631
        case num%2 == 0:
×
UNCOV
632
                return (vals[num/2-1] + vals[num/2]) / 2
×
633

UNCOV
634
        default:
×
UNCOV
635
                return vals[num/2]
×
636
        }
637
}
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