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

lightningnetwork / lnd / 15774978611

20 Jun 2025 08:42AM UTC coverage: 68.259% (+10.2%) from 58.079%
15774978611

Pull #9967

github

web-flow
Merge fd1e84f38 into a3209a5bf
Pull Request #9967: itest: test automatic peer bootstrapping

1 of 89 new or added lines in 3 files covered. (1.12%)

13 existing lines in 4 files now uncovered.

134766 of 197433 relevant lines covered (68.26%)

22105.62 hits per line

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

3.52
/lntest/node/config.go
1
package node
2

3
import (
4
        "flag"
5
        "fmt"
6
        "io"
7
        "os"
8
        "path"
9
        "path/filepath"
10

11
        "github.com/btcsuite/btcd/chaincfg"
12
        "github.com/btcsuite/btcd/integration/rpctest"
13
        "github.com/lightningnetwork/lnd"
14
        "github.com/lightningnetwork/lnd/chanbackup"
15
        "github.com/lightningnetwork/lnd/kvdb/etcd"
16
        "github.com/lightningnetwork/lnd/lntest/port"
17
        "github.com/lightningnetwork/lnd/lntest/wait"
18
)
19

20
const (
21
        // ListenerFormat is the format string that is used to generate local
22
        // listener addresses.
23
        ListenerFormat = "127.0.0.1:%d"
24

25
        // DefaultCSV is the CSV delay (remotedelay) we will start our test
26
        // nodes with.
27
        DefaultCSV = 4
28
)
29

30
var (
31
        // logOutput is a flag that can be set to append the output from the
32
        // seed nodes to log files.
33
        logOutput = flag.Bool("logoutput", false,
34
                "log output from node n to file output-n.log")
35

36
        // logSubDir is the default directory where the logs are written to if
37
        // logOutput is true.
38
        logSubDir = flag.String("logdir", ".", "default dir to write logs to")
39

40
        // btcdExecutable is the full path to the btcd binary.
41
        btcdExecutable = flag.String(
42
                "btcdexec", "", "full path to btcd binary",
43
        )
44

45
        // CfgLegacy specifies the config used to create a node that uses the
46
        // legacy channel format.
47
        CfgLegacy = []string{"--protocol.legacy.committweak"}
48

49
        // CfgStaticRemoteKey specifies the config used to create a node that
50
        // uses the static remote key feature.
51
        CfgStaticRemoteKey = []string{}
52

53
        // CfgAnchor specifies the config used to create a node that uses the
54
        // anchor output feature.
55
        CfgAnchor = []string{"--protocol.anchors"}
56

57
        // CfgLeased specifies the config used to create a node that uses the
58
        // leased channel feature.
59
        CfgLeased = []string{
60
                "--protocol.anchors",
61
                "--protocol.script-enforced-lease",
62
        }
63

64
        // CfgSimpleTaproot specifies the config used to create a node that
65
        // uses the simple taproot feature.
66
        CfgSimpleTaproot = []string{
67
                "--protocol.anchors",
68
                "--protocol.simple-taproot-chans",
69
        }
70

71
        // CfgRbfCoopClose specifies the config used to create a node that
72
        // supports the new RBF close protocol.
73
        CfgRbfClose = []string{
74
                "--protocol.rbf-coop-close",
75
        }
76

77
        // CfgZeroConf specifies the config used to create a node that uses the
78
        // zero-conf channel feature.
79
        CfgZeroConf = []string{
80
                "--protocol.anchors",
81
                "--protocol.option-scid-alias",
82
                "--protocol.zero-conf",
83
        }
84
)
85

86
type DatabaseBackend int
87

88
const (
89
        BackendBbolt DatabaseBackend = iota
90
        BackendEtcd
91
        BackendPostgres
92
        BackendSqlite
93
)
94

95
// Option is a function for updating a node's configuration.
96
type Option func(*BaseNodeConfig)
97

