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

lightningnetwork / lnd / 13236757158

10 Feb 2025 08:39AM UTC coverage: 57.649% (-1.2%) from 58.815%
13236757158

Pull #9493

github

ziggie1984
lncli: for some cmds we don't replace the data of the response.

For some cmds it is not very practical to replace the json output
because we might pipe it into other commands. For example when
creating the route we want to pipe it into sendtoRoute.
Pull Request #9493: For some lncli cmds we should not replace the content with other data

0 of 9 new or added lines in 2 files covered. (0.0%)

19535 existing lines in 252 files now uncovered.

103517 of 179563 relevant lines covered (57.65%)

24878.49 hits per line

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

0.0
/pilot.go
1
package lnd
2

3
import (
4
        "errors"
5
        "fmt"
6
        "net"
7

8
        "github.com/btcsuite/btcd/btcec/v2"
9
        "github.com/btcsuite/btcd/btcutil"
10
        "github.com/btcsuite/btcd/wire"
11
        "github.com/lightningnetwork/lnd/autopilot"
12
        "github.com/lightningnetwork/lnd/chainreg"
13
        "github.com/lightningnetwork/lnd/funding"
14
        "github.com/lightningnetwork/lnd/lncfg"
15
        "github.com/lightningnetwork/lnd/lnwallet"
16
        "github.com/lightningnetwork/lnd/lnwire"
17
        "github.com/lightningnetwork/lnd/tor"
18
)
19

20
// validateAtplCfg is a helper method that makes sure the passed
21
// configuration is sane. Currently it checks that the heuristic configuration
22
// makes sense. In case the config is valid, it will return a list of
23
// WeightedHeuristics that can be combined for use with the autopilot agent.
24
func validateAtplCfg(cfg *lncfg.AutoPilot) ([]*autopilot.WeightedHeuristic,
UNCOV
25
        error) {
×
UNCOV
26

×
UNCOV
27
        var (
×
UNCOV
28
                heuristicsStr string
×
UNCOV
29
                sum           float64
×
UNCOV
30
                heuristics    []*autopilot.WeightedHeuristic
×
UNCOV
31
        )
×
UNCOV
32

×
UNCOV
33
        // Create a help text that we can return in case the config is not
×
UNCOV
34
        // correct.
×
UNCOV
35
        for _, a := range autopilot.AvailableHeuristics {
×
UNCOV
36
                heuristicsStr += fmt.Sprintf(" '%v' ", a.Name())
×
UNCOV
37
        }
×
UNCOV
38
        availStr := fmt.Sprintf("Available heuristics are: [%v]", heuristicsStr)
×
UNCOV
39

×
UNCOV
40
        // We'll go through the config and make sure all the heuristics exists,
×
UNCOV
41
        // and that the sum of their weights is 1.0.
×
UNCOV
42
        for name, weight := range cfg.Heuristic {
×
UNCOV
43
                a, ok := autopilot.AvailableHeuristics[name]
×
UNCOV
44
                if !ok {
×
45
                        // No heuristic matching this config option was found.
×
46
                        return nil, fmt.Errorf("heuristic %v not available. %v",
×
47
                                name, availStr)
×
48
                }
×
49

50
                // If this heuristic was among the registered ones, we add it
51
                // to the list we'll give to the agent, and keep track of the
52
                // sum of weights.
UNCOV
53
                heuristics = append(
×
UNCOV
54
                        heuristics,
×
UNCOV
55
                        &autopilot.WeightedHeuristic{
×
UNCOV
56
                                Weight:              weight,
×
UNCOV
57
                                AttachmentHeuristic: a,
×
UNCOV
58
                        },
×
UNCOV
59
                )
×
UNCOV
60
                sum += weight
×
61
        }
62

63
        // Check found heuristics. We must have at least one to operate.
UNCOV
64
        if len(heuristics) == 0 {
×
65
                return nil, fmt.Errorf("no active heuristics: %v", availStr)
×
66
        }
×
67

UNCOV
68
        if sum != 1.0 {
×
69
                return nil, fmt.Errorf("heuristic weights must sum to 1.0")
×
70
        }
×
UNCOV
71
        return heuristics, nil
×
72
}
73

74
// chanController is an implementation of the autopilot.ChannelController
75
// interface that's backed by a running lnd instance.
76
type chanController struct {
77
        server        *server
78
        private       bool
79
        minConfs      int32
80
        confTarget    uint32
81
        chanMinHtlcIn lnwire.MilliSatoshi
82
        netParams     chainreg.BitcoinNetParams
83
}
84

