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

lightningnetwork / lnd / 16683051882

01 Aug 2025 07:03PM UTC coverage: 54.949% (-12.1%) from 67.047%
16683051882

Pull #9455

github

web-flow
Merge 3f1f50be8 into 37523b6cb
Pull Request #9455: discovery+lnwire: add support for DNS host name in NodeAnnouncement msg

144 of 226 new or added lines in 7 files covered. (63.72%)

23852 existing lines in 290 files now uncovered.

108751 of 197912 relevant lines covered (54.95%)

22080.83 hits per line

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

53.28
/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.
UNCOV
44
func ChannelGraphFromDatabase(db GraphSource) ChannelGraph {
×
UNCOV
45
        return &databaseChannelGraph{
×
UNCOV
46
                db: db,
×
UNCOV
47
        }
×
UNCOV
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 {
3,874✔
67
        return d.tx.Node().PubKeyBytes
3,874✔
68
}
3,874✔
69

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.
UNCOV
74
func (d *dbNode) Addrs() []net.Addr {
×
UNCOV
75
        return d.tx.Node().Addresses
×
UNCOV
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 {
965✔
86

965✔
87
        return d.tx.ForEachChannel(func(ei *models.ChannelEdgeInfo, ep,
965✔
88
                _ *models.ChannelEdgePolicy) error {
3,909✔
89

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

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

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

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

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

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

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

970✔
138
                return cb(ctx, node)
970✔
139
        }, reset)
140
}
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 {
3,956✔
256
        var n [33]byte
3,956✔
257
        copy(n[:], m.pub.SerializeCompressed())
3,956✔
258

3,956✔
259
        return n
3,956✔
260
}
3,956✔
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 {
82✔
267
        return m.addrs
82✔
268
}
82✔
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
273
// describes the active channel.
274
//
275
// NOTE: Part of the autopilot.Node interface.
276
func (m memNode) ForEachChannel(ctx context.Context,
277
        cb func(context.Context, ChannelEdge) error) error {
965✔
278

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

285
        return nil
965✔
286
}
287

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

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

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

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