98
// BackendConfig is an interface that abstracts away the specific chain backend
99
// node implementation.
100
type BackendConfig interface {
101
        // GenArgs returns the arguments needed to be passed to LND at startup
102
        // for using this node as a chain backend.
103
        GenArgs() []string
104

105
        // ConnectMiner is called to establish a connection to the test miner.
106
        ConnectMiner() error
107

108
        // DisconnectMiner is called to disconnect the miner.
109
        DisconnectMiner() error
110

111
        // Name returns the name of the backend type.
112
        Name() string
113

114
        // Credentials returns the rpc username, password and host for the
115
        // backend.
116
        Credentials() (string, string, string, error)
117
}
118

119
// BaseNodeConfig is the base node configuration.
120
type BaseNodeConfig struct {
121
        Name string
122

123
        // LogFilenamePrefix is used to prefix node log files. Can be used to
124
        // store the current test case for simpler postmortem debugging.
125
        LogFilenamePrefix string
126

127
        NetParams         *chaincfg.Params
128
        BackendCfg        BackendConfig
129
        BaseDir           string
130
        ExtraArgs         []string
131
        OriginalExtraArgs []string
132

133
        DataDir        string
134
        LogDir         string
135
        TLSCertPath    string
136
        TLSKeyPath     string
137
        AdminMacPath   string
138
        ReadMacPath    string
139
        InvoiceMacPath string
140

141
        SkipUnlock        bool
142
        Password          []byte
143
        WithPeerBootstrap bool
144

145
        P2PPort     int
146
        RPCPort     int
147
        RESTPort    int
148
        ProfilePort int
149

150
        FeeURL string
151

152
        DBBackend   DatabaseBackend
153
        PostgresDsn string
154
        NativeSQL   bool
155

156
        // NodeID is a unique ID used to identify the node.
157
        NodeID uint32
158

159
        // LndBinary is the full path to the lnd binary that was specifically
160
        // compiled with all required itest flags.
161
        LndBinary string
162

163
        // backupDBDir is the path where a database backup is stored, if any.
164
        backupDBDir string
165

166
        // postgresDBName is the name of the postgres database where lnd data
167
        // is stored in.
168
        postgresDBName string
169
}
170

171
func (cfg BaseNodeConfig) P2PAddr() string {
×
172
        return fmt.Sprintf(ListenerFormat, cfg.P2PPort)
×
173
}
×
174

175
func (cfg BaseNodeConfig) RPCAddr() string {
×
176
        return fmt.Sprintf(ListenerFormat, cfg.RPCPort)
×
177
}
×
178

179
func (cfg BaseNodeConfig) RESTAddr() string {
×
180
        return fmt.Sprintf(ListenerFormat, cfg.RESTPort)
×
181
}
×
182

183
// DBDir returns the holding directory path of the graph database.
184
func (cfg BaseNodeConfig) DBDir() string {
×
185
        return filepath.Join(cfg.DataDir, "graph", cfg.NetParams.Name)
×
186
}
×
187

188
func (cfg BaseNodeConfig) DBPath() string {
×
189
        return filepath.Join(cfg.DBDir(), "channel.db")
×
190
}
×
191

192
func (cfg BaseNodeConfig) ChanBackupPath() string {
×
193
        return filepath.Join(
×
194
                cfg.DataDir, "chain", lnd.BitcoinChainName,
×
195
                fmt.Sprintf(
×
196
                        "%v/%v", cfg.NetParams.Name,
×
197
                        chanbackup.DefaultBackupFileName,
×
198
                ),
×
199
        )
×
200
}
×
201

202
// GenerateListeningPorts generates the ports to listen on designated for the
203
// current lightning network test.
204
func (cfg *BaseNodeConfig) GenerateListeningPorts() {
×
205
        if cfg.P2PPort == 0 {
×
206
                cfg.P2PPort = port.NextAvailablePort()
×
207
        }
×
208
        if cfg.RPCPort == 0 {
×
209
                cfg.RPCPort = port.NextAvailablePort()
×
210
        }
×
211
        if cfg.RESTPort == 0 {
×
212
                cfg.RESTPort = port.NextAvailablePort()
×
213
        }
×
214
        if cfg.ProfilePort == 0 {
×
215
                cfg.ProfilePort = port.NextAvailablePort()
×
216
        }
×
217
}
218

219
// BaseConfig returns the base node configuration struct.
220
func (cfg *BaseNodeConfig) BaseConfig() *BaseNodeConfig {
×
221
        return cfg
×
222
}
×
223