85
// OpenChannel opens a channel to a target peer, with a capacity of the
86
// specified amount. This function should un-block immediately after the
87
// funding transaction that marks the channel open has been broadcast.
88
func (c *chanController) OpenChannel(target *btcec.PublicKey,
89
        amt btcutil.Amount) error {
×
90

×
91
        // With the connection established, we'll now establish our connection
×
92
        // to the target peer, waiting for the first update before we exit.
×
93
        feePerKw, err := c.server.cc.FeeEstimator.EstimateFeePerKW(
×
94
                c.confTarget,
×
95
        )
×
96
        if err != nil {
×
97
                return err
×
98
        }
×
99

100
        // Construct the open channel request and send it to the server to begin
101
        // the funding workflow.
102
        req := &funding.InitFundingMsg{
×
103
                TargetPubkey:     target,
×
104
                ChainHash:        *c.netParams.GenesisHash,
×
105
                SubtractFees:     true,
×
106
                LocalFundingAmt:  amt,
×
107
                PushAmt:          0,
×
108
                MinHtlcIn:        c.chanMinHtlcIn,
×
109
                FundingFeePerKw:  feePerKw,
×
110
                Private:          c.private,
×
111
                RemoteCsvDelay:   0,
×
112
                MinConfs:         c.minConfs,
×
113
                MaxValueInFlight: 0,
×
114
        }
×
115

×
116
        updateStream, errChan := c.server.OpenChannel(req)
×
117
        select {
×
118
        case err := <-errChan:
×
119
                return err
×
120
        case <-updateStream:
×
121
                return nil
×
122
        case <-c.server.quit:
×
123
                return nil
×
124
        }
125
}
126

127
func (c *chanController) CloseChannel(chanPoint *wire.OutPoint) error {
×
128
        return nil
×
129
}
×
130

131
// A compile time assertion to ensure chanController meets the
132
// autopilot.ChannelController interface.
133
var _ autopilot.ChannelController = (*chanController)(nil)
134

