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

lightningnetwork / lnd / 16777740336

06 Aug 2025 01:04PM UTC coverage: 54.85% (-12.1%) from 66.954%
16777740336

Pull #10135

github

web-flow
Merge 429aa830c into e512770f1
Pull Request #10135: docs: move v0.19.3 items to correct file

108702 of 198181 relevant lines covered (54.85%)

22045.97 hits per line

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

49.6
/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 {
×
45
        return &databaseChannelGraph{
×
46
                db: db,
×
47
        }
×
48
}
×
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
        tx graphdb.NodeRTx
55
}
56

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

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

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

×
78
// ForEachChannel is a higher-order function that will be used to iterate
79
// through all edges emanating from/to the target node. For each active
80
// channel, this function should be called with the populated ChannelEdge that
81
// describes the active channel.
82
//
83
// NOTE: Part of the autopilot.Node interface.
84
func (d *dbNode) ForEachChannel(ctx context.Context,
85
        cb func(context.Context, ChannelEdge) error) error {
2✔
86

2✔
87
        return d.tx.ForEachChannel(func(ei *models.ChannelEdgeInfo, ep,
7✔
88
                _ *models.ChannelEdgePolicy) error {
5✔
89

5✔
90
                // Skip channels for which no outgoing edge policy is available.
5✔
91
                //
5✔
92
                // TODO(joostjager): Ideally the case where channels have a nil
×
93
                // policy should be supported, as autopilot is not looking at
×
94
                // the policies. For now, it is not easily possible to get a
95
                // reference to the other end LightningNode object without
5✔
96
                // retrieving the policy.
5✔
97
                if ep == nil {
5✔
98
                        return nil
5✔
99
                }
5✔
100

5✔
101
                node, err := d.tx.FetchNode(ep.ToNode)
102
                if err != nil {
103
                        return err
104
                }
105

106
                edge := ChannelEdge{
107
                        ChanID:   lnwire.NewShortChanIDFromInt(ep.ChannelID),
108
                        Capacity: ei.Capacity,
109
                        Peer: &dbNode{
110
                                tx: node,
111
                        },
112
                }
118✔
113

118✔
114
                return cb(ctx, edge)
118✔
115
        })
118✔
116
}
118✔
117

1,083✔
118
// ForEachNode is a higher-order function that should be called once for each
965✔
119
// connected node within the channel graph. If the passed callback returns an
965✔
120
// error, then execution should be terminated.
965✔
121
//
965✔
122
// NOTE: Part of the autopilot.ChannelGraph interface.
965✔
123
func (d *databaseChannelGraph) ForEachNode(ctx context.Context,
×
124
        cb func(context.Context, Node) error, reset func()) error {
×
125

126
        return d.db.ForEachNode(ctx, func(nodeTx graphdb.NodeRTx) error {
965✔
127
                // We'll skip over any node that doesn't have any advertised
3,909✔
128
                // addresses. As we won't be able to reach them to actually
2,944✔
129
                // open any channels.
2,944✔
130
                if len(nodeTx.Node().Addresses) == 0 {
2,944✔
131
                        return nil
2,944✔
132
                }
2,944✔
133

2,944✔
134
                node := &dbNode{
2,944✔
135
                        tx: nodeTx,
2,944✔
136
                }
137

965✔
138
                return cb(ctx, node)
965✔
139
        }, reset)
965✔
140
}
965✔
141

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

148
// A compile time assertion to ensure databaseChannelGraphCached meets the
149
// autopilot.ChannelGraph interface.
150
var _ ChannelGraph = (*databaseChannelGraphCached)(nil)
151

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

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

168
// A compile time assertion to ensure dbNodeCached meets the autopilot.Node
169
// interface.
170
var _ Node = (*dbNodeCached)(nil)
171

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

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

×
188
// ForEachChannel is a higher-order function that will be used to iterate
×
189
// through all edges emanating from/to the target node. For each active
×
190
// channel, this function should be called with the populated ChannelEdge that
191
// describes the active channel.
192
//
193
// NOTE: Part of the autopilot.Node interface.
194
func (nc dbNodeCached) ForEachChannel(ctx context.Context,
195
        cb func(context.Context, ChannelEdge) error) error {
196

197
        for cid, channel := range nc.channels {
×
198
                edge := ChannelEdge{
×
199
                        ChanID:   lnwire.NewShortChanIDFromInt(cid),
×
200
                        Capacity: channel.Capacity,
×
201
                        Peer: dbNodeCached{
×
202
                                node: channel.OtherNode,
×
203
                        },
×
204
                }
×
205

×
206
                if err := cb(ctx, edge); err != nil {
×
207
                        return err
×
208
                }
×
209
        }
×
210

×
211
        return nil
212
}
×
213

214
// ForEachNode is a higher-order function that should be called once for each
215
// connected node within the channel graph. If the passed callback returns an
216
// error, then execution should be terminated.
217
//
218
// NOTE: Part of the autopilot.ChannelGraph interface.
219
func (dc *databaseChannelGraphCached) ForEachNode(ctx context.Context,
220
        cb func(context.Context, Node) error, reset func()) error {
221

222
        return dc.db.ForEachNodeCached(ctx, func(n route.Vertex,
223
                channels map[uint64]*graphdb.DirectedChannel) error {
224

×
225
                if len(channels) > 0 {
×
226
                        node := dbNodeCached{
×
227
                                node:     n,
×
228
                                channels: channels,
×
229
                        }
×
230

×
231
                        return cb(ctx, node)
×
232
                }
×
233
                return nil
×
234
        }, reset)
×
235
}
×
236

×
237
// memNode is a purely in-memory implementation of the autopilot.Node
×
238
// interface.
239
type memNode struct {
×
240
        pub *btcec.PublicKey
×
241

×
242
        chans []ChannelEdge
×
243

×
244
        addrs []net.Addr
×
245
}
×
246

×
247
// A compile time assertion to ensure memNode meets the autopilot.Node
×
248
// interface.
249
var _ Node = (*memNode)(nil)
250

×
251
// PubKey is the identity public key of the node. This will be used to attempt
252
// to target a node for channel opening by the main autopilot agent.
253
//
254
// NOTE: Part of the autopilot.Node interface.
255
func (m memNode) PubKey() [33]byte {
256
        var n [33]byte
257
        copy(n[:], m.pub.SerializeCompressed())
258

259
        return n
260
}
261

262
// Addrs returns a slice of publicly reachable public TCP addresses that the
263
// peer is known to be listening on.
264
//
265
// NOTE: Part of the autopilot.Node interface.
266
func (m memNode) Addrs() []net.Addr {
267
        return m.addrs
268
}
269

270
// ForEachChannel is a higher-order function that will be used to iterate
271
// through all edges emanating from/to the target node. For each active
272
// channel, this function should be called with the populated ChannelEdge that
1,187✔
273
// describes the active channel.
1,187✔
274
//
1,187✔
275
// NOTE: Part of the autopilot.Node interface.
1,187✔
276
func (m memNode) ForEachChannel(ctx context.Context,
1,187✔
277
        cb func(context.Context, ChannelEdge) error) error {
1,187✔
278

279
        for _, channel := range m.chans {
280
                if err := cb(ctx, channel); err != nil {
281
                        return err
282
                }
283
        }
82✔
284

82✔
285
        return nil
82✔
286
}
287

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

18✔
294
        num := len(vals)
18✔
295
        switch {
3✔
296
        case num == 0:
3✔
297
                return 0
298

8✔
299
        case num%2 == 0:
8✔
300
                return (vals[num/2-1] + vals[num/2]) / 2
301

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