224
// GenArgs generates a slice of command line arguments from the lightning node
225
// config struct.
226
func (cfg *BaseNodeConfig) GenArgs() []string {
×
227
        var args []string
×
228

×
229
        switch cfg.NetParams {
×
230
        case &chaincfg.TestNet3Params:
×
231
                args = append(args, "--bitcoin.testnet")
×
232
        case &chaincfg.TestNet4Params:
×
233
                args = append(args, "--bitcoin.testnet4")
×
234
        case &chaincfg.SimNetParams:
×
235
                args = append(args, "--bitcoin.simnet")
×
236
        case &chaincfg.RegressionNetParams:
×
237
                args = append(args, "--bitcoin.regtest")
×
238
        }
239

240
        backendArgs := cfg.BackendCfg.GenArgs()
×
241
        args = append(args, backendArgs...)
×
242

×
243
        nodeArgs := []string{
×
244
                "--debuglevel=debug",
×
245
                "--bitcoin.defaultchanconfs=1",
×
246
                "--accept-keysend",
×
247
                "--keep-failed-payment-attempts",
×
248
                "--logging.no-commit-hash",
×
249
                fmt.Sprintf("--db.batch-commit-interval=%v", commitInterval),
×
250
                fmt.Sprintf("--bitcoin.defaultremotedelay=%v", DefaultCSV),
×
251
                fmt.Sprintf("--rpclisten=%v", cfg.RPCAddr()),
×
252
                fmt.Sprintf("--restlisten=%v", cfg.RESTAddr()),
×
253
                fmt.Sprintf("--restcors=https://%v", cfg.RESTAddr()),
×
254
                fmt.Sprintf("--listen=%v", cfg.P2PAddr()),
×
255
                fmt.Sprintf("--externalip=%v", cfg.P2PAddr()),
×
256
                fmt.Sprintf("--lnddir=%v", cfg.BaseDir),
×
257
                fmt.Sprintf("--adminmacaroonpath=%v", cfg.AdminMacPath),
×
258
                fmt.Sprintf("--readonlymacaroonpath=%v", cfg.ReadMacPath),
×
259
                fmt.Sprintf("--invoicemacaroonpath=%v", cfg.InvoiceMacPath),
×
260
                fmt.Sprintf("--trickledelay=%v", trickleDelay),
×
261

×
262
                // Use a small batch delay so we can broadcast the
×
263
                // announcements quickly in the tests.
×
264
                "--gossip.sub-batch-delay=5ms",
×
265

×
266
                // Use a small cache duration so the `DescribeGraph` can be
×
267
                // updated quicker.
×
268
                "--caches.rpc-graph-cache-duration=100ms",
×
269

×
270
                // Speed up the tests for bitcoind backend.
×
271
                "--bitcoind.blockpollinginterval=100ms",
×
272
                "--bitcoind.txpollinginterval=100ms",
×
273

×
274
                // Allow unsafe disconnect in itest.
×
275
                "--dev.unsafedisconnect",
×
276
        }
×
277

×
278
        args = append(args, nodeArgs...)
×
279

×
280
        if cfg.Password == nil {
×
281
                args = append(args, "--noseedbackup")
×
282
        }
×
283

NEW
284
        if !cfg.WithPeerBootstrap {
×
NEW
285
                args = append(args, "--nobootstrap")
×
NEW
286
        }
×
287

288
        switch cfg.DBBackend {
×
289
        case BackendEtcd:
×
290
                args = append(args, "--db.backend=etcd")
×
291
                args = append(args, "--db.etcd.embedded")
×
292
                args = append(
×
293
                        args, fmt.Sprintf(
×
294
                                "--db.etcd.embedded_client_port=%v",
×
295
                                port.NextAvailablePort(),
×
296
                        ),
×
297
                )
×
298
                args = append(
×
299
                        args, fmt.Sprintf(
×
300
                                "--db.etcd.embedded_peer_port=%v",
×
301
                                port.NextAvailablePort(),
×
302
                        ),
×
303
                )
×
304
                args = append(
×
305
                        args, fmt.Sprintf(
×
306
                                "--db.etcd.embedded_log_file=%v",
×
307
                                path.Join(cfg.LogDir, "etcd.log"),
×
308
                        ),
×
309
                )
×
310

311
        case BackendPostgres:
×
312
                args = append(args, "--db.backend=postgres")
×
313
                args = append(args, "--db.postgres.dsn="+cfg.PostgresDsn)
×
314
                if cfg.NativeSQL {
×
315
                        args = append(args, "--db.use-native-sql")
×
316
                }
×
317

318
        case BackendSqlite:
×
319
                args = append(args, "--db.backend=sqlite")
×
320
                args = append(args, fmt.Sprintf("--db.sqlite.busytimeout=%v",
×
321
                        wait.SqliteBusyTimeout))
×
322
                if cfg.NativeSQL {
×
323
                        args = append(args, "--db.use-native-sql")
×
324
                }
×
325
        }
326

327
        if cfg.FeeURL != "" {
×
328
                args = append(args, "--fee.url="+cfg.FeeURL)
×
329
        }
×
330

331
        // Put extra args in the end so the args can be overwritten.
332
        if cfg.ExtraArgs != nil {
×
333
                args = append(args, cfg.ExtraArgs...)
×
334
        }
×
335

336
        return args
×
337
}
338

339
// ExtraArgsEtcd returns extra args for configuring LND to use an external etcd
340
// database (for remote channel DB and wallet DB).
341
func ExtraArgsEtcd(etcdCfg *etcd.Config, name string, cluster bool,
342
        leaderSessionTTL int) []string {
×
343

×
344
        extraArgs := []string{
×
345
                "--db.backend=etcd",
×
346
                fmt.Sprintf("--db.etcd.host=%v", etcdCfg.Host),
×
347
                fmt.Sprintf("--db.etcd.user=%v", etcdCfg.User),
×
348
                fmt.Sprintf("--db.etcd.pass=%v", etcdCfg.Pass),
×
349
                fmt.Sprintf("--db.etcd.namespace=%v", etcdCfg.Namespace),
×
350
        }
×
351

×
352
        if etcdCfg.InsecureSkipVerify {
×
353
                extraArgs = append(extraArgs, "--db.etcd.insecure_skip_verify")
×
354
        }
×
355

356
        if cluster {
×
357
                clusterArgs := []string{
×
358
                        "--cluster.enable-leader-election",
×
359
                        fmt.Sprintf("--cluster.id=%v", name),
×
360
                        fmt.Sprintf("--cluster.leader-session-ttl=%v",
×
361
                                leaderSessionTTL),
×
362
                }
×
363
                extraArgs = append(extraArgs, clusterArgs...)
×
364
                extraArgs = append(
×
365
                        extraArgs, "--healthcheck.leader.interval=10s",
×
366
                )
×
367
        }
×
368

369
        return extraArgs
×
370
}
371

372
// GetLogDir returns the passed --logdir flag or the default value if it wasn't
373
// set.
374
func GetLogDir() string {
×
375
        if logSubDir != nil && *logSubDir != "" {
×
376
                return *logSubDir
×
377
        }
×
378

379
        return "."
×
380
}
381

382
// CopyFile copies the file src to dest.
383
func CopyFile(dest, src string) error {
×
384
        s, err := os.Open(src)
×
385
        if err != nil {
×
386
                return err
×
387
        }
×
388
        defer s.Close()
×
389

×
390
        d, err := os.Create(dest)
×
391
        if err != nil {
×
392
                return err
×
393
        }
×
394

395
        if _, err := io.Copy(d, s); err != nil {
×
396
                d.Close()
×
397
                return err
×
398
        }
×
399

400
        return d.Close()
×
401
}
402

403
// GetBtcdBinary returns the full path to the binary of the custom built btcd
404
// executable or an empty string if none is set.
405
func GetBtcdBinary() string {
×
406
        if btcdExecutable != nil {
×
407
                return *btcdExecutable
×
408
        }
×
409

410
        return ""
×
411
}
412

413
func init() {
1✔
414
        // Before we start any node, we need to make sure that any btcd or
1✔
415
        // bitcoind node that is started through the RPC harness uses a unique
1✔
416
        // port as well to avoid any port collisions.
1✔
417
        rpctest.ListenAddressGenerator =
1✔
418
                port.GenerateSystemUniqueListenerAddresses
1✔
419
}
1✔
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