135
// initAutoPilot initializes a new autopilot.ManagerCfg to manage an autopilot.
136
// Agent instance based on the passed configuration structs. The agent and all
137
// interfaces needed to drive it won't be launched before the Manager's
138
// StartAgent method is called.
139
func initAutoPilot(svr *server, cfg *lncfg.AutoPilot,
140
        minHTLCIn lnwire.MilliSatoshi, netParams chainreg.BitcoinNetParams) (
UNCOV
141
        *autopilot.ManagerCfg, error) {
×
UNCOV
142

×
UNCOV
143
        atplLog.Infof("Instantiating autopilot with active=%v, "+
×
UNCOV
144
                "max_channels=%d, allocation=%f, min_chan_size=%d, "+
×
UNCOV
145
                "max_chan_size=%d, private=%t, min_confs=%d, conf_target=%d",
×
UNCOV
146
                cfg.Active, cfg.MaxChannels, cfg.Allocation, cfg.MinChannelSize,
×
UNCOV
147
                cfg.MaxChannelSize, cfg.Private, cfg.MinConfs, cfg.ConfTarget)
×
UNCOV
148

×
UNCOV
149
        // Set up the constraints the autopilot heuristics must adhere to.
×
UNCOV
150
        atplConstraints := autopilot.NewConstraints(
×
UNCOV
151
                btcutil.Amount(cfg.MinChannelSize),
×
UNCOV
152
                btcutil.Amount(cfg.MaxChannelSize),
×
UNCOV
153
                uint16(cfg.MaxChannels),
×
UNCOV
154
                10,
×
UNCOV
155
                cfg.Allocation,
×
UNCOV
156
        )
×
UNCOV
157
        heuristics, err := validateAtplCfg(cfg)
×
UNCOV
158
        if err != nil {
×
159
                return nil, err
×
160
        }
×
161

UNCOV
162
        weightedAttachment, err := autopilot.NewWeightedCombAttachment(
×
UNCOV
163
                heuristics...,
×
UNCOV
164
        )
×
UNCOV
165
        if err != nil {
×
166
                return nil, err
×
167
        }
×
168

169
        // With the heuristic itself created, we can now populate the remainder
170
        // of the items that the autopilot agent needs to perform its duties.
UNCOV
171
        self := svr.identityECDH.PubKey()
×
UNCOV
172
        pilotCfg := autopilot.Config{
×
UNCOV
173
                Self:      self,
×
UNCOV
174
                Heuristic: weightedAttachment,
×
UNCOV
175
                ChanController: &chanController{
×
UNCOV
176
                        server:        svr,
×
UNCOV
177
                        private:       cfg.Private,
×
UNCOV
178
                        minConfs:      cfg.MinConfs,
×
UNCOV
179
                        confTarget:    cfg.ConfTarget,
×
UNCOV
180
                        chanMinHtlcIn: minHTLCIn,
×
UNCOV
181
                        netParams:     netParams,
×
UNCOV
182
                },
×
UNCOV
183
                WalletBalance: func() (btcutil.Amount, error) {
×
184
                        return svr.cc.Wallet.ConfirmedBalance(
×
185
                                cfg.MinConfs, lnwallet.DefaultAccountName,
×
186
                        )
×
187
                },
×
188
                Graph:       autopilot.ChannelGraphFromDatabase(svr.graphDB),
189
                Constraints: atplConstraints,
190
                ConnectToPeer: func(target *btcec.PublicKey, addrs []net.Addr) (bool, error) {
×
191
                        // First, we'll check if we're already connected to the
×
192
                        // target peer. If we are, we can exit early. Otherwise,
×
193
                        // we'll need to establish a connection.
×
194
                        if _, err := svr.FindPeer(target); err == nil {
×
195
                                return true, nil
×
196
                        }
×
197

198
                        // We can't establish a channel if no addresses were
199
                        // provided for the peer.
200
                        if len(addrs) == 0 {
×
201
                                return false, errors.New("no addresses specified")
×
202
                        }
×
203

204
                        atplLog.Tracef("Attempting to connect to %x",
×
205
                                target.SerializeCompressed())
×
206

×
207
                        lnAddr := &lnwire.NetAddress{
×
208
                                IdentityKey: target,
×
209
                                ChainNet:    netParams.Net,
×
210
                        }
×
211

×
212
                        // We'll attempt to successively connect to each of the
×
213
                        // advertised IP addresses until we've either exhausted
×
214
                        // the advertised IP addresses, or have made a
×
215
                        // connection.
×
216
                        var connected bool
×
217
                        for _, addr := range addrs {
×
218
                                switch addr.(type) {
×
219
                                case *net.TCPAddr, *tor.OnionAddr:
×
220
                                        lnAddr.Address = addr
×
221
                                default:
×
222
                                        return false, fmt.Errorf("unknown "+
×
223
                                                "address type %T", addr)
×
224
                                }
225

226
                                err := svr.ConnectToPeer(
×
227
                                        lnAddr, false, svr.cfg.ConnectionTimeout,
×
228
                                )
×
229
                                if err != nil {
×
230
                                        // If we weren't able to connect to the
×
231
                                        // peer at this address, then we'll move
×
232
                                        // onto the next.
×
233
                                        continue
×
234
                                }
235

236
                                connected = true
×
237
                                break
×
238
                        }
239

240
                        // If we weren't able to establish a connection at all,
241
                        // then we'll error out.
242
                        if !connected {
×
243
                                return false, errors.New("exhausted all " +
×
244
                                        "advertised addresses")
×
245
                        }
×
246

247
                        return false, nil
×
248
                },
249
                DisconnectPeer: svr.DisconnectPeer,
250
        }
251

252
        // Create and return the autopilot.ManagerCfg that administrates this
253
        // agent-pilot instance.
UNCOV
254
        return &autopilot.ManagerCfg{
×
UNCOV
255
                Self:     self,
×
UNCOV
256
                PilotCfg: &pilotCfg,
×
UNCOV
257
                ChannelState: func() ([]autopilot.LocalChannel, error) {
×
258
                        // We'll fetch the current state of open
×
259
                        // channels from the database to use as initial
×
260
                        // state for the auto-pilot agent.
×
261
                        activeChannels, err := svr.chanStateDB.FetchAllChannels()
×
262
                        if err != nil {
×
263
                                return nil, err
×
264
                        }
×
265
                        chanState := make([]autopilot.LocalChannel,
×
266
                                len(activeChannels))
×
267
                        for i, channel := range activeChannels {
×
268
                                localCommit := channel.LocalCommitment
×
269
                                balance := localCommit.LocalBalance.ToSatoshis()
×
270

×
271
                                chanState[i] = autopilot.LocalChannel{
×
272
                                        ChanID:  channel.ShortChanID(),
×
273
                                        Balance: balance,
×
274
                                        Node: autopilot.NewNodeID(
×
275
                                                channel.IdentityPub,
×
276
                                        ),
×
277
                                }
×
278
                        }
×
279

280
                        return chanState, nil
×
281
                },
282
                ChannelInfo: func(chanPoint wire.OutPoint) (
283
                        *autopilot.LocalChannel, error) {
×
284

×
285
                        channel, err := svr.chanStateDB.FetchChannel(chanPoint)
×
286
                        if err != nil {
×
287
                                return nil, err
×
288
                        }
×
289

290
                        localCommit := channel.LocalCommitment
×
291
                        return &autopilot.LocalChannel{
×
292
                                ChanID:  channel.ShortChanID(),
×
293
                                Balance: localCommit.LocalBalance.ToSatoshis(),
×
294
                                Node:    autopilot.NewNodeID(channel.IdentityPub),
×
295
                        }, nil
×
296
                },
297
                SubscribeTransactions: svr.cc.Wallet.SubscribeTransactions,
298
                SubscribeTopology:     svr.graphBuilder.SubscribeTopology,
299
        }, nil
300
}
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