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

lightningnetwork / lnd / 11216766535

07 Oct 2024 01:37PM UTC coverage: 57.817% (-1.0%) from 58.817%
11216766535

Pull #9148

github

ProofOfKeags
lnwire: remove kickoff feerate from propose/commit
Pull Request #9148: DynComms [2/n]: lnwire: add authenticated wire messages for Dyn*

571 of 879 new or added lines in 16 files covered. (64.96%)

23253 existing lines in 251 files now uncovered.

99022 of 171268 relevant lines covered (57.82%)

38420.67 hits per line

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

0.0
/lnd.go
1
// Copyright (c) 2013-2017 The btcsuite developers
2
// Copyright (c) 2015-2016 The Decred developers
3
// Copyright (C) 2015-2022 The Lightning Network Developers
4

5
package lnd
6

7
import (
8
        "context"
9
        "errors"
10
        "fmt"
11
        "net"
12
        "net/http"
13
        "net/http/pprof"
14
        "os"
15
        "runtime"
16
        runtimePprof "runtime/pprof"
17
        "strings"
18
        "sync"
19
        "time"
20

21
        "github.com/btcsuite/btcd/btcutil"
22
        proxy "github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
23
        "github.com/lightningnetwork/lnd/autopilot"
24
        "github.com/lightningnetwork/lnd/build"
25
        "github.com/lightningnetwork/lnd/chanacceptor"
26
        "github.com/lightningnetwork/lnd/channeldb"
27
        "github.com/lightningnetwork/lnd/cluster"
28
        "github.com/lightningnetwork/lnd/keychain"
29
        "github.com/lightningnetwork/lnd/lncfg"
30
        "github.com/lightningnetwork/lnd/lnrpc"
31
        "github.com/lightningnetwork/lnd/lnwallet"
32
        "github.com/lightningnetwork/lnd/macaroons"
33
        "github.com/lightningnetwork/lnd/monitoring"
34
        "github.com/lightningnetwork/lnd/rpcperms"
35
        "github.com/lightningnetwork/lnd/signal"
36
        "github.com/lightningnetwork/lnd/tor"
37
        "github.com/lightningnetwork/lnd/walletunlocker"
38
        "github.com/lightningnetwork/lnd/watchtower"
39
        "google.golang.org/grpc"
40
        "google.golang.org/grpc/credentials"
41
        "google.golang.org/grpc/keepalive"
42
        "gopkg.in/macaroon-bakery.v2/bakery"
43
        "gopkg.in/macaroon.v2"
44
)
45

46
const (
47
        // adminMacaroonFilePermissions is the file permission that is used for
48
        // creating the admin macaroon file.
49
        //
50
        // Why 640 is safe:
51
        // Assuming a reasonably secure Linux system, it will have a
52
        // separate group for each user. E.g. a new user lnd gets assigned group
53
        // lnd which nothing else belongs to. A system that does not do this is
54
        // inherently broken already.
55
        //
56
        // Since there is no other user in the group, no other user can read
57
        // admin macaroon unless the administrator explicitly allowed it. Thus
58
        // there's no harm allowing group read.
59
        adminMacaroonFilePermissions = 0640
60

61
        // leaderResignTimeout is the timeout used when resigning from the
62
        // leader role. This is kept short so LND can shut down quickly in case
63
        // of a system failure or network partition making the cluster
64
        // unresponsive. The cluster itself should ensure that the leader is not
65
        // elected again until the previous leader has resigned or the leader
66
        // election timeout has passed.
67
        leaderResignTimeout = 5 * time.Second
68
)
69

70
// AdminAuthOptions returns a list of DialOptions that can be used to
71
// authenticate with the RPC server with admin capabilities.
72
// skipMacaroons=true should be set if we don't want to include macaroons with
73
// the auth options. This is needed for instance for the WalletUnlocker
74
// service, which must be usable also before macaroons are created.
75
//
76
// NOTE: This should only be called after the RPCListener has signaled it is
77
// ready.
78
func AdminAuthOptions(cfg *Config, skipMacaroons bool) ([]grpc.DialOption,
79
        error) {
×
80

×
81
        creds, err := credentials.NewClientTLSFromFile(cfg.TLSCertPath, "")
×
82
        if err != nil {
×
83
                return nil, fmt.Errorf("unable to read TLS cert: %w", err)
×
84
        }
×
85

86
        // Create a dial options array.
87
        opts := []grpc.DialOption{
×
88
                grpc.WithTransportCredentials(creds),
×
89
        }
×
90

×
91
        // Get the admin macaroon if macaroons are active.
×
92
        if !skipMacaroons && !cfg.NoMacaroons {
×
93
                // Load the admin macaroon file.
×
94
                macBytes, err := os.ReadFile(cfg.AdminMacPath)
×
95
                if err != nil {
×
96
                        return nil, fmt.Errorf("unable to read macaroon "+
×
97
                                "path (check the network setting!): %v", err)
×
98
                }
×
99

100
                mac := &macaroon.Macaroon{}
×
101
                if err = mac.UnmarshalBinary(macBytes); err != nil {
×
102
                        return nil, fmt.Errorf("unable to decode macaroon: %w",
×
103
                                err)
×
104
                }
×
105

106
                // Now we append the macaroon credentials to the dial options.
107
                cred, err := macaroons.NewMacaroonCredential(mac)
×
108
                if err != nil {
×
109
                        return nil, fmt.Errorf("error cloning mac: %w", err)
×
110
                }
×
111
                opts = append(opts, grpc.WithPerRPCCredentials(cred))
×
112
        }
113

114
        return opts, nil
×
115
}
116

117
// ListenerWithSignal is a net.Listener that has an additional Ready channel
118
// that will be closed when a server starts listening.
119
type ListenerWithSignal struct {
120
        net.Listener
121

122
        // Ready will be closed by the server listening on Listener.
123
        Ready chan struct{}
124

125
        // MacChan is an optional way to pass the admin macaroon to the program
126
        // that started lnd. The channel should be buffered to avoid lnd being
127
        // blocked on sending to the channel.
128
        MacChan chan []byte
129
}
130

131
// ListenerCfg is a wrapper around custom listeners that can be passed to lnd
132
// when calling its main method.
133
type ListenerCfg struct {
134
        // RPCListeners can be set to the listeners to use for the RPC server.
135
        // If empty a regular network listener will be created.
136
        RPCListeners []*ListenerWithSignal
137
}
138

139
var errStreamIsolationWithProxySkip = errors.New(
140
        "while stream isolation is enabled, the TOR proxy may not be skipped",
141
)
142

143
// Main is the true entry point for lnd. It accepts a fully populated and
144
// validated main configuration struct and an optional listener config struct.
145
// This function starts all main system components then blocks until a signal
146
// is received on the shutdownChan at which point everything is shut down again.
147
func Main(cfg *Config, lisCfg ListenerCfg, implCfg *ImplementationCfg,
UNCOV
148
        interceptor signal.Interceptor) error {
×
UNCOV
149

×
UNCOV
150
        defer func() {
×
UNCOV
151
                ltndLog.Info("Shutdown complete\n")
×
UNCOV
152
                err := cfg.LogWriter.Close()
×
UNCOV
153
                if err != nil {
×
154
                        ltndLog.Errorf("Could not close log rotator: %v", err)
×
155
                }
×
156
        }()
157

UNCOV
158
        mkErr := func(format string, args ...interface{}) error {
×
159
                ltndLog.Errorf("Shutting down because error in main "+
×
160
                        "method: "+format, args...)
×
161
                return fmt.Errorf(format, args...)
×
162
        }
×
163

164
        // Show version at startup.
UNCOV
165
        ltndLog.Infof("Version: %s commit=%s, build=%s, logging=%s, "+
×
UNCOV
166
                "debuglevel=%s", build.Version(), build.Commit,
×
UNCOV
167
                build.Deployment, build.LoggingType, cfg.DebugLevel)
×
UNCOV
168

×
UNCOV
169
        var network string
×
UNCOV
170
        switch {
×
171
        case cfg.Bitcoin.TestNet3:
×
172
                network = "testnet"
×
173

174
        case cfg.Bitcoin.MainNet:
×
175
                network = "mainnet"
×
176

177
        case cfg.Bitcoin.SimNet:
×
178
                network = "simnet"
×
179

UNCOV
180
        case cfg.Bitcoin.RegTest:
×
UNCOV
181
                network = "regtest"
×
182

183
        case cfg.Bitcoin.SigNet:
×
184
                network = "signet"
×
185
        }
186

UNCOV
187
        ltndLog.Infof("Active chain: %v (network=%v)",
×
UNCOV
188
                strings.Title(BitcoinChainName), network,
×
UNCOV
189
        )
×
UNCOV
190

×
UNCOV
191
        ctx := context.Background()
×
UNCOV
192
        ctx, cancel := context.WithCancel(ctx)
×
UNCOV
193
        defer cancel()
×
UNCOV
194

×
UNCOV
195
        // Enable http profiling server if requested.
×
UNCOV
196
        if cfg.Profile != "" {
×
UNCOV
197
                // Create the http handler.
×
UNCOV
198
                pprofMux := http.NewServeMux()
×
UNCOV
199
                pprofMux.HandleFunc("/debug/pprof/", pprof.Index)
×
UNCOV
200
                pprofMux.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline)
×
UNCOV
201
                pprofMux.HandleFunc("/debug/pprof/profile", pprof.Profile)
×
UNCOV
202
                pprofMux.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
×
UNCOV
203
                pprofMux.HandleFunc("/debug/pprof/trace", pprof.Trace)
×
UNCOV
204

×
UNCOV
205
                if cfg.BlockingProfile != 0 {
×
206
                        runtime.SetBlockProfileRate(cfg.BlockingProfile)
×
207
                }
×
UNCOV
208
                if cfg.MutexProfile != 0 {
×
209
                        runtime.SetMutexProfileFraction(cfg.MutexProfile)
×
210
                }
×
211

212
                // Redirect all requests to the pprof handler, thus visiting
213
                // `127.0.0.1:6060` will be redirected to
214
                // `127.0.0.1:6060/debug/pprof`.
UNCOV
215
                pprofMux.Handle("/", http.RedirectHandler(
×
UNCOV
216
                        "/debug/pprof/", http.StatusSeeOther,
×
UNCOV
217
                ))
×
UNCOV
218

×
UNCOV
219
                ltndLog.Infof("Pprof listening on %v", cfg.Profile)
×
UNCOV
220

×
UNCOV
221
                // Create the pprof server.
×
UNCOV
222
                pprofServer := &http.Server{
×
UNCOV
223
                        Addr:              cfg.Profile,
×
UNCOV
224
                        Handler:           pprofMux,
×
UNCOV
225
                        ReadHeaderTimeout: cfg.HTTPHeaderTimeout,
×
UNCOV
226
                }
×
UNCOV
227

×
UNCOV
228
                // Shut the server down when lnd is shutting down.
×
UNCOV
229
                defer func() {
×
UNCOV
230
                        ltndLog.Info("Stopping pprof server...")
×
UNCOV
231
                        err := pprofServer.Shutdown(ctx)
×
UNCOV
232
                        if err != nil {
×
233
                                ltndLog.Errorf("Stop pprof server got err: %v",
×
234
                                        err)
×
235
                        }
×
236
                }()
237

238
                // Start the pprof server.
UNCOV
239
                go func() {
×
UNCOV
240
                        err := pprofServer.ListenAndServe()
×
UNCOV
241
                        if err != nil && !errors.Is(err, http.ErrServerClosed) {
×
242
                                ltndLog.Errorf("Serving pprof got err: %v", err)
×
243
                        }
×
244
                }()
245
        }
246

247
        // Write cpu profile if requested.
UNCOV
248
        if cfg.CPUProfile != "" {
×
249
                f, err := os.Create(cfg.CPUProfile)
×
250
                if err != nil {
×
251
                        return mkErr("unable to create CPU profile: %v", err)
×
252
                }
×
253
                _ = runtimePprof.StartCPUProfile(f)
×
254
                defer func() {
×
255
                        _ = f.Close()
×
256
                }()
×
257
                defer runtimePprof.StopCPUProfile()
×
258
        }
259

260
        // Run configuration dependent DB pre-initialization. Note that this
261
        // needs to be done early and once during the startup process, before
262
        // any DB access.
UNCOV
263
        if err := cfg.DB.Init(ctx, cfg.graphDatabaseDir()); err != nil {
×
264
                return mkErr("error initializing DBs: %v", err)
×
265
        }
×
266

UNCOV
267
        tlsManagerCfg := &TLSManagerCfg{
×
UNCOV
268
                TLSCertPath:        cfg.TLSCertPath,
×
UNCOV
269
                TLSKeyPath:         cfg.TLSKeyPath,
×
UNCOV
270
                TLSEncryptKey:      cfg.TLSEncryptKey,
×
UNCOV
271
                TLSExtraIPs:        cfg.TLSExtraIPs,
×
UNCOV
272
                TLSExtraDomains:    cfg.TLSExtraDomains,
×
UNCOV
273
                TLSAutoRefresh:     cfg.TLSAutoRefresh,
×
UNCOV
274
                TLSDisableAutofill: cfg.TLSDisableAutofill,
×
UNCOV
275
                TLSCertDuration:    cfg.TLSCertDuration,
×
UNCOV
276

×
UNCOV
277
                LetsEncryptDir:    cfg.LetsEncryptDir,
×
UNCOV
278
                LetsEncryptDomain: cfg.LetsEncryptDomain,
×
UNCOV
279
                LetsEncryptListen: cfg.LetsEncryptListen,
×
UNCOV
280

×
UNCOV
281
                DisableRestTLS: cfg.DisableRestTLS,
×
UNCOV
282

×
UNCOV
283
                HTTPHeaderTimeout: cfg.HTTPHeaderTimeout,
×
UNCOV
284
        }
×
UNCOV
285
        tlsManager := NewTLSManager(tlsManagerCfg)
×
UNCOV
286
        serverOpts, restDialOpts, restListen, cleanUp,
×
UNCOV
287
                err := tlsManager.SetCertificateBeforeUnlock()
×
UNCOV
288
        if err != nil {
×
289
                return mkErr("error setting cert before unlock: %v", err)
×
290
        }
×
UNCOV
291
        if cleanUp != nil {
×
UNCOV
292
                defer cleanUp()
×
UNCOV
293
        }
×
294

295
        // If we have chosen to start with a dedicated listener for the
296
        // rpc server, we set it directly.
UNCOV
297
        grpcListeners := append([]*ListenerWithSignal{}, lisCfg.RPCListeners...)
×
UNCOV
298
        if len(grpcListeners) == 0 {
×
UNCOV
299
                // Otherwise we create listeners from the RPCListeners defined
×
UNCOV
300
                // in the config.
×
UNCOV
301
                for _, grpcEndpoint := range cfg.RPCListeners {
×
UNCOV
302
                        // Start a gRPC server listening for HTTP/2
×
UNCOV
303
                        // connections.
×
UNCOV
304
                        lis, err := lncfg.ListenOnAddress(grpcEndpoint)
×
UNCOV
305
                        if err != nil {
×
306
                                return mkErr("unable to listen on %s: %v",
×
307
                                        grpcEndpoint, err)
×
308
                        }
×
UNCOV
309
                        defer lis.Close()
×
UNCOV
310

×
UNCOV
311
                        grpcListeners = append(
×
UNCOV
312
                                grpcListeners, &ListenerWithSignal{
×
UNCOV
313
                                        Listener: lis,
×
UNCOV
314
                                        Ready:    make(chan struct{}),
×
UNCOV
315
                                },
×
UNCOV
316
                        )
×
317
                }
318
        }
319

320
        // Create a new RPC interceptor that we'll add to the GRPC server. This
321
        // will be used to log the API calls invoked on the GRPC server.
UNCOV
322
        interceptorChain := rpcperms.NewInterceptorChain(
×
UNCOV
323
                rpcsLog, cfg.NoMacaroons, cfg.RPCMiddleware.Mandatory,
×
UNCOV
324
        )
×
UNCOV
325
        if err := interceptorChain.Start(); err != nil {
×
326
                return mkErr("error starting interceptor chain: %v", err)
×
327
        }
×
UNCOV
328
        defer func() {
×
UNCOV
329
                err := interceptorChain.Stop()
×
UNCOV
330
                if err != nil {
×
331
                        ltndLog.Warnf("error stopping RPC interceptor "+
×
332
                                "chain: %v", err)
×
333
                }
×
334
        }()
335

336
        // Allow the user to overwrite some defaults of the gRPC library related
337
        // to connection keepalive (server side and client side pings).
UNCOV
338
        serverKeepalive := keepalive.ServerParameters{
×
UNCOV
339
                Time:    cfg.GRPC.ServerPingTime,
×
UNCOV
340
                Timeout: cfg.GRPC.ServerPingTimeout,
×
UNCOV
341
        }
×
UNCOV
342
        clientKeepalive := keepalive.EnforcementPolicy{
×
UNCOV
343
                MinTime:             cfg.GRPC.ClientPingMinWait,
×
UNCOV
344
                PermitWithoutStream: cfg.GRPC.ClientAllowPingWithoutStream,
×
UNCOV
345
        }
×
UNCOV
346

×
UNCOV
347
        rpcServerOpts := interceptorChain.CreateServerOpts()
×
UNCOV
348
        serverOpts = append(serverOpts, rpcServerOpts...)
×
UNCOV
349
        serverOpts = append(
×
UNCOV
350
                serverOpts, grpc.MaxRecvMsgSize(lnrpc.MaxGrpcMsgSize),
×
UNCOV
351
                grpc.KeepaliveParams(serverKeepalive),
×
UNCOV
352
                grpc.KeepaliveEnforcementPolicy(clientKeepalive),
×
UNCOV
353
        )
×
UNCOV
354

×
UNCOV
355
        grpcServer := grpc.NewServer(serverOpts...)
×
UNCOV
356
        defer grpcServer.Stop()
×
UNCOV
357

×
UNCOV
358
        // We'll also register the RPC interceptor chain as the StateServer, as
×
UNCOV
359
        // it can be used to query for the current state of the wallet.
×
UNCOV
360
        lnrpc.RegisterStateServer(grpcServer, interceptorChain)
×
UNCOV
361

×
UNCOV
362
        // Initialize, and register our implementation of the gRPC interface
×
UNCOV
363
        // exported by the rpcServer.
×
UNCOV
364
        rpcServer := newRPCServer(cfg, interceptorChain, implCfg, interceptor)
×
UNCOV
365
        err = rpcServer.RegisterWithGrpcServer(grpcServer)
×
UNCOV
366
        if err != nil {
×
367
                return mkErr("error registering gRPC server: %v", err)
×
368
        }
×
369

370
        // Now that both the WalletUnlocker and LightningService have been
371
        // registered with the GRPC server, we can start listening.
UNCOV
372
        err = startGrpcListen(cfg, grpcServer, grpcListeners)
×
UNCOV
373
        if err != nil {
×
374
                return mkErr("error starting gRPC listener: %v", err)
×
375
        }
×
376

377
        // Now start the REST proxy for our gRPC server above. We'll ensure
378
        // we direct LND to connect to its loopback address rather than a
379
        // wildcard to prevent certificate issues when accessing the proxy
380
        // externally.
UNCOV
381
        stopProxy, err := startRestProxy(
×
UNCOV
382
                cfg, rpcServer, restDialOpts, restListen,
×
UNCOV
383
        )
×
UNCOV
384
        if err != nil {
×
385
                return mkErr("error starting REST proxy: %v", err)
×
386
        }
×
UNCOV
387
        defer stopProxy()
×
UNCOV
388

×
UNCOV
389
        // Start leader election if we're running on etcd. Continuation will be
×
UNCOV
390
        // blocked until this instance is elected as the current leader or
×
UNCOV
391
        // shutting down.
×
UNCOV
392
        elected := false
×
UNCOV
393
        var leaderElector cluster.LeaderElector
×
UNCOV
394
        if cfg.Cluster.EnableLeaderElection {
×
395
                electionCtx, cancelElection := context.WithCancel(ctx)
×
396

×
397
                go func() {
×
398
                        <-interceptor.ShutdownChannel()
×
399
                        cancelElection()
×
400
                }()
×
401

402
                ltndLog.Infof("Using %v leader elector",
×
403
                        cfg.Cluster.LeaderElector)
×
404

×
405
                leaderElector, err = cfg.Cluster.MakeLeaderElector(
×
406
                        electionCtx, cfg.DB,
×
407
                )
×
408
                if err != nil {
×
409
                        return err
×
410
                }
×
411

412
                defer func() {
×
413
                        if !elected {
×
414
                                return
×
415
                        }
×
416

417
                        ltndLog.Infof("Attempting to resign from leader role "+
×
418
                                "(%v)", cfg.Cluster.ID)
×
419

×
420
                        // Ensure that we don't block the shutdown process if
×
421
                        // the leader resigning process takes too long. The
×
422
                        // cluster will ensure that the leader is not elected
×
423
                        // again until the previous leader has resigned or the
×
424
                        // leader election timeout has passed.
×
425
                        timeoutCtx, cancel := context.WithTimeout(
×
426
                                ctx, leaderResignTimeout,
×
427
                        )
×
428
                        defer cancel()
×
429

×
430
                        if err := leaderElector.Resign(timeoutCtx); err != nil {
×
431
                                ltndLog.Errorf("Leader elector failed to "+
×
432
                                        "resign: %v", err)
×
433
                        }
×
434
                }()
435

436
                ltndLog.Infof("Starting leadership campaign (%v)",
×
437
                        cfg.Cluster.ID)
×
438

×
439
                if err := leaderElector.Campaign(electionCtx); err != nil {
×
440
                        return mkErr("leadership campaign failed: %v", err)
×
441
                }
×
442

443
                elected = true
×
444
                ltndLog.Infof("Elected as leader (%v)", cfg.Cluster.ID)
×
445
        }
446

UNCOV
447
        dbs, cleanUp, err := implCfg.DatabaseBuilder.BuildDatabase(ctx)
×
UNCOV
448
        switch {
×
449
        case err == channeldb.ErrDryRunMigrationOK:
×
450
                ltndLog.Infof("%v, exiting", err)
×
451
                return nil
×
452
        case err != nil:
×
453
                return mkErr("unable to open databases: %v", err)
×
454
        }
455

UNCOV
456
        defer cleanUp()
×
UNCOV
457

×
UNCOV
458
        partialChainControl, walletConfig, cleanUp, err := implCfg.BuildWalletConfig(
×
UNCOV
459
                ctx, dbs, &implCfg.AuxComponents, interceptorChain,
×
UNCOV
460
                grpcListeners,
×
UNCOV
461
        )
×
UNCOV
462
        if err != nil {
×
463
                return mkErr("error creating wallet config: %v", err)
×
464
        }
×
465

UNCOV
466
        defer cleanUp()
×
UNCOV
467

×
UNCOV
468
        activeChainControl, cleanUp, err := implCfg.BuildChainControl(
×
UNCOV
469
                partialChainControl, walletConfig,
×
UNCOV
470
        )
×
UNCOV
471
        if err != nil {
×
472
                return mkErr("error loading chain control: %v", err)
×
473
        }
×
474

UNCOV
475
        defer cleanUp()
×
UNCOV
476

×
UNCOV
477
        // TODO(roasbeef): add rotation
×
UNCOV
478
        idKeyDesc, err := activeChainControl.KeyRing.DeriveKey(
×
UNCOV
479
                keychain.KeyLocator{
×
UNCOV
480
                        Family: keychain.KeyFamilyNodeKey,
×
UNCOV
481
                        Index:  0,
×
UNCOV
482
                },
×
UNCOV
483
        )
×
UNCOV
484
        if err != nil {
×
485
                return mkErr("error deriving node key: %v", err)
×
486
        }
×
487

UNCOV
488
        if cfg.Tor.StreamIsolation && cfg.Tor.SkipProxyForClearNetTargets {
×
489
                return errStreamIsolationWithProxySkip
×
490
        }
×
491

UNCOV
492
        if cfg.Tor.Active {
×
493
                if cfg.Tor.SkipProxyForClearNetTargets {
×
494
                        srvrLog.Info("Onion services are accessible via Tor! " +
×
495
                                "NOTE: Traffic to clearnet services is not " +
×
496
                                "routed via Tor.")
×
497
                } else {
×
498
                        srvrLog.Infof("Proxying all network traffic via Tor "+
×
499
                                "(stream_isolation=%v)! NOTE: Ensure the "+
×
500
                                "backend node is proxying over Tor as well",
×
501
                                cfg.Tor.StreamIsolation)
×
502
                }
×
503
        }
504

505
        // If tor is active and either v2 or v3 onion services have been
506
        // specified, make a tor controller and pass it into both the watchtower
507
        // server and the regular lnd server.
UNCOV
508
        var torController *tor.Controller
×
UNCOV
509
        if cfg.Tor.Active && (cfg.Tor.V2 || cfg.Tor.V3) {
×
510
                torController = tor.NewController(
×
511
                        cfg.Tor.Control, cfg.Tor.TargetIPAddress,
×
512
                        cfg.Tor.Password,
×
513
                )
×
514

×
515
                // Start the tor controller before giving it to any other
×
516
                // subsystems.
×
517
                if err := torController.Start(); err != nil {
×
518
                        return mkErr("unable to initialize tor controller: %v",
×
519
                                err)
×
520
                }
×
521
                defer func() {
×
522
                        if err := torController.Stop(); err != nil {
×
523
                                ltndLog.Errorf("error stopping tor "+
×
524
                                        "controller: %v", err)
×
525
                        }
×
526
                }()
527
        }
528

UNCOV
529
        var tower *watchtower.Standalone
×
UNCOV
530
        if cfg.Watchtower.Active {
×
UNCOV
531
                towerKeyDesc, err := activeChainControl.KeyRing.DeriveKey(
×
UNCOV
532
                        keychain.KeyLocator{
×
UNCOV
533
                                Family: keychain.KeyFamilyTowerID,
×
UNCOV
534
                                Index:  0,
×
UNCOV
535
                        },
×
UNCOV
536
                )
×
UNCOV
537
                if err != nil {
×
538
                        return mkErr("error deriving tower key: %v", err)
×
539
                }
×
540

UNCOV
541
                wtCfg := &watchtower.Config{
×
UNCOV
542
                        BlockFetcher:   activeChainControl.ChainIO,
×
UNCOV
543
                        DB:             dbs.TowerServerDB,
×
UNCOV
544
                        EpochRegistrar: activeChainControl.ChainNotifier,
×
UNCOV
545
                        Net:            cfg.net,
×
UNCOV
546
                        NewAddress: func() (btcutil.Address, error) {
×
547
                                return activeChainControl.Wallet.NewAddress(
×
548
                                        lnwallet.TaprootPubkey, false,
×
549
                                        lnwallet.DefaultAccountName,
×
550
                                )
×
551
                        },
×
552
                        NodeKeyECDH: keychain.NewPubKeyECDH(
553
                                towerKeyDesc, activeChainControl.KeyRing,
554
                        ),
555
                        PublishTx: activeChainControl.Wallet.PublishTransaction,
556
                        ChainHash: *cfg.ActiveNetParams.GenesisHash,
557
                }
558

559
                // If there is a tor controller (user wants auto hidden
560
                // services), then store a pointer in the watchtower config.
UNCOV
561
                if torController != nil {
×
562
                        wtCfg.TorController = torController
×
563
                        wtCfg.WatchtowerKeyPath = cfg.Tor.WatchtowerKeyPath
×
564
                        wtCfg.EncryptKey = cfg.Tor.EncryptKey
×
565
                        wtCfg.KeyRing = activeChainControl.KeyRing
×
566

×
567
                        switch {
×
568
                        case cfg.Tor.V2:
×
569
                                wtCfg.Type = tor.V2
×
570
                        case cfg.Tor.V3:
×
571
                                wtCfg.Type = tor.V3
×
572
                        }
573
                }
574

UNCOV
575
                wtConfig, err := cfg.Watchtower.Apply(
×
UNCOV
576
                        wtCfg, lncfg.NormalizeAddresses,
×
UNCOV
577
                )
×
UNCOV
578
                if err != nil {
×
579
                        return mkErr("unable to configure watchtower: %v", err)
×
580
                }
×
581

UNCOV
582
                tower, err = watchtower.New(wtConfig)
×
UNCOV
583
                if err != nil {
×
584
                        return mkErr("unable to create watchtower: %v", err)
×
585
                }
×
586
        }
587

588
        // Initialize the MultiplexAcceptor. If lnd was started with the
589
        // zero-conf feature bit, then this will be a ZeroConfAcceptor.
590
        // Otherwise, this will be a ChainedAcceptor.
UNCOV
591
        var multiAcceptor chanacceptor.MultiplexAcceptor
×
UNCOV
592
        if cfg.ProtocolOptions.ZeroConf() {
×
UNCOV
593
                multiAcceptor = chanacceptor.NewZeroConfAcceptor()
×
UNCOV
594
        } else {
×
UNCOV
595
                multiAcceptor = chanacceptor.NewChainedAcceptor()
×
UNCOV
596
        }
×
597

598
        // Set up the core server which will listen for incoming peer
599
        // connections.
UNCOV
600
        server, err := newServer(
×
UNCOV
601
                cfg, cfg.Listeners, dbs, activeChainControl, &idKeyDesc,
×
UNCOV
602
                activeChainControl.Cfg.WalletUnlockParams.ChansToRestore,
×
UNCOV
603
                multiAcceptor, torController, tlsManager, leaderElector,
×
UNCOV
604
                implCfg,
×
UNCOV
605
        )
×
UNCOV
606
        if err != nil {
×
607
                return mkErr("unable to create server: %v", err)
×
608
        }
×
609

610
        // Set up an autopilot manager from the current config. This will be
611
        // used to manage the underlying autopilot agent, starting and stopping
612
        // it at will.
UNCOV
613
        atplCfg, err := initAutoPilot(
×
UNCOV
614
                server, cfg.Autopilot, activeChainControl.MinHtlcIn,
×
UNCOV
615
                cfg.ActiveNetParams,
×
UNCOV
616
        )
×
UNCOV
617
        if err != nil {
×
618
                return mkErr("unable to initialize autopilot: %v", err)
×
619
        }
×
620

UNCOV
621
        atplManager, err := autopilot.NewManager(atplCfg)
×
UNCOV
622
        if err != nil {
×
623
                return mkErr("unable to create autopilot manager: %v", err)
×
624
        }
×
UNCOV
625
        if err := atplManager.Start(); err != nil {
×
626
                return mkErr("unable to start autopilot manager: %v", err)
×
627
        }
×
UNCOV
628
        defer atplManager.Stop()
×
UNCOV
629

×
UNCOV
630
        err = tlsManager.LoadPermanentCertificate(activeChainControl.KeyRing)
×
UNCOV
631
        if err != nil {
×
632
                return mkErr("unable to load permanent TLS certificate: %v",
×
633
                        err)
×
634
        }
×
635

636
        // Now we have created all dependencies necessary to populate and
637
        // start the RPC server.
UNCOV
638
        err = rpcServer.addDeps(
×
UNCOV
639
                server, interceptorChain.MacaroonService(), cfg.SubRPCServers,
×
UNCOV
640
                atplManager, server.invoices, tower, multiAcceptor,
×
UNCOV
641
                server.invoiceHtlcModifier,
×
UNCOV
642
        )
×
UNCOV
643
        if err != nil {
×
644
                return mkErr("unable to add deps to RPC server: %v", err)
×
645
        }
×
UNCOV
646
        if err := rpcServer.Start(); err != nil {
×
647
                return mkErr("unable to start RPC server: %v", err)
×
648
        }
×
UNCOV
649
        defer rpcServer.Stop()
×
UNCOV
650

×
UNCOV
651
        // We transition the RPC state to Active, as the RPC server is up.
×
UNCOV
652
        interceptorChain.SetRPCActive()
×
UNCOV
653

×
UNCOV
654
        if err := interceptor.Notifier.NotifyReady(true); err != nil {
×
655
                return mkErr("error notifying ready: %v", err)
×
656
        }
×
657

658
        // We'll wait until we're fully synced to continue the start up of the
659
        // remainder of the daemon. This ensures that we don't accept any
660
        // possibly invalid state transitions, or accept channels with spent
661
        // funds.
UNCOV
662
        _, bestHeight, err := activeChainControl.ChainIO.GetBestBlock()
×
UNCOV
663
        if err != nil {
×
664
                return mkErr("unable to determine chain tip: %v", err)
×
665
        }
×
666

UNCOV
667
        ltndLog.Infof("Waiting for chain backend to finish sync, "+
×
UNCOV
668
                "start_height=%v", bestHeight)
×
UNCOV
669

×
UNCOV
670
        for {
×
UNCOV
671
                if !interceptor.Alive() {
×
672
                        return nil
×
673
                }
×
674

UNCOV
675
                synced, ts, err := activeChainControl.Wallet.IsSynced()
×
UNCOV
676
                if err != nil {
×
677
                        return mkErr("unable to determine if wallet is "+
×
678
                                "synced: %v", err)
×
679
                }
×
680

UNCOV
681
                ltndLog.Debugf("Syncing to block timestamp: %v, is synced=%v",
×
UNCOV
682
                        time.Unix(ts, 0), synced)
×
UNCOV
683

×
UNCOV
684
                if synced {
×
UNCOV
685
                        break
×
686
                }
687

UNCOV
688
                time.Sleep(time.Second * 1)
×
689
        }
690

UNCOV
691
        _, bestHeight, err = activeChainControl.ChainIO.GetBestBlock()
×
UNCOV
692
        if err != nil {
×
693
                return mkErr("unable to determine chain tip: %v", err)
×
694
        }
×
695

UNCOV
696
        ltndLog.Infof("Chain backend is fully synced (end_height=%v)!",
×
UNCOV
697
                bestHeight)
×
UNCOV
698

×
UNCOV
699
        // With all the relevant chains initialized, we can finally start the
×
UNCOV
700
        // server itself. We start the server in an asynchronous goroutine so
×
UNCOV
701
        // that we are able to interrupt and shutdown the daemon gracefully in
×
UNCOV
702
        // case the startup of the subservers do not behave as expected.
×
UNCOV
703
        errChan := make(chan error)
×
UNCOV
704
        go func() {
×
UNCOV
705
                errChan <- server.Start()
×
UNCOV
706
        }()
×
707

UNCOV
708
        defer func() {
×
UNCOV
709
                err := server.Stop()
×
UNCOV
710
                if err != nil {
×
711
                        ltndLog.Warnf("Stopping the server including all "+
×
712
                                "its subsystems failed with %v", err)
×
713
                }
×
714
        }()
715

UNCOV
716
        select {
×
UNCOV
717
        case err := <-errChan:
×
UNCOV
718
                if err == nil {
×
UNCOV
719
                        break
×
720
                }
721

722
                return mkErr("unable to start server: %v", err)
×
723

724
        case <-interceptor.ShutdownChannel():
×
725
                return nil
×
726
        }
727

728
        // We transition the server state to Active, as the server is up.
UNCOV
729
        interceptorChain.SetServerActive()
×
UNCOV
730

×
UNCOV
731
        // Now that the server has started, if the autopilot mode is currently
×
UNCOV
732
        // active, then we'll start the autopilot agent immediately. It will be
×
UNCOV
733
        // stopped together with the autopilot service.
×
UNCOV
734
        if cfg.Autopilot.Active {
×
735
                if err := atplManager.StartAgent(); err != nil {
×
736
                        return mkErr("unable to start autopilot agent: %v", err)
×
737
                }
×
738
        }
739

UNCOV
740
        if cfg.Watchtower.Active {
×
UNCOV
741
                if err := tower.Start(); err != nil {
×
742
                        return mkErr("unable to start watchtower: %v", err)
×
743
                }
×
UNCOV
744
                defer tower.Stop()
×
745
        }
746

747
        // Wait for shutdown signal from either a graceful server stop or from
748
        // the interrupt handler.
UNCOV
749
        <-interceptor.ShutdownChannel()
×
UNCOV
750
        return nil
×
751
}
752

753
// bakeMacaroon creates a new macaroon with newest version and the given
754
// permissions then returns it binary serialized.
755
func bakeMacaroon(ctx context.Context, svc *macaroons.Service,
UNCOV
756
        permissions []bakery.Op) ([]byte, error) {
×
UNCOV
757

×
UNCOV
758
        mac, err := svc.NewMacaroon(
×
UNCOV
759
                ctx, macaroons.DefaultRootKeyID, permissions...,
×
UNCOV
760
        )
×
UNCOV
761
        if err != nil {
×
762
                return nil, err
×
763
        }
×
764

UNCOV
765
        return mac.M().MarshalBinary()
×
766
}
767

768
// saveMacaroon bakes a macaroon with the specified macaroon permissions and
769
// writes it to a file with the given filename and file permissions.
770
func saveMacaroon(ctx context.Context, svc *macaroons.Service, filename string,
UNCOV
771
        macaroonPermissions []bakery.Op, filePermissions os.FileMode) error {
×
UNCOV
772

×
UNCOV
773
        macaroonBytes, err := bakeMacaroon(ctx, svc, macaroonPermissions)
×
UNCOV
774
        if err != nil {
×
775
                return err
×
776
        }
×
UNCOV
777
        err = os.WriteFile(filename, macaroonBytes, filePermissions)
×
UNCOV
778
        if err != nil {
×
779
                _ = os.Remove(filename)
×
780
                return err
×
781
        }
×
782

UNCOV
783
        return nil
×
784
}
785

786
// genDefaultMacaroons checks for three default macaroon files and generates
787
// them if they do not exist; one admin-level, one for invoice access and one
788
// read-only. Each macaroon is checked and created independently to ensure all
789
// three exist. The admin macaroon can also be used to generate more granular
790
// macaroons.
791
func genDefaultMacaroons(ctx context.Context, svc *macaroons.Service,
UNCOV
792
        admFile, roFile, invoiceFile string) error {
×
UNCOV
793

×
UNCOV
794
        // First, we'll generate a macaroon that only allows the caller to
×
UNCOV
795
        // access invoice related calls. This is useful for merchants and other
×
UNCOV
796
        // services to allow an isolated instance that can only query and
×
UNCOV
797
        // modify invoices.
×
UNCOV
798
        if !lnrpc.FileExists(invoiceFile) {
×
UNCOV
799
                err := saveMacaroon(
×
UNCOV
800
                        ctx, svc, invoiceFile, invoicePermissions, 0644,
×
UNCOV
801
                )
×
UNCOV
802
                if err != nil {
×
803
                        return err
×
804
                }
×
805
        }
806

807
        // Generate the read-only macaroon and write it to a file.
UNCOV
808
        if !lnrpc.FileExists(roFile) {
×
UNCOV
809
                err := saveMacaroon(
×
UNCOV
810
                        ctx, svc, roFile, readPermissions, 0644,
×
UNCOV
811
                )
×
UNCOV
812
                if err != nil {
×
813
                        return err
×
814
                }
×
815
        }
816

817
        // Generate the admin macaroon and write it to a file.
UNCOV
818
        if !lnrpc.FileExists(admFile) {
×
UNCOV
819
                err := saveMacaroon(
×
UNCOV
820
                        ctx, svc, admFile, adminPermissions(),
×
UNCOV
821
                        adminMacaroonFilePermissions,
×
UNCOV
822
                )
×
UNCOV
823
                if err != nil {
×
824
                        return err
×
825
                }
×
826
        }
827

UNCOV
828
        return nil
×
829
}
830

831
// adminPermissions returns a list of all permissions in a safe way that doesn't
832
// modify any of the source lists.
UNCOV
833
func adminPermissions() []bakery.Op {
×
UNCOV
834
        admin := make([]bakery.Op, len(readPermissions)+len(writePermissions))
×
UNCOV
835
        copy(admin[:len(readPermissions)], readPermissions)
×
UNCOV
836
        copy(admin[len(readPermissions):], writePermissions)
×
UNCOV
837
        return admin
×
UNCOV
838
}
×
839

840
// createWalletUnlockerService creates a WalletUnlockerService from the passed
841
// config.
UNCOV
842
func createWalletUnlockerService(cfg *Config) *walletunlocker.UnlockerService {
×
UNCOV
843
        // The macaroonFiles are passed to the wallet unlocker so they can be
×
UNCOV
844
        // deleted and recreated in case the root macaroon key is also changed
×
UNCOV
845
        // during the change password operation.
×
UNCOV
846
        macaroonFiles := []string{
×
UNCOV
847
                cfg.AdminMacPath, cfg.ReadMacPath, cfg.InvoiceMacPath,
×
UNCOV
848
        }
×
UNCOV
849

×
UNCOV
850
        return walletunlocker.New(
×
UNCOV
851
                cfg.ActiveNetParams.Params, macaroonFiles,
×
UNCOV
852
                cfg.ResetWalletTransactions, nil,
×
UNCOV
853
        )
×
UNCOV
854
}
×
855

856
// startGrpcListen starts the GRPC server on the passed listeners.
857
func startGrpcListen(cfg *Config, grpcServer *grpc.Server,
UNCOV
858
        listeners []*ListenerWithSignal) error {
×
UNCOV
859

×
UNCOV
860
        // Use a WaitGroup so we can be sure the instructions on how to input the
×
UNCOV
861
        // password is the last thing to be printed to the console.
×
UNCOV
862
        var wg sync.WaitGroup
×
UNCOV
863

×
UNCOV
864
        for _, lis := range listeners {
×
UNCOV
865
                wg.Add(1)
×
UNCOV
866
                go func(lis *ListenerWithSignal) {
×
UNCOV
867
                        rpcsLog.Infof("RPC server listening on %s", lis.Addr())
×
UNCOV
868

×
UNCOV
869
                        // Close the ready chan to indicate we are listening.
×
UNCOV
870
                        close(lis.Ready)
×
UNCOV
871

×
UNCOV
872
                        wg.Done()
×
UNCOV
873
                        _ = grpcServer.Serve(lis)
×
UNCOV
874
                }(lis)
×
875
        }
876

877
        // If Prometheus monitoring is enabled, start the Prometheus exporter.
UNCOV
878
        if cfg.Prometheus.Enabled() {
×
879
                err := monitoring.ExportPrometheusMetrics(
×
880
                        grpcServer, cfg.Prometheus,
×
881
                )
×
882
                if err != nil {
×
883
                        return err
×
884
                }
×
885
        }
886

887
        // Wait for gRPC servers to be up running.
UNCOV
888
        wg.Wait()
×
UNCOV
889

×
UNCOV
890
        return nil
×
891
}
892

893
// startRestProxy starts the given REST proxy on the listeners found in the
894
// config.
895
func startRestProxy(cfg *Config, rpcServer *rpcServer, restDialOpts []grpc.DialOption,
UNCOV
896
        restListen func(net.Addr) (net.Listener, error)) (func(), error) {
×
UNCOV
897

×
UNCOV
898
        // We use the first RPC listener as the destination for our REST proxy.
×
UNCOV
899
        // If the listener is set to listen on all interfaces, we replace it
×
UNCOV
900
        // with localhost, as we cannot dial it directly.
×
UNCOV
901
        restProxyDest := cfg.RPCListeners[0].String()
×
UNCOV
902
        switch {
×
903
        case strings.Contains(restProxyDest, "0.0.0.0"):
×
904
                restProxyDest = strings.Replace(
×
905
                        restProxyDest, "0.0.0.0", "127.0.0.1", 1,
×
906
                )
×
907

908
        case strings.Contains(restProxyDest, "[::]"):
×
909
                restProxyDest = strings.Replace(
×
910
                        restProxyDest, "[::]", "[::1]", 1,
×
911
                )
×
912
        }
913

UNCOV
914
        var shutdownFuncs []func()
×
UNCOV
915
        shutdown := func() {
×
UNCOV
916
                for _, shutdownFn := range shutdownFuncs {
×
UNCOV
917
                        shutdownFn()
×
UNCOV
918
                }
×
919
        }
920

921
        // Start a REST proxy for our gRPC server.
UNCOV
922
        ctx := context.Background()
×
UNCOV
923
        ctx, cancel := context.WithCancel(ctx)
×
UNCOV
924
        shutdownFuncs = append(shutdownFuncs, cancel)
×
UNCOV
925

×
UNCOV
926
        // We'll set up a proxy that will forward REST calls to the GRPC
×
UNCOV
927
        // server.
×
UNCOV
928
        //
×
UNCOV
929
        // The default JSON marshaler of the REST proxy only sets OrigName to
×
UNCOV
930
        // true, which instructs it to use the same field names as specified in
×
UNCOV
931
        // the proto file and not switch to camel case. What we also want is
×
UNCOV
932
        // that the marshaler prints all values, even if they are falsey.
×
UNCOV
933
        customMarshalerOption := proxy.WithMarshalerOption(
×
UNCOV
934
                proxy.MIMEWildcard, &proxy.JSONPb{
×
UNCOV
935
                        MarshalOptions:   *lnrpc.RESTJsonMarshalOpts,
×
UNCOV
936
                        UnmarshalOptions: *lnrpc.RESTJsonUnmarshalOpts,
×
UNCOV
937
                },
×
UNCOV
938
        )
×
UNCOV
939
        mux := proxy.NewServeMux(
×
UNCOV
940
                customMarshalerOption,
×
UNCOV
941

×
UNCOV
942
                // Don't allow falling back to other HTTP methods, we want exact
×
UNCOV
943
                // matches only. The actual method to be used can be overwritten
×
UNCOV
944
                // by setting X-HTTP-Method-Override so there should be no
×
UNCOV
945
                // reason for not specifying the correct method in the first
×
UNCOV
946
                // place.
×
UNCOV
947
                proxy.WithDisablePathLengthFallback(),
×
UNCOV
948
        )
×
UNCOV
949

×
UNCOV
950
        // Register our services with the REST proxy.
×
UNCOV
951
        err := rpcServer.RegisterWithRestProxy(
×
UNCOV
952
                ctx, mux, restDialOpts, restProxyDest,
×
UNCOV
953
        )
×
UNCOV
954
        if err != nil {
×
955
                return nil, err
×
956
        }
×
957

958
        // Wrap the default grpc-gateway handler with the WebSocket handler.
UNCOV
959
        restHandler := lnrpc.NewWebSocketProxy(
×
UNCOV
960
                mux, rpcsLog, cfg.WSPingInterval, cfg.WSPongWait,
×
UNCOV
961
                lnrpc.LndClientStreamingURIs,
×
UNCOV
962
        )
×
UNCOV
963

×
UNCOV
964
        // Use a WaitGroup so we can be sure the instructions on how to input the
×
UNCOV
965
        // password is the last thing to be printed to the console.
×
UNCOV
966
        var wg sync.WaitGroup
×
UNCOV
967

×
UNCOV
968
        // Now spin up a network listener for each requested port and start a
×
UNCOV
969
        // goroutine that serves REST with the created mux there.
×
UNCOV
970
        for _, restEndpoint := range cfg.RESTListeners {
×
UNCOV
971
                lis, err := restListen(restEndpoint)
×
UNCOV
972
                if err != nil {
×
973
                        ltndLog.Errorf("gRPC proxy unable to listen on %s",
×
974
                                restEndpoint)
×
975
                        return nil, err
×
976
                }
×
977

UNCOV
978
                shutdownFuncs = append(shutdownFuncs, func() {
×
UNCOV
979
                        err := lis.Close()
×
UNCOV
980
                        if err != nil {
×
981
                                rpcsLog.Errorf("Error closing listener: %v",
×
982
                                        err)
×
983
                        }
×
984
                })
985

UNCOV
986
                wg.Add(1)
×
UNCOV
987
                go func() {
×
UNCOV
988
                        rpcsLog.Infof("gRPC proxy started at %s", lis.Addr())
×
UNCOV
989

×
UNCOV
990
                        // Create our proxy chain now. A request will pass
×
UNCOV
991
                        // through the following chain:
×
UNCOV
992
                        // req ---> CORS handler --> WS proxy --->
×
UNCOV
993
                        //   REST proxy --> gRPC endpoint
×
UNCOV
994
                        corsHandler := allowCORS(restHandler, cfg.RestCORS)
×
UNCOV
995

×
UNCOV
996
                        wg.Done()
×
UNCOV
997
                        err := http.Serve(lis, corsHandler)
×
UNCOV
998
                        if err != nil && !lnrpc.IsClosedConnError(err) {
×
999
                                rpcsLog.Error(err)
×
1000
                        }
×
1001
                }()
1002
        }
1003

1004
        // Wait for REST servers to be up running.
UNCOV
1005
        wg.Wait()
×
UNCOV
1006

×
UNCOV
1007
        return shutdown, nil
×
1008
}
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