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

lightningnetwork / lnd / 13536249039

26 Feb 2025 03:42AM UTC coverage: 57.462% (-1.4%) from 58.835%
13536249039

Pull #8453

github

Roasbeef
peer: update chooseDeliveryScript to gen script if needed

In this commit, we update `chooseDeliveryScript` to generate a new
script if needed. This allows us to fold in a few other lines that
always followed this function into this expanded function.

The tests have been updated accordingly.
Pull Request #8453: [4/4] - multi: integrate new rbf coop close FSM into the existing peer flow

275 of 1318 new or added lines in 22 files covered. (20.86%)

19521 existing lines in 257 files now uncovered.

103858 of 180741 relevant lines covered (57.46%)

24750.23 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