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

lightningnetwork / lnd / 15561477203

10 Jun 2025 01:54PM UTC coverage: 58.351% (-10.1%) from 68.487%
15561477203

Pull #9356

github

web-flow
Merge 6440b25db into c6d6d4c0b
Pull Request #9356: lnrpc: add incoming/outgoing channel ids filter to forwarding history request

33 of 36 new or added lines in 2 files covered. (91.67%)

28366 existing lines in 455 files now uncovered.

97715 of 167461 relevant lines covered (58.35%)

1.81 hits per line

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

4.1
/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
        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.
UNCOV
66
func (d *dbNode) PubKey() [33]byte {
×
UNCOV
67
        return d.tx.Node().PubKeyBytes
×
UNCOV
68
}
×
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.
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,
UNCOV
85
        cb func(context.Context, ChannelEdge) error) error {
×
UNCOV
86

×
UNCOV
87
        return d.tx.ForEachChannel(func(ei *models.ChannelEdgeInfo, ep,
×
UNCOV
88
                _ *models.ChannelEdgePolicy) error {
×
UNCOV
89

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

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

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

×
UNCOV
114
                return cb(ctx, edge)
×
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,
UNCOV
124
        cb func(context.Context, Node) error) error {
×
UNCOV
125

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

UNCOV
134
                node := &dbNode{
×
UNCOV
135
                        tx: nodeTx,
×
UNCOV
136
                }
×
UNCOV
137

×
UNCOV
138
                return cb(ctx, node)
×
139
        })
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) error {
×
221

×
222
        return dc.db.ForEachNodeCached(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
        })
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.
UNCOV
255
func (m memNode) PubKey() [33]byte {
×
UNCOV
256
        var n [33]byte
×
UNCOV
257
        copy(n[:], m.pub.SerializeCompressed())
×
UNCOV
258

×
UNCOV
259
        return n
×
UNCOV
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.
UNCOV
266
func (m memNode) Addrs() []net.Addr {
×
UNCOV
267
        return m.addrs
×
UNCOV
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
273
// describes the active channel.
274
//
275
// NOTE: Part of the autopilot.Node interface.
276
func (m memNode) ForEachChannel(ctx context.Context,
UNCOV
277
        cb func(context.Context, ChannelEdge) error) error {
×
UNCOV
278

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

UNCOV
285
        return nil
×
286
}
287

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

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

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

UNCOV
302
        default:
×
UNCOV
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