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

lightningnetwork / lnd / 17011395530

16 Aug 2025 06:08PM UTC coverage: 57.298% (-9.5%) from 66.765%
17011395530

Pull #10167

github

web-flow
Merge 3c250722d into fb1adfc21
Pull Request #10167: multi: bump Go to 1.24.6

99112 of 172975 relevant lines covered (57.3%)

1.78 hits per line

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

19.2
/autopilot/graph.go
1
package autopilot
2

3
import (
4
        "context"
5
        "encoding/hex"
6
        "net"
7
        "sort"
8

9
        "github.com/btcsuite/btcd/btcec/v2"
10
        "github.com/btcsuite/btcd/btcec/v2/ecdsa"
11
        "github.com/btcsuite/btcd/btcutil"
12
        graphdb "github.com/lightningnetwork/lnd/graph/db"
13
        "github.com/lightningnetwork/lnd/graph/db/models"
14
        "github.com/lightningnetwork/lnd/lnwire"
15
        "github.com/lightningnetwork/lnd/routing/route"
16
)
17

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

27
        chanIDCounter uint64 // To be used atomically.
28
)
29

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

38
// A compile time assertion to ensure databaseChannelGraph meets the
39
// autopilot.ChannelGraph interface.
40
var _ ChannelGraph = (*databaseChannelGraph)(nil)
41

42
// ChannelGraphFromDatabase returns an instance of the autopilot.ChannelGraph
43
// backed by a GraphSource.
44
func ChannelGraphFromDatabase(db GraphSource) ChannelGraph {
3✔
45
        return &databaseChannelGraph{
3✔
46
                db: db,
3✔
47
        }
3✔
48
}
3✔
49

50
// type dbNode is a wrapper struct around a database transaction an
51
// channeldb.LightningNode. The wrapper method implement the autopilot.Node
52
// interface.
53
type dbNode struct {
54
        pub   [33]byte
55
        addrs []net.Addr
56
}
57

58
// A compile time assertion to ensure dbNode meets the autopilot.Node
59
// interface.
60
var _ Node = (*dbNode)(nil)
61

62
// PubKey is the identity public key of the node. This will be used to attempt
63
// to target a node for channel opening by the main autopilot agent. The key
64
// will be returned in serialized compressed format.
65
//
66
// NOTE: Part of the autopilot.Node interface.
67
func (d *dbNode) PubKey() [33]byte {
3✔
68
        return d.pub
3✔
69
}
3✔
70

71
// Addrs returns a slice of publicly reachable public TCP addresses that the
72
// peer is known to be listening on.
73
//
74
// NOTE: Part of the autopilot.Node interface.
75
func (d *dbNode) Addrs() []net.Addr {
3✔
76
        return d.addrs
3✔
77
}
3✔
78

79
// ForEachNode is a higher-order function that should be called once for each
80
// connected node within the channel graph. If the passed callback returns an
81
// error, then execution should be terminated.
82
//
83
// NOTE: Part of the autopilot.ChannelGraph interface.
84
func (d *databaseChannelGraph) ForEachNode(ctx context.Context,
85
        cb func(context.Context, Node) error, reset func()) error {
3✔
86

3✔
87
        return d.db.ForEachNode(ctx, func(n *models.LightningNode) error {
6✔
88
                // We'll skip over any node that doesn't have any advertised
3✔
89
                // addresses. As we won't be able to reach them to actually
3✔
90
                // open any channels.
3✔
91
                if len(n.Addresses) == 0 {
3✔
92
                        return nil
×
93
                }
×
94

95
                node := &dbNode{
3✔
96
                        pub:   n.PubKeyBytes,
3✔
97
                        addrs: n.Addresses,
3✔
98
                }
3✔
99

3✔
100
                return cb(ctx, node)
3✔
101
        }, reset)
102
}
103

104
// ForEachNodesChannels iterates through all connected nodes, and for each node,
105
// all the channels that connect to it. The passed callback will be called with
106
// the context, the Node itself, and a slice of ChannelEdge that connect to the
107
// node.
108
//
109
// NOTE: Part of the autopilot.ChannelGraph interface.
110
func (d *databaseChannelGraph) ForEachNodesChannels(ctx context.Context,
111
        cb func(context.Context, Node, []*ChannelEdge) error,
112
        reset func()) error {
×
113

×
114
        return d.db.ForEachNodeCached(
×
115
                ctx, true, func(ctx context.Context, node route.Vertex,
×
116
                        addrs []net.Addr,
×
117
                        chans map[uint64]*graphdb.DirectedChannel) error {
×
118

×
119
                        // We'll skip over any node that doesn't have any
×
120
                        // advertised addresses. As we won't be able to reach
×
121
                        // them to actually open any channels.
×
122
                        if len(addrs) == 0 {
×
123
                                return nil
×
124
                        }
×
125

126
                        edges := make([]*ChannelEdge, 0, len(chans))
×
127
                        for _, channel := range chans {
×
128
                                edges = append(edges, &ChannelEdge{
×
129
                                        ChanID: lnwire.NewShortChanIDFromInt(
×
130
                                                channel.ChannelID,
×
131
                                        ),
×
132
                                        Capacity: channel.Capacity,
×
133
                                        Peer:     channel.OtherNode,
×
134
                                })
×
135
                        }
×
136

137
                        return cb(ctx, &dbNode{
×
138
                                pub:   node,
×
139
                                addrs: addrs,
×
140
                        }, edges)
×
141
                }, reset,
142
        )
143
}
144

145
// databaseChannelGraphCached wraps a channeldb.ChannelGraph instance with the
146
// necessary API to properly implement the autopilot.ChannelGraph interface.
147
type databaseChannelGraphCached struct {
148
        db GraphSource
149
}
150

151
// A compile time assertion to ensure databaseChannelGraphCached meets the
152
// autopilot.ChannelGraph interface.
153
var _ ChannelGraph = (*databaseChannelGraphCached)(nil)
154

155
// ChannelGraphFromCachedDatabase returns an instance of the
156
// autopilot.ChannelGraph backed by a live, open channeldb instance.
157
func ChannelGraphFromCachedDatabase(db GraphSource) ChannelGraph {
×
158
        return &databaseChannelGraphCached{
×
159
                db: db,
×
160
        }
×
161
}
×
162

163
// dbNodeCached is a wrapper struct around a database transaction for a
164
// channeldb.LightningNode. The wrapper methods implement the autopilot.Node
165
// interface.
166
type dbNodeCached struct {
167
        node     route.Vertex
168
        channels map[uint64]*graphdb.DirectedChannel
169
}
170

171
// A compile time assertion to ensure dbNodeCached meets the autopilot.Node
172
// interface.
173
var _ Node = (*dbNodeCached)(nil)
174

175
// PubKey is the identity public key of the node.
176
//
177
// NOTE: Part of the autopilot.Node interface.
178
func (nc dbNodeCached) PubKey() [33]byte {
×
179
        return nc.node
×
180
}
×
181

182
// Addrs returns a slice of publicly reachable public TCP addresses that the
183
// peer is known to be listening on.
184
//
185
// NOTE: Part of the autopilot.Node interface.
186
func (nc dbNodeCached) Addrs() []net.Addr {
×
187
        // TODO: Add addresses to be usable by autopilot.
×
188
        return []net.Addr{}
×
189
}
×
190

191
// ForEachNode is a higher-order function that should be called once for each
192
// connected node within the channel graph. If the passed callback returns an
193
// error, then execution should be terminated.
194
//
195
// NOTE: Part of the autopilot.ChannelGraph interface.
196
func (dc *databaseChannelGraphCached) ForEachNode(ctx context.Context,
197
        cb func(context.Context, Node) error, reset func()) error {
×
198

×
199
        return dc.db.ForEachNodeCached(ctx, false, func(ctx context.Context,
×
200
                n route.Vertex, _ []net.Addr,
×
201
                channels map[uint64]*graphdb.DirectedChannel) error {
×
202

×
203
                if len(channels) > 0 {
×
204
                        node := dbNodeCached{
×
205
                                node:     n,
×
206
                                channels: channels,
×
207
                        }
×
208

×
209
                        return cb(ctx, node)
×
210
                }
×
211

212
                return nil
×
213
        }, reset)
214
}
215

216
// ForEachNodesChannels iterates through all connected nodes, and for each node,
217
// all the channels that connect to it. The passed callback will be called with
218
// the context, the Node itself, and a slice of ChannelEdge that connect to the
219
// node.
220
//
221
// NOTE: Part of the autopilot.ChannelGraph interface.
222
func (dc *databaseChannelGraphCached) ForEachNodesChannels(ctx context.Context,
223
        cb func(context.Context, Node, []*ChannelEdge) error,
224
        reset func()) error {
×
225

×
226
        return dc.db.ForEachNodeCached(ctx, false, func(ctx context.Context,
×
227
                n route.Vertex, _ []net.Addr,
×
228
                channels map[uint64]*graphdb.DirectedChannel) error {
×
229

×
230
                edges := make([]*ChannelEdge, 0, len(channels))
×
231
                for cid, channel := range channels {
×
232
                        edges = append(edges, &ChannelEdge{
×
233
                                ChanID:   lnwire.NewShortChanIDFromInt(cid),
×
234
                                Capacity: channel.Capacity,
×
235
                                Peer:     channel.OtherNode,
×
236
                        })
×
237
                }
×
238

239
                if len(channels) > 0 {
×
240
                        node := dbNodeCached{
×
241
                                node:     n,
×
242
                                channels: channels,
×
243
                        }
×
244

×
245
                        if err := cb(ctx, node, edges); err != nil {
×
246
                                return err
×
247
                        }
×
248
                }
249

250
                return nil
×
251
        }, reset)
252
}
253

254
// memNode is a purely in-memory implementation of the autopilot.Node
255
// interface.
256
type memNode struct {
257
        pub *btcec.PublicKey
258

259
        chans []ChannelEdge
260

261
        addrs []net.Addr
262
}
263

264
// A compile time assertion to ensure memNode meets the autopilot.Node
265
// interface.
266
var _ Node = (*memNode)(nil)
267

268
// PubKey is the identity public key of the node. This will be used to attempt
269
// to target a node for channel opening by the main autopilot agent.
270
//
271
// NOTE: Part of the autopilot.Node interface.
272
func (m memNode) PubKey() [33]byte {
×
273
        var n [33]byte
×
274
        copy(n[:], m.pub.SerializeCompressed())
×
275

×
276
        return n
×
277
}
×
278

279
// Addrs returns a slice of publicly reachable public TCP addresses that the
280
// peer is known to be listening on.
281
//
282
// NOTE: Part of the autopilot.Node interface.
283
func (m memNode) Addrs() []net.Addr {
×
284
        return m.addrs
×
285
}
×
286

287
// Median returns the median value in the slice of Amounts.
288
func Median(vals []btcutil.Amount) btcutil.Amount {
×
289
        sort.Slice(vals, func(i, j int) bool {
×
290
                return vals[i] < vals[j]
×
291
        })
×
292

293
        num := len(vals)
×
294
        switch {
×
295
        case num == 0:
×
296
                return 0
×
297

298
        case num%2 == 0:
×
299
                return (vals[num/2-1] + vals[num/2]) / 2
×
300

301
        default:
×
302
                return vals[num/2]
×
303
        }
304
}
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