• 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

4.44
/lncfg/db.go
1
package lncfg
2

3
import (
4
        "context"
5
        "fmt"
6
        "path"
7
        "path/filepath"
8
        "time"
9

10
        "github.com/btcsuite/btclog"
11
        "github.com/lightningnetwork/lnd/kvdb"
12
        "github.com/lightningnetwork/lnd/kvdb/etcd"
13
        "github.com/lightningnetwork/lnd/kvdb/postgres"
14
        "github.com/lightningnetwork/lnd/kvdb/sqlbase"
15
        "github.com/lightningnetwork/lnd/kvdb/sqlite"
16
        "github.com/lightningnetwork/lnd/lnrpc"
17
        "github.com/lightningnetwork/lnd/lnwallet/btcwallet"
18
        "github.com/lightningnetwork/lnd/sqldb"
19
)
20

21
const (
22
        ChannelDBName     = "channel.db"
23
        MacaroonDBName    = "macaroons.db"
24
        DecayedLogDbName  = "sphinxreplay.db"
25
        TowerClientDBName = "wtclient.db"
26
        TowerServerDBName = "watchtower.db"
27
        WalletDBName      = "wallet.db"
28

29
        SqliteChannelDBName  = "channel.sqlite"
30
        SqliteChainDBName    = "chain.sqlite"
31
        SqliteNeutrinoDBName = "neutrino.sqlite"
32
        SqliteTowerDBName    = "watchtower.sqlite"
33
        SqliteNativeDBName   = "lnd.sqlite"
34

35
        BoltBackend                = "bolt"
36
        EtcdBackend                = "etcd"
37
        PostgresBackend            = "postgres"
38
        SqliteBackend              = "sqlite"
39
        DefaultBatchCommitInterval = 500 * time.Millisecond
40

41
        defaultPostgresMaxConnections = 50
42
        defaultSqliteMaxConnections   = 2
43

44
        defaultSqliteBusyTimeout = 5 * time.Second
45

46
        // NSChannelDB is the namespace name that we use for the combined graph
47
        // and channel state DB.
48
        NSChannelDB = "channeldb"
49

50
        // NSMacaroonDB is the namespace name that we use for the macaroon DB.
51
        NSMacaroonDB = "macaroondb"
52

53
        // NSDecayedLogDB is the namespace name that we use for the sphinx
54
        // replay a.k.a. decayed log DB.
55
        NSDecayedLogDB = "decayedlogdb"
56

57
        // NSTowerClientDB is the namespace name that we use for the watchtower
58
        // client DB.
59
        NSTowerClientDB = "towerclientdb"
60

61
        // NSTowerServerDB is the namespace name that we use for the watchtower
62
        // server DB.
63
        NSTowerServerDB = "towerserverdb"
64

65
        // NSWalletDB is the namespace name that we use for the wallet DB.
66
        NSWalletDB = "walletdb"
67

68
        // NSNeutrinoDB is the namespace name that we use for the neutrino DB.
69
        NSNeutrinoDB = "neutrinodb"
70
)
71

72
// DB holds database configuration for LND.
73
//
74
//nolint:lll
75
type DB struct {
76
        Backend string `long:"backend" description:"The selected database backend."`
77

78
        BatchCommitInterval time.Duration `long:"batch-commit-interval" description:"The maximum duration the channel graph batch schedulers will wait before attempting to commit a batch of pending updates. This can be tradeoff database contenion for commit latency."`
79

80
        Etcd *etcd.Config `group:"etcd" namespace:"etcd" description:"Etcd settings."`
81

82
        Bolt *kvdb.BoltConfig `group:"bolt" namespace:"bolt" description:"Bolt settings."`
83

84
        Postgres *sqldb.PostgresConfig `group:"postgres" namespace:"postgres" description:"Postgres settings."`
85

86
        Sqlite *sqldb.SqliteConfig `group:"sqlite" namespace:"sqlite" description:"Sqlite settings."`
87

88
        UseNativeSQL bool `long:"use-native-sql" description:"Use native SQL for tables that already support it."`
89

90
        NoGraphCache bool `long:"no-graph-cache" description:"Don't use the in-memory graph cache for path finding. Much slower but uses less RAM. Can only be used with a bolt database backend."`
91

92
        PruneRevocation bool `long:"prune-revocation" description:"Run the optional migration that prunes the revocation logs to save disk space."`
93

94
        NoRevLogAmtData bool `long:"no-rev-log-amt-data" description:"If set, the to-local and to-remote output amounts of revoked commitment transactions will not be stored in the revocation log. Note that once this data is lost, a watchtower client will not be able to back up the revoked state."`
95
}
96

97
// DefaultDB creates and returns a new default DB config.
98
func DefaultDB() *DB {
2✔
99
        return &DB{
2✔
100
                Backend:             BoltBackend,
2✔
101
                BatchCommitInterval: DefaultBatchCommitInterval,
2✔
102
                Bolt: &kvdb.BoltConfig{
2✔
103
                        NoFreelistSync:    true,
2✔
104
                        AutoCompactMinAge: kvdb.DefaultBoltAutoCompactMinAge,
2✔
105
                        DBTimeout:         kvdb.DefaultDBTimeout,
2✔
106
                },
2✔
107
                Etcd: &etcd.Config{
2✔
108
                        // Allow at most 32 MiB messages by default.
2✔
109
                        MaxMsgSize: 32768 * 1024,
2✔
110
                },
2✔
111
                Postgres: &sqldb.PostgresConfig{
2✔
112
                        MaxConnections: defaultPostgresMaxConnections,
2✔
113
                },
2✔
114
                Sqlite: &sqldb.SqliteConfig{
2✔
115
                        MaxConnections: defaultSqliteMaxConnections,
2✔
116
                        BusyTimeout:    defaultSqliteBusyTimeout,
2✔
117
                },
2✔
118
                UseNativeSQL: false,
2✔
119
        }
2✔
120
}
2✔
121

122
// Validate validates the DB config.
UNCOV
123
func (db *DB) Validate() error {
×
UNCOV
124
        switch db.Backend {
×
UNCOV
125
        case BoltBackend:
×
UNCOV
126
                if db.UseNativeSQL {
×
127
                        return fmt.Errorf("cannot use native SQL with bolt " +
×
128
                                "backend")
×
129
                }
×
130

131
        case SqliteBackend:
×
132
        case PostgresBackend:
×
133
                if err := db.Postgres.Validate(); err != nil {
×
134
                        return err
×
135
                }
×
136

137
        case EtcdBackend:
×
138
                if db.UseNativeSQL {
×
139
                        return fmt.Errorf("cannot use native SQL with etcd " +
×
140
                                "backend")
×
141
                }
×
142

143
                if !db.Etcd.Embedded && db.Etcd.Host == "" {
×
144
                        return fmt.Errorf("etcd host must be set")
×
145
                }
×
146

147
        default:
×
148
                return fmt.Errorf("unknown backend, must be either '%v', "+
×
149
                        "'%v', '%v' or '%v'", BoltBackend, EtcdBackend,
×
150
                        PostgresBackend, SqliteBackend)
×
151
        }
152

153
        // The path finding uses a manual read transaction that's open for a
154
        // potentially long time. That works fine with the locking model of
155
        // bbolt but can lead to locks or rolled back transactions with etcd or
156
        // postgres. And since we already have a smaller memory footprint for
157
        // remote database setups (due to not needing to memory-map the bbolt DB
158
        // files), we can keep the graph in memory instead. But for mobile
159
        // devices the tradeoff between a smaller memory footprint and the
160
        // longer time needed for path finding might be a desirable one.
UNCOV
161
        if db.NoGraphCache && db.Backend != BoltBackend {
×
162
                return fmt.Errorf("cannot use no-graph-cache with database "+
×
163
                        "backend '%v'", db.Backend)
×
164
        }
×
165

UNCOV
166
        return nil
×
167
}
168

169
// Init should be called upon start to pre-initialize database access dependent
170
// on configuration.
UNCOV
171
func (db *DB) Init(ctx context.Context, dbPath string) error {
×
UNCOV
172
        // Start embedded etcd server if requested.
×
UNCOV
173
        switch {
×
174
        case db.Backend == EtcdBackend && db.Etcd.Embedded:
×
175
                cfg, _, err := kvdb.StartEtcdTestBackend(
×
176
                        dbPath, db.Etcd.EmbeddedClientPort,
×
177
                        db.Etcd.EmbeddedPeerPort, db.Etcd.EmbeddedLogFile,
×
178
                )
×
179
                if err != nil {
×
180
                        return err
×
181
                }
×
182

183
                // Override the original config with the config for
184
                // the embedded instance.
185
                db.Etcd = cfg
×
186

187
        case db.Backend == PostgresBackend:
×
188
                sqlbase.Init(db.Postgres.MaxConnections)
×
189

190
        case db.Backend == SqliteBackend:
×
191
                sqlbase.Init(db.Sqlite.MaxConnections)
×
192
        }
193

UNCOV
194
        return nil
×
195
}
196

197
// DatabaseBackends is a two-tuple that holds the set of active database
198
// backends for the daemon. The two backends we expose are the graph database
199
// backend, and the channel state backend.
200
type DatabaseBackends struct {
201
        // GraphDB points to the database backend that contains the less
202
        // critical data that is accessed often, such as the channel graph and
203
        // chain height hints.
204
        GraphDB kvdb.Backend
205

206
        // ChanStateDB points to a possibly networked replicated backend that
207
        // contains the critical channel state related data.
208
        ChanStateDB kvdb.Backend
209

210
        // HeightHintDB points to a possibly networked replicated backend that
211
        // contains the chain height hint related data.
212
        HeightHintDB kvdb.Backend
213

214
        // MacaroonDB points to a database backend that stores the macaroon root
215
        // keys.
216
        MacaroonDB kvdb.Backend
217

218
        // DecayedLogDB points to a database backend that stores the decayed log
219
        // data.
220
        DecayedLogDB kvdb.Backend
221

222
        // TowerClientDB points to a database backend that stores the watchtower
223
        // client data. This might be nil if the watchtower client is disabled.
224
        TowerClientDB kvdb.Backend
225

226
        // TowerServerDB points to a database backend that stores the watchtower
227
        // server data. This might be nil if the watchtower server is disabled.
228
        TowerServerDB kvdb.Backend
229

230
        // WalletDB is an option that instructs the wallet loader where to load
231
        // the underlying wallet database from.
232
        WalletDB btcwallet.LoaderOption
233

234
        // NativeSQLStore is a pointer to a native SQL store that can be used
235
        // for native SQL queries for tables that already support it. This may
236
        // be nil if the use-native-sql flag was not set.
237
        NativeSQLStore *sqldb.BaseDB
238

239
        // Remote indicates whether the database backends are remote, possibly
240
        // replicated instances or local bbolt or sqlite backed databases.
241
        Remote bool
242

243
        // CloseFuncs is a map of close functions for each of the initialized
244
        // DB backends keyed by their namespace name.
245
        CloseFuncs map[string]func() error
246
}
247

248
// GetPostgresConfigKVDB converts a sqldb.PostgresConfig to a kvdb
249
// postgres.Config.
250
func GetPostgresConfigKVDB(cfg *sqldb.PostgresConfig) *postgres.Config {
×
251
        return &postgres.Config{
×
252
                Dsn:            cfg.Dsn,
×
253
                Timeout:        cfg.Timeout,
×
254
                MaxConnections: cfg.MaxConnections,
×
255
        }
×
256
}
×
257

258
// GetSqliteConfigKVDB converts a sqldb.SqliteConfig to a kvdb sqlite.Config.
259
func GetSqliteConfigKVDB(cfg *sqldb.SqliteConfig) *sqlite.Config {
×
260
        return &sqlite.Config{
×
261
                Timeout:        cfg.Timeout,
×
262
                BusyTimeout:    cfg.BusyTimeout,
×
263
                MaxConnections: cfg.MaxConnections,
×
264
                PragmaOptions:  cfg.PragmaOptions,
×
265
        }
×
266
}
×
267

268
// GetBackends returns a set of kvdb.Backends as set in the DB config.
269
func (db *DB) GetBackends(ctx context.Context, chanDBPath,
270
        walletDBPath, towerServerDBPath string, towerClientEnabled,
271
        towerServerEnabled bool, logger btclog.Logger) (*DatabaseBackends,
UNCOV
272
        error) {
×
UNCOV
273

×
UNCOV
274
        // We keep track of all the kvdb backends we actually open and return a
×
UNCOV
275
        // reference to their close function so they can be cleaned up properly
×
UNCOV
276
        // on error or shutdown.
×
UNCOV
277
        closeFuncs := make(map[string]func() error)
×
UNCOV
278

×
UNCOV
279
        // If we need to return early because of an error, we invoke any close
×
UNCOV
280
        // function that has been initialized so far.
×
UNCOV
281
        returnEarly := true
×
UNCOV
282
        defer func() {
×
UNCOV
283
                if !returnEarly {
×
UNCOV
284
                        return
×
UNCOV
285
                }
×
286

287
                for _, closeFunc := range closeFuncs {
×
288
                        _ = closeFunc()
×
289
                }
×
290
        }()
291

UNCOV
292
        switch db.Backend {
×
293
        case EtcdBackend:
×
294
                // As long as the graph data, channel state and height hint
×
295
                // cache are all still in the channel.db file in bolt, we
×
296
                // replicate the same behavior here and use the same etcd
×
297
                // backend for those three sub DBs. But we namespace it properly
×
298
                // to make such a split even easier in the future. This will
×
299
                // break lnd for users that ran on etcd with 0.13.x since that
×
300
                // code used the root namespace. We assume that nobody used etcd
×
301
                // for mainnet just yet since that feature was clearly marked as
×
302
                // experimental in 0.13.x.
×
303
                etcdBackend, err := kvdb.Open(
×
304
                        kvdb.EtcdBackendName, ctx,
×
305
                        db.Etcd.CloneWithSubNamespace(NSChannelDB),
×
306
                )
×
307
                if err != nil {
×
308
                        return nil, fmt.Errorf("error opening etcd DB: %w", err)
×
309
                }
×
310
                closeFuncs[NSChannelDB] = etcdBackend.Close
×
311

×
312
                etcdMacaroonBackend, err := kvdb.Open(
×
313
                        kvdb.EtcdBackendName, ctx,
×
314
                        db.Etcd.CloneWithSubNamespace(NSMacaroonDB),
×
315
                )
×
316
                if err != nil {
×
317
                        return nil, fmt.Errorf("error opening etcd macaroon "+
×
318
                                "DB: %v", err)
×
319
                }
×
320
                closeFuncs[NSMacaroonDB] = etcdMacaroonBackend.Close
×
321

×
322
                etcdDecayedLogBackend, err := kvdb.Open(
×
323
                        kvdb.EtcdBackendName, ctx,
×
324
                        db.Etcd.CloneWithSubNamespace(NSDecayedLogDB),
×
325
                )
×
326
                if err != nil {
×
327
                        return nil, fmt.Errorf("error opening etcd decayed "+
×
328
                                "log DB: %v", err)
×
329
                }
×
330
                closeFuncs[NSDecayedLogDB] = etcdDecayedLogBackend.Close
×
331

×
332
                etcdTowerClientBackend, err := kvdb.Open(
×
333
                        kvdb.EtcdBackendName, ctx,
×
334
                        db.Etcd.CloneWithSubNamespace(NSTowerClientDB),
×
335
                )
×
336
                if err != nil {
×
337
                        return nil, fmt.Errorf("error opening etcd tower "+
×
338
                                "client DB: %v", err)
×
339
                }
×
340
                closeFuncs[NSTowerClientDB] = etcdTowerClientBackend.Close
×
341

×
342
                etcdTowerServerBackend, err := kvdb.Open(
×
343
                        kvdb.EtcdBackendName, ctx,
×
344
                        db.Etcd.CloneWithSubNamespace(NSTowerServerDB),
×
345
                )
×
346
                if err != nil {
×
347
                        return nil, fmt.Errorf("error opening etcd tower "+
×
348
                                "server DB: %v", err)
×
349
                }
×
350
                closeFuncs[NSTowerServerDB] = etcdTowerServerBackend.Close
×
351

×
352
                etcdWalletBackend, err := kvdb.Open(
×
353
                        kvdb.EtcdBackendName, ctx,
×
354
                        db.Etcd.
×
355
                                CloneWithSubNamespace(NSWalletDB).
×
356
                                CloneWithSingleWriter(),
×
357
                )
×
358
                if err != nil {
×
359
                        return nil, fmt.Errorf("error opening etcd macaroon "+
×
360
                                "DB: %v", err)
×
361
                }
×
362
                closeFuncs[NSWalletDB] = etcdWalletBackend.Close
×
363

×
364
                returnEarly = false
×
365

×
366
                return &DatabaseBackends{
×
367
                        GraphDB:       etcdBackend,
×
368
                        ChanStateDB:   etcdBackend,
×
369
                        HeightHintDB:  etcdBackend,
×
370
                        MacaroonDB:    etcdMacaroonBackend,
×
371
                        DecayedLogDB:  etcdDecayedLogBackend,
×
372
                        TowerClientDB: etcdTowerClientBackend,
×
373
                        TowerServerDB: etcdTowerServerBackend,
×
374
                        // The wallet loader will attempt to use/create the
×
375
                        // wallet in the replicated remote DB if we're running
×
376
                        // in a clustered environment. This will ensure that all
×
377
                        // members of the cluster have access to the same wallet
×
378
                        // state.
×
379
                        WalletDB: btcwallet.LoaderWithExternalWalletDB(
×
380
                                etcdWalletBackend,
×
381
                        ),
×
382
                        Remote:     true,
×
383
                        CloseFuncs: closeFuncs,
×
384
                }, nil
×
385

386
        case PostgresBackend:
×
387
                // Convert the sqldb PostgresConfig to a kvdb postgres.Config.
×
388
                // This is a temporary measure until we migrate all kvdb SQL
×
389
                // users to native SQL.
×
390
                postgresConfig := GetPostgresConfigKVDB(db.Postgres)
×
391

×
392
                postgresBackend, err := kvdb.Open(
×
393
                        kvdb.PostgresBackendName, ctx,
×
394
                        postgresConfig, NSChannelDB,
×
395
                )
×
396
                if err != nil {
×
397
                        return nil, fmt.Errorf("error opening postgres graph "+
×
398
                                "DB: %v", err)
×
399
                }
×
400
                closeFuncs[NSChannelDB] = postgresBackend.Close
×
401

×
402
                postgresMacaroonBackend, err := kvdb.Open(
×
403
                        kvdb.PostgresBackendName, ctx,
×
404
                        postgresConfig, NSMacaroonDB,
×
405
                )
×
406
                if err != nil {
×
407
                        return nil, fmt.Errorf("error opening postgres "+
×
408
                                "macaroon DB: %v", err)
×
409
                }
×
410
                closeFuncs[NSMacaroonDB] = postgresMacaroonBackend.Close
×
411

×
412
                postgresDecayedLogBackend, err := kvdb.Open(
×
413
                        kvdb.PostgresBackendName, ctx,
×
414
                        postgresConfig, NSDecayedLogDB,
×
415
                )
×
416
                if err != nil {
×
417
                        return nil, fmt.Errorf("error opening postgres "+
×
418
                                "decayed log DB: %v", err)
×
419
                }
×
420
                closeFuncs[NSDecayedLogDB] = postgresDecayedLogBackend.Close
×
421

×
422
                postgresTowerClientBackend, err := kvdb.Open(
×
423
                        kvdb.PostgresBackendName, ctx,
×
424
                        postgresConfig, NSTowerClientDB,
×
425
                )
×
426
                if err != nil {
×
427
                        return nil, fmt.Errorf("error opening postgres tower "+
×
428
                                "client DB: %v", err)
×
429
                }
×
430
                closeFuncs[NSTowerClientDB] = postgresTowerClientBackend.Close
×
431

×
432
                postgresTowerServerBackend, err := kvdb.Open(
×
433
                        kvdb.PostgresBackendName, ctx,
×
434
                        postgresConfig, NSTowerServerDB,
×
435
                )
×
436
                if err != nil {
×
437
                        return nil, fmt.Errorf("error opening postgres tower "+
×
438
                                "server DB: %v", err)
×
439
                }
×
440
                closeFuncs[NSTowerServerDB] = postgresTowerServerBackend.Close
×
441

×
442
                postgresWalletBackend, err := kvdb.Open(
×
443
                        kvdb.PostgresBackendName, ctx,
×
444
                        postgresConfig, NSWalletDB,
×
445
                )
×
446
                if err != nil {
×
447
                        return nil, fmt.Errorf("error opening postgres macaroon "+
×
448
                                "DB: %v", err)
×
449
                }
×
450
                closeFuncs[NSWalletDB] = postgresWalletBackend.Close
×
451

×
452
                var nativeSQLStore *sqldb.BaseDB
×
453
                if db.UseNativeSQL {
×
454
                        nativePostgresStore, err := sqldb.NewPostgresStore(
×
455
                                db.Postgres,
×
456
                        )
×
457
                        if err != nil {
×
458
                                return nil, fmt.Errorf("error opening "+
×
459
                                        "native postgres store: %v", err)
×
460
                        }
×
461

462
                        nativeSQLStore = nativePostgresStore.BaseDB
×
463
                        closeFuncs[PostgresBackend] = nativePostgresStore.Close
×
464
                }
465

466
                // Warn if the user is trying to switch over to a Postgres DB
467
                // while there is a wallet or channel bbolt DB still present.
468
                warnExistingBoltDBs(
×
469
                        logger, "postgres", walletDBPath, WalletDBName,
×
470
                )
×
471
                warnExistingBoltDBs(
×
472
                        logger, "postgres", chanDBPath, ChannelDBName,
×
473
                )
×
474

×
475
                returnEarly = false
×
476

×
477
                return &DatabaseBackends{
×
478
                        GraphDB:       postgresBackend,
×
479
                        ChanStateDB:   postgresBackend,
×
480
                        HeightHintDB:  postgresBackend,
×
481
                        MacaroonDB:    postgresMacaroonBackend,
×
482
                        DecayedLogDB:  postgresDecayedLogBackend,
×
483
                        TowerClientDB: postgresTowerClientBackend,
×
484
                        TowerServerDB: postgresTowerServerBackend,
×
485
                        // The wallet loader will attempt to use/create the
×
486
                        // wallet in the replicated remote DB if we're running
×
487
                        // in a clustered environment. This will ensure that all
×
488
                        // members of the cluster have access to the same wallet
×
489
                        // state.
×
490
                        WalletDB: btcwallet.LoaderWithExternalWalletDB(
×
491
                                postgresWalletBackend,
×
492
                        ),
×
493
                        NativeSQLStore: nativeSQLStore,
×
494
                        Remote:         true,
×
495
                        CloseFuncs:     closeFuncs,
×
496
                }, nil
×
497

498
        case SqliteBackend:
×
499
                // Convert the sqldb SqliteConfig to a kvdb sqlite.Config.
×
500
                // This is a temporary measure until we migrate all kvdb SQL
×
501
                // users to native SQL.
×
502
                sqliteConfig := GetSqliteConfigKVDB(db.Sqlite)
×
503

×
504
                // Note that for sqlite, we put kv tables for the channel.db,
×
505
                // wtclient.db and sphinxreplay.db all in the channel.sqlite db.
×
506
                // The tables for wallet.db and macaroon.db are in the
×
507
                // chain.sqlite db and watchtower.db tables are in the
×
508
                // watchtower.sqlite db. The reason for the multiple sqlite dbs
×
509
                // is twofold. The first reason is that it maintains the file
×
510
                // structure that users are used to. The second reason is the
×
511
                // fact that sqlite only supports one writer at a time which
×
512
                // would cause deadlocks in the code due to the wallet db often
×
513
                // being accessed during a write to another db.
×
514
                sqliteBackend, err := kvdb.Open(
×
515
                        kvdb.SqliteBackendName, ctx, sqliteConfig, chanDBPath,
×
516
                        SqliteChannelDBName, NSChannelDB,
×
517
                )
×
518
                if err != nil {
×
519
                        return nil, fmt.Errorf("error opening sqlite graph "+
×
520
                                "DB: %v", err)
×
521
                }
×
522
                closeFuncs[NSChannelDB] = sqliteBackend.Close
×
523

×
524
                sqliteMacaroonBackend, err := kvdb.Open(
×
525
                        kvdb.SqliteBackendName, ctx, sqliteConfig, walletDBPath,
×
526
                        SqliteChainDBName, NSMacaroonDB,
×
527
                )
×
528
                if err != nil {
×
529
                        return nil, fmt.Errorf("error opening sqlite "+
×
530
                                "macaroon DB: %v", err)
×
531
                }
×
532
                closeFuncs[NSMacaroonDB] = sqliteMacaroonBackend.Close
×
533

×
534
                sqliteDecayedLogBackend, err := kvdb.Open(
×
535
                        kvdb.SqliteBackendName, ctx, sqliteConfig, chanDBPath,
×
536
                        SqliteChannelDBName, NSDecayedLogDB,
×
537
                )
×
538
                if err != nil {
×
539
                        return nil, fmt.Errorf("error opening sqlite decayed "+
×
540
                                "log DB: %v", err)
×
541
                }
×
542
                closeFuncs[NSDecayedLogDB] = sqliteDecayedLogBackend.Close
×
543

×
544
                sqliteTowerClientBackend, err := kvdb.Open(
×
545
                        kvdb.SqliteBackendName, ctx, sqliteConfig, chanDBPath,
×
546
                        SqliteChannelDBName, NSTowerClientDB,
×
547
                )
×
548
                if err != nil {
×
549
                        return nil, fmt.Errorf("error opening sqlite tower "+
×
550
                                "client DB: %v", err)
×
551
                }
×
552
                closeFuncs[NSTowerClientDB] = sqliteTowerClientBackend.Close
×
553

×
554
                sqliteTowerServerBackend, err := kvdb.Open(
×
555
                        kvdb.SqliteBackendName, ctx, sqliteConfig,
×
556
                        towerServerDBPath, SqliteTowerDBName, NSTowerServerDB,
×
557
                )
×
558
                if err != nil {
×
559
                        return nil, fmt.Errorf("error opening sqlite tower "+
×
560
                                "server DB: %v", err)
×
561
                }
×
562
                closeFuncs[NSTowerServerDB] = sqliteTowerServerBackend.Close
×
563

×
564
                sqliteWalletBackend, err := kvdb.Open(
×
565
                        kvdb.SqliteBackendName, ctx, sqliteConfig, walletDBPath,
×
566
                        SqliteChainDBName, NSWalletDB,
×
567
                )
×
568
                if err != nil {
×
569
                        return nil, fmt.Errorf("error opening sqlite macaroon "+
×
570
                                "DB: %v", err)
×
571
                }
×
572
                closeFuncs[NSWalletDB] = sqliteWalletBackend.Close
×
573

×
574
                var nativeSQLStore *sqldb.BaseDB
×
575
                if db.UseNativeSQL {
×
576
                        nativeSQLiteStore, err := sqldb.NewSqliteStore(
×
577
                                db.Sqlite,
×
578
                                path.Join(chanDBPath, SqliteNativeDBName),
×
579
                        )
×
580
                        if err != nil {
×
581
                                return nil, fmt.Errorf("error opening "+
×
582
                                        "native SQLite store: %v", err)
×
583
                        }
×
584

585
                        nativeSQLStore = nativeSQLiteStore.BaseDB
×
586
                        closeFuncs[SqliteBackend] = nativeSQLiteStore.Close
×
587
                }
588

589
                // Warn if the user is trying to switch over to a sqlite DB
590
                // while there is a wallet or channel bbolt DB still present.
591
                warnExistingBoltDBs(
×
592
                        logger, "sqlite", walletDBPath, WalletDBName,
×
593
                )
×
594
                warnExistingBoltDBs(
×
595
                        logger, "sqlite", chanDBPath, ChannelDBName,
×
596
                )
×
597

×
598
                returnEarly = false
×
599

×
600
                return &DatabaseBackends{
×
601
                        GraphDB:       sqliteBackend,
×
602
                        ChanStateDB:   sqliteBackend,
×
603
                        HeightHintDB:  sqliteBackend,
×
604
                        MacaroonDB:    sqliteMacaroonBackend,
×
605
                        DecayedLogDB:  sqliteDecayedLogBackend,
×
606
                        TowerClientDB: sqliteTowerClientBackend,
×
607
                        TowerServerDB: sqliteTowerServerBackend,
×
608
                        // The wallet loader will attempt to use/create the
×
609
                        // wallet in the replicated remote DB if we're running
×
610
                        // in a clustered environment. This will ensure that all
×
611
                        // members of the cluster have access to the same wallet
×
612
                        // state.
×
613
                        WalletDB: btcwallet.LoaderWithExternalWalletDB(
×
614
                                sqliteWalletBackend,
×
615
                        ),
×
616
                        NativeSQLStore: nativeSQLStore,
×
617
                        CloseFuncs:     closeFuncs,
×
618
                }, nil
×
619
        }
620

621
        // We're using all bbolt based databases by default.
UNCOV
622
        boltBackend, err := kvdb.GetBoltBackend(&kvdb.BoltBackendConfig{
×
UNCOV
623
                DBPath:            chanDBPath,
×
UNCOV
624
                DBFileName:        ChannelDBName,
×
UNCOV
625
                DBTimeout:         db.Bolt.DBTimeout,
×
UNCOV
626
                NoFreelistSync:    db.Bolt.NoFreelistSync,
×
UNCOV
627
                AutoCompact:       db.Bolt.AutoCompact,
×
UNCOV
628
                AutoCompactMinAge: db.Bolt.AutoCompactMinAge,
×
UNCOV
629
        })
×
UNCOV
630
        if err != nil {
×
631
                return nil, fmt.Errorf("error opening bolt DB: %w", err)
×
632
        }
×
UNCOV
633
        closeFuncs[NSChannelDB] = boltBackend.Close
×
UNCOV
634

×
UNCOV
635
        macaroonBackend, err := kvdb.GetBoltBackend(&kvdb.BoltBackendConfig{
×
UNCOV
636
                DBPath:            walletDBPath,
×
UNCOV
637
                DBFileName:        MacaroonDBName,
×
UNCOV
638
                DBTimeout:         db.Bolt.DBTimeout,
×
UNCOV
639
                NoFreelistSync:    db.Bolt.NoFreelistSync,
×
UNCOV
640
                AutoCompact:       db.Bolt.AutoCompact,
×
UNCOV
641
                AutoCompactMinAge: db.Bolt.AutoCompactMinAge,
×
UNCOV
642
        })
×
UNCOV
643
        if err != nil {
×
644
                return nil, fmt.Errorf("error opening macaroon DB: %w", err)
×
645
        }
×
UNCOV
646
        closeFuncs[NSMacaroonDB] = macaroonBackend.Close
×
UNCOV
647

×
UNCOV
648
        decayedLogBackend, err := kvdb.GetBoltBackend(&kvdb.BoltBackendConfig{
×
UNCOV
649
                DBPath:            chanDBPath,
×
UNCOV
650
                DBFileName:        DecayedLogDbName,
×
UNCOV
651
                DBTimeout:         db.Bolt.DBTimeout,
×
UNCOV
652
                NoFreelistSync:    db.Bolt.NoFreelistSync,
×
UNCOV
653
                AutoCompact:       db.Bolt.AutoCompact,
×
UNCOV
654
                AutoCompactMinAge: db.Bolt.AutoCompactMinAge,
×
UNCOV
655
        })
×
UNCOV
656
        if err != nil {
×
657
                return nil, fmt.Errorf("error opening decayed log DB: %w", err)
×
658
        }
×
UNCOV
659
        closeFuncs[NSDecayedLogDB] = decayedLogBackend.Close
×
UNCOV
660

×
UNCOV
661
        // The tower client is optional and might not be enabled by the user. We
×
UNCOV
662
        // handle it being nil properly in the main server.
×
UNCOV
663
        var towerClientBackend kvdb.Backend
×
UNCOV
664
        if towerClientEnabled {
×
UNCOV
665
                towerClientBackend, err = kvdb.GetBoltBackend(
×
UNCOV
666
                        &kvdb.BoltBackendConfig{
×
UNCOV
667
                                DBPath:            chanDBPath,
×
UNCOV
668
                                DBFileName:        TowerClientDBName,
×
UNCOV
669
                                DBTimeout:         db.Bolt.DBTimeout,
×
UNCOV
670
                                NoFreelistSync:    db.Bolt.NoFreelistSync,
×
UNCOV
671
                                AutoCompact:       db.Bolt.AutoCompact,
×
UNCOV
672
                                AutoCompactMinAge: db.Bolt.AutoCompactMinAge,
×
UNCOV
673
                        },
×
UNCOV
674
                )
×
UNCOV
675
                if err != nil {
×
676
                        return nil, fmt.Errorf("error opening tower client "+
×
677
                                "DB: %v", err)
×
678
                }
×
UNCOV
679
                closeFuncs[NSTowerClientDB] = towerClientBackend.Close
×
680
        }
681

682
        // The tower server is optional and might not be enabled by the user. We
683
        // handle it being nil properly in the main server.
UNCOV
684
        var towerServerBackend kvdb.Backend
×
UNCOV
685
        if towerServerEnabled {
×
UNCOV
686
                towerServerBackend, err = kvdb.GetBoltBackend(
×
UNCOV
687
                        &kvdb.BoltBackendConfig{
×
UNCOV
688
                                DBPath:            towerServerDBPath,
×
UNCOV
689
                                DBFileName:        TowerServerDBName,
×
UNCOV
690
                                DBTimeout:         db.Bolt.DBTimeout,
×
UNCOV
691
                                NoFreelistSync:    db.Bolt.NoFreelistSync,
×
UNCOV
692
                                AutoCompact:       db.Bolt.AutoCompact,
×
UNCOV
693
                                AutoCompactMinAge: db.Bolt.AutoCompactMinAge,
×
UNCOV
694
                        },
×
UNCOV
695
                )
×
UNCOV
696
                if err != nil {
×
697
                        return nil, fmt.Errorf("error opening tower server "+
×
698
                                "DB: %v", err)
×
699
                }
×
UNCOV
700
                closeFuncs[NSTowerServerDB] = towerServerBackend.Close
×
701
        }
702

UNCOV
703
        returnEarly = false
×
UNCOV
704

×
UNCOV
705
        return &DatabaseBackends{
×
UNCOV
706
                GraphDB:       boltBackend,
×
UNCOV
707
                ChanStateDB:   boltBackend,
×
UNCOV
708
                HeightHintDB:  boltBackend,
×
UNCOV
709
                MacaroonDB:    macaroonBackend,
×
UNCOV
710
                DecayedLogDB:  decayedLogBackend,
×
UNCOV
711
                TowerClientDB: towerClientBackend,
×
UNCOV
712
                TowerServerDB: towerServerBackend,
×
UNCOV
713
                // When "running locally", LND will use the bbolt wallet.db to
×
UNCOV
714
                // store the wallet located in the chain data dir, parametrized
×
UNCOV
715
                // by the active network. The wallet loader has its own cleanup
×
UNCOV
716
                // method so we don't need to add anything to our map (in fact
×
UNCOV
717
                // nothing is opened just yet).
×
UNCOV
718
                WalletDB: btcwallet.LoaderWithLocalWalletDB(
×
UNCOV
719
                        walletDBPath, db.Bolt.NoFreelistSync, db.Bolt.DBTimeout,
×
UNCOV
720
                ),
×
UNCOV
721
                CloseFuncs: closeFuncs,
×
UNCOV
722
        }, nil
×
723
}
724

725
// warnExistingBoltDBs checks if there is an existing bbolt database in the
726
// given location and logs a warning if so.
727
func warnExistingBoltDBs(log btclog.Logger, dbType, dir, fileName string) {
×
728
        if lnrpc.FileExists(filepath.Join(dir, fileName)) {
×
729
                log.Warnf("Found existing bbolt database file in %s/%s while "+
×
730
                        "using database type %s. Existing data will NOT be "+
×
731
                        "migrated to %s automatically!", dir, fileName, dbType,
×
732
                        dbType)
×
733
        }
×
734
}
735

736
// Compile-time constraint to ensure Workers implements the Validator interface.
737
var _ Validator = (*DB)(nil)
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