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

lightningnetwork / lnd / 16181619122

09 Jul 2025 10:33PM UTC coverage: 55.326% (-2.3%) from 57.611%
16181619122

Pull #10060

github

web-flow
Merge d15e8671f into 0e830da9d
Pull Request #10060: sweep: fix expected spending events being missed

9 of 26 new or added lines in 2 files covered. (34.62%)

23695 existing lines in 280 files now uncovered.

108518 of 196143 relevant lines covered (55.33%)

22354.81 hits per line

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

4.55
/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/v2"
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
        NeutrinoDBName    = "neutrino.db"
29

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

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

42
        defaultPostgresMaxConnections = 50
43
        defaultSqliteMaxConnections   = 2
44

45
        defaultSqliteBusyTimeout = 5 * time.Second
46

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

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

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

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

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

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

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

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

79
        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."`
80

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

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

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

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

89
        UseNativeSQL bool `long:"use-native-sql" description:"If set to true, native SQL will be used instead of KV emulation for tables that support it. Subsystems which support native SQL tables: Invoices."`
90

91
        SkipNativeSQLMigration bool `long:"skip-native-sql-migration" description:"If set to true, the KV to native SQL migration will be skipped. Note that this option is intended for users who experience non-resolvable migration errors. Enabling after there is a non-resolvable migration error that resulted in an incomplete migration will cause that partial migration to be abandoned and ignored and an empty database will be used instead. Since invoices are currently the only native SQL database used, our channels will still work but the invoice history will be forgotten. This option has no effect if native SQL is not in use (db.use-native-sql=false)."`
92

93
        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."`
94

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

97
        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."`
98

99
        NoGcDecayedLog bool `long:"no-gc-decayed-log" description:"Do not run the optional migration that garbage collects the decayed log to save disk space."`
100
}
101

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

128
// Validate validates the DB config.
UNCOV
129
func (db *DB) Validate() error {
×
UNCOV
130
        switch db.Backend {
×
UNCOV
131
        case BoltBackend:
×
UNCOV
132
                if db.UseNativeSQL {
×
133
                        return fmt.Errorf("cannot use native SQL with bolt " +
×
134
                                "backend")
×
135
                }
×
136

137
        case SqliteBackend:
×
138
        case PostgresBackend:
×
139
                if err := db.Postgres.Validate(); err != nil {
×
140
                        return err
×
141
                }
×
142

143
        case EtcdBackend:
×
144
                if db.UseNativeSQL {
×
145
                        return fmt.Errorf("cannot use native SQL with etcd " +
×
146
                                "backend")
×
147
                }
×
148

149
                if !db.Etcd.Embedded && db.Etcd.Host == "" {
×
150
                        return fmt.Errorf("etcd host must be set")
×
151
                }
×
152

153
        default:
×
154
                return fmt.Errorf("unknown backend, must be either '%v', "+
×
155
                        "'%v', '%v' or '%v'", BoltBackend, EtcdBackend,
×
156
                        PostgresBackend, SqliteBackend)
×
157
        }
158

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

UNCOV
172
        return nil
×
173
}
174

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

189
                // Override the original config with the config for
190
                // the embedded instance.
191
                db.Etcd = cfg
×
192

193
        case db.Backend == PostgresBackend:
×
194
                sqlbase.Init(db.Postgres.MaxConnections)
×
195

196
        case db.Backend == SqliteBackend:
×
197
                sqlbase.Init(db.Sqlite.MaxConnections)
×
198
        }
199

UNCOV
200
        return nil
×
201
}
202

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

212
        // ChanStateDB points to a possibly networked replicated backend that
213
        // contains the critical channel state related data.
214
        ChanStateDB kvdb.Backend
215

216
        // HeightHintDB points to a possibly networked replicated backend that
217
        // contains the chain height hint related data.
218
        HeightHintDB kvdb.Backend
219

220
        // MacaroonDB points to a database backend that stores the macaroon root
221
        // keys.
222
        MacaroonDB kvdb.Backend
223

224
        // DecayedLogDB points to a database backend that stores the decayed log
225
        // data.
226
        DecayedLogDB kvdb.Backend
227

228
        // TowerClientDB points to a database backend that stores the watchtower
229
        // client data. This might be nil if the watchtower client is disabled.
230
        TowerClientDB kvdb.Backend
231

232
        // TowerServerDB points to a database backend that stores the watchtower
233
        // server data. This might be nil if the watchtower server is disabled.
234
        TowerServerDB kvdb.Backend
235

236
        // WalletDB is an option that instructs the wallet loader where to load
237
        // the underlying wallet database from.
238
        WalletDB btcwallet.LoaderOption
239

240
        // NativeSQLStore holds a reference to the native SQL store that can
241
        // be used for native SQL queries for tables that already support it.
242
        // This may be nil if the use-native-sql flag was not set.
243
        NativeSQLStore sqldb.DB
244

245
        // Remote indicates whether the database backends are remote, possibly
246
        // replicated instances or local bbolt or sqlite backed databases.
247
        Remote bool
248

249
        // CloseFuncs is a map of close functions for each of the initialized
250
        // DB backends keyed by their namespace name.
251
        CloseFuncs map[string]func() error
252
}
253

254
// GetPostgresConfigKVDB converts a sqldb.PostgresConfig to a kvdb
255
// postgres.Config.
256
func GetPostgresConfigKVDB(cfg *sqldb.PostgresConfig) *postgres.Config {
×
257
        return &postgres.Config{
×
258
                Dsn:            cfg.Dsn,
×
259
                Timeout:        cfg.Timeout,
×
260
                MaxConnections: cfg.MaxConnections,
×
261
        }
×
262
}
×
263

264
// GetSqliteConfigKVDB converts a sqldb.SqliteConfig to a kvdb sqlite.Config.
265
func GetSqliteConfigKVDB(cfg *sqldb.SqliteConfig) *sqlite.Config {
×
266
        return &sqlite.Config{
×
267
                Timeout:        cfg.Timeout,
×
268
                BusyTimeout:    cfg.BusyTimeout,
×
269
                MaxConnections: cfg.MaxConnections,
×
270
                PragmaOptions:  cfg.PragmaOptions,
×
271
        }
×
272
}
×
273

274
// GetBackends returns a set of kvdb.Backends as set in the DB config.
275
func (db *DB) GetBackends(ctx context.Context, chanDBPath,
276
        walletDBPath, towerServerDBPath string, towerClientEnabled,
277
        towerServerEnabled bool, logger btclog.Logger) (*DatabaseBackends,
UNCOV
278
        error) {
×
UNCOV
279

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

×
UNCOV
285
        // If we need to return early because of an error, we invoke any close
×
UNCOV
286
        // function that has been initialized so far.
×
UNCOV
287
        returnEarly := true
×
UNCOV
288
        defer func() {
×
UNCOV
289
                if !returnEarly {
×
UNCOV
290
                        return
×
UNCOV
291
                }
×
292

293
                for _, closeFunc := range closeFuncs {
×
294
                        _ = closeFunc()
×
295
                }
×
296
        }()
297

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

×
318
                etcdMacaroonBackend, err := kvdb.Open(
×
319
                        kvdb.EtcdBackendName, ctx,
×
320
                        db.Etcd.CloneWithSubNamespace(NSMacaroonDB),
×
321
                )
×
322
                if err != nil {
×
323
                        return nil, fmt.Errorf("error opening etcd macaroon "+
×
324
                                "DB: %v", err)
×
325
                }
×
326
                closeFuncs[NSMacaroonDB] = etcdMacaroonBackend.Close
×
327

×
328
                etcdDecayedLogBackend, err := kvdb.Open(
×
329
                        kvdb.EtcdBackendName, ctx,
×
330
                        db.Etcd.CloneWithSubNamespace(NSDecayedLogDB),
×
331
                )
×
332
                if err != nil {
×
333
                        return nil, fmt.Errorf("error opening etcd decayed "+
×
334
                                "log DB: %v", err)
×
335
                }
×
336
                closeFuncs[NSDecayedLogDB] = etcdDecayedLogBackend.Close
×
337

×
338
                etcdTowerClientBackend, err := kvdb.Open(
×
339
                        kvdb.EtcdBackendName, ctx,
×
340
                        db.Etcd.CloneWithSubNamespace(NSTowerClientDB),
×
341
                )
×
342
                if err != nil {
×
343
                        return nil, fmt.Errorf("error opening etcd tower "+
×
344
                                "client DB: %v", err)
×
345
                }
×
346
                closeFuncs[NSTowerClientDB] = etcdTowerClientBackend.Close
×
347

×
348
                etcdTowerServerBackend, err := kvdb.Open(
×
349
                        kvdb.EtcdBackendName, ctx,
×
350
                        db.Etcd.CloneWithSubNamespace(NSTowerServerDB),
×
351
                )
×
352
                if err != nil {
×
353
                        return nil, fmt.Errorf("error opening etcd tower "+
×
354
                                "server DB: %v", err)
×
355
                }
×
356
                closeFuncs[NSTowerServerDB] = etcdTowerServerBackend.Close
×
357

×
358
                etcdWalletBackend, err := kvdb.Open(
×
359
                        kvdb.EtcdBackendName, ctx,
×
360
                        db.Etcd.
×
361
                                CloneWithSubNamespace(NSWalletDB).
×
362
                                CloneWithSingleWriter(),
×
363
                )
×
364
                if err != nil {
×
365
                        return nil, fmt.Errorf("error opening etcd macaroon "+
×
366
                                "DB: %v", err)
×
367
                }
×
368
                closeFuncs[NSWalletDB] = etcdWalletBackend.Close
×
369

×
370
                returnEarly = false
×
371

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

392
        case PostgresBackend:
×
393
                // Convert the sqldb PostgresConfig to a kvdb postgres.Config.
×
394
                // This is a temporary measure until we migrate all kvdb SQL
×
395
                // users to native SQL.
×
396
                postgresConfig := GetPostgresConfigKVDB(db.Postgres)
×
397

×
398
                postgresBackend, err := kvdb.Open(
×
399
                        kvdb.PostgresBackendName, ctx,
×
400
                        postgresConfig, NSChannelDB,
×
401
                )
×
402
                if err != nil {
×
403
                        return nil, fmt.Errorf("error opening postgres graph "+
×
404
                                "DB: %v", err)
×
405
                }
×
406
                closeFuncs[NSChannelDB] = postgresBackend.Close
×
407

×
408
                postgresMacaroonBackend, err := kvdb.Open(
×
409
                        kvdb.PostgresBackendName, ctx,
×
410
                        postgresConfig, NSMacaroonDB,
×
411
                )
×
412
                if err != nil {
×
413
                        return nil, fmt.Errorf("error opening postgres "+
×
414
                                "macaroon DB: %v", err)
×
415
                }
×
416
                closeFuncs[NSMacaroonDB] = postgresMacaroonBackend.Close
×
417

×
418
                postgresDecayedLogBackend, err := kvdb.Open(
×
419
                        kvdb.PostgresBackendName, ctx,
×
420
                        postgresConfig, NSDecayedLogDB,
×
421
                )
×
422
                if err != nil {
×
423
                        return nil, fmt.Errorf("error opening postgres "+
×
424
                                "decayed log DB: %v", err)
×
425
                }
×
426
                closeFuncs[NSDecayedLogDB] = postgresDecayedLogBackend.Close
×
427

×
428
                postgresTowerClientBackend, err := kvdb.Open(
×
429
                        kvdb.PostgresBackendName, ctx,
×
430
                        postgresConfig, NSTowerClientDB,
×
431
                )
×
432
                if err != nil {
×
433
                        return nil, fmt.Errorf("error opening postgres tower "+
×
434
                                "client DB: %v", err)
×
435
                }
×
436
                closeFuncs[NSTowerClientDB] = postgresTowerClientBackend.Close
×
437

×
438
                postgresTowerServerBackend, err := kvdb.Open(
×
439
                        kvdb.PostgresBackendName, ctx,
×
440
                        postgresConfig, NSTowerServerDB,
×
441
                )
×
442
                if err != nil {
×
443
                        return nil, fmt.Errorf("error opening postgres tower "+
×
444
                                "server DB: %v", err)
×
445
                }
×
446
                closeFuncs[NSTowerServerDB] = postgresTowerServerBackend.Close
×
447

×
448
                // The wallet subsystem is still not robust enough to run it
×
449
                // without a single writer in postgres therefore we create a
×
450
                // new config with the global lock enabled.
×
451
                //
×
452
                // NOTE: This is a temporary measure and should be removed as
×
453
                // soon as the wallet code is more robust.
×
454
                postgresConfigWalletDB := GetPostgresConfigKVDB(db.Postgres)
×
455
                postgresConfigWalletDB.WithGlobalLock = true
×
456

×
457
                postgresWalletBackend, err := kvdb.Open(
×
458
                        kvdb.PostgresBackendName, ctx,
×
459
                        postgresConfigWalletDB, NSWalletDB,
×
460
                )
×
461
                if err != nil {
×
462
                        return nil, fmt.Errorf("error opening postgres wallet "+
×
463
                                "DB: %v", err)
×
464
                }
×
465
                closeFuncs[NSWalletDB] = postgresWalletBackend.Close
×
466

×
467
                var nativeSQLStore sqldb.DB
×
468
                if db.UseNativeSQL {
×
469
                        nativePostgresStore, err := sqldb.NewPostgresStore(
×
470
                                db.Postgres,
×
471
                        )
×
472
                        if err != nil {
×
473
                                return nil, fmt.Errorf("error opening "+
×
474
                                        "native postgres store: %v", err)
×
475
                        }
×
476

477
                        nativeSQLStore = nativePostgresStore
×
478
                        closeFuncs[PostgresBackend] = nativePostgresStore.Close
×
479
                }
480

481
                // Warn if the user is trying to switch over to a Postgres DB
482
                // while there is a wallet or channel bbolt DB still present.
483
                warnExistingBoltDBs(
×
484
                        logger, "postgres", walletDBPath, WalletDBName,
×
485
                )
×
486
                warnExistingBoltDBs(
×
487
                        logger, "postgres", chanDBPath, ChannelDBName,
×
488
                )
×
489

×
490
                returnEarly = false
×
491

×
492
                return &DatabaseBackends{
×
493
                        GraphDB:       postgresBackend,
×
494
                        ChanStateDB:   postgresBackend,
×
495
                        HeightHintDB:  postgresBackend,
×
496
                        MacaroonDB:    postgresMacaroonBackend,
×
497
                        DecayedLogDB:  postgresDecayedLogBackend,
×
498
                        TowerClientDB: postgresTowerClientBackend,
×
499
                        TowerServerDB: postgresTowerServerBackend,
×
500
                        // The wallet loader will attempt to use/create the
×
501
                        // wallet in the replicated remote DB if we're running
×
502
                        // in a clustered environment. This will ensure that all
×
503
                        // members of the cluster have access to the same wallet
×
504
                        // state.
×
505
                        WalletDB: btcwallet.LoaderWithExternalWalletDB(
×
506
                                postgresWalletBackend,
×
507
                        ),
×
508
                        NativeSQLStore: nativeSQLStore,
×
509
                        Remote:         true,
×
510
                        CloseFuncs:     closeFuncs,
×
511
                }, nil
×
512

513
        case SqliteBackend:
×
514
                // Convert the sqldb SqliteConfig to a kvdb sqlite.Config.
×
515
                // This is a temporary measure until we migrate all kvdb SQL
×
516
                // users to native SQL.
×
517
                sqliteConfig := GetSqliteConfigKVDB(db.Sqlite)
×
518

×
519
                // Note that for sqlite, we put kv tables for the channel.db,
×
520
                // wtclient.db and sphinxreplay.db all in the channel.sqlite db.
×
521
                // The tables for wallet.db and macaroon.db are in the
×
522
                // chain.sqlite db and watchtower.db tables are in the
×
523
                // watchtower.sqlite db. The reason for the multiple sqlite dbs
×
524
                // is twofold. The first reason is that it maintains the file
×
525
                // structure that users are used to. The second reason is the
×
526
                // fact that sqlite only supports one writer at a time which
×
527
                // would cause deadlocks in the code due to the wallet db often
×
528
                // being accessed during a write to another db.
×
529
                sqliteBackend, err := kvdb.Open(
×
530
                        kvdb.SqliteBackendName, ctx, sqliteConfig, chanDBPath,
×
531
                        SqliteChannelDBName, NSChannelDB,
×
532
                )
×
533
                if err != nil {
×
534
                        return nil, fmt.Errorf("error opening sqlite graph "+
×
535
                                "DB: %v", err)
×
536
                }
×
537
                closeFuncs[NSChannelDB] = sqliteBackend.Close
×
538

×
539
                sqliteMacaroonBackend, err := kvdb.Open(
×
540
                        kvdb.SqliteBackendName, ctx, sqliteConfig, walletDBPath,
×
541
                        SqliteChainDBName, NSMacaroonDB,
×
542
                )
×
543
                if err != nil {
×
544
                        return nil, fmt.Errorf("error opening sqlite "+
×
545
                                "macaroon DB: %v", err)
×
546
                }
×
547
                closeFuncs[NSMacaroonDB] = sqliteMacaroonBackend.Close
×
548

×
549
                sqliteDecayedLogBackend, err := kvdb.Open(
×
550
                        kvdb.SqliteBackendName, ctx, sqliteConfig, chanDBPath,
×
551
                        SqliteChannelDBName, NSDecayedLogDB,
×
552
                )
×
553
                if err != nil {
×
554
                        return nil, fmt.Errorf("error opening sqlite decayed "+
×
555
                                "log DB: %v", err)
×
556
                }
×
557
                closeFuncs[NSDecayedLogDB] = sqliteDecayedLogBackend.Close
×
558

×
559
                sqliteTowerClientBackend, err := kvdb.Open(
×
560
                        kvdb.SqliteBackendName, ctx, sqliteConfig, chanDBPath,
×
561
                        SqliteChannelDBName, NSTowerClientDB,
×
562
                )
×
563
                if err != nil {
×
564
                        return nil, fmt.Errorf("error opening sqlite tower "+
×
565
                                "client DB: %v", err)
×
566
                }
×
567
                closeFuncs[NSTowerClientDB] = sqliteTowerClientBackend.Close
×
568

×
569
                sqliteTowerServerBackend, err := kvdb.Open(
×
570
                        kvdb.SqliteBackendName, ctx, sqliteConfig,
×
571
                        towerServerDBPath, SqliteTowerDBName, NSTowerServerDB,
×
572
                )
×
573
                if err != nil {
×
574
                        return nil, fmt.Errorf("error opening sqlite tower "+
×
575
                                "server DB: %v", err)
×
576
                }
×
577
                closeFuncs[NSTowerServerDB] = sqliteTowerServerBackend.Close
×
578

×
579
                sqliteWalletBackend, err := kvdb.Open(
×
580
                        kvdb.SqliteBackendName, ctx, sqliteConfig, walletDBPath,
×
581
                        SqliteChainDBName, NSWalletDB,
×
582
                )
×
583
                if err != nil {
×
584
                        return nil, fmt.Errorf("error opening sqlite macaroon "+
×
585
                                "DB: %v", err)
×
586
                }
×
587
                closeFuncs[NSWalletDB] = sqliteWalletBackend.Close
×
588

×
589
                var nativeSQLStore sqldb.DB
×
590
                if db.UseNativeSQL {
×
591
                        nativeSQLiteStore, err := sqldb.NewSqliteStore(
×
592
                                db.Sqlite,
×
593
                                path.Join(chanDBPath, SqliteNativeDBName),
×
594
                        )
×
595
                        if err != nil {
×
596
                                return nil, fmt.Errorf("error opening "+
×
597
                                        "native SQLite store: %v", err)
×
598
                        }
×
599

600
                        nativeSQLStore = nativeSQLiteStore
×
601
                        closeFuncs[SqliteBackend] = nativeSQLiteStore.Close
×
602
                }
603

604
                // Warn if the user is trying to switch over to a sqlite DB
605
                // while there is a wallet or channel bbolt DB still present.
606
                warnExistingBoltDBs(
×
607
                        logger, "sqlite", walletDBPath, WalletDBName,
×
608
                )
×
609
                warnExistingBoltDBs(
×
610
                        logger, "sqlite", chanDBPath, ChannelDBName,
×
611
                )
×
612

×
613
                returnEarly = false
×
614

×
615
                return &DatabaseBackends{
×
616
                        GraphDB:       sqliteBackend,
×
617
                        ChanStateDB:   sqliteBackend,
×
618
                        HeightHintDB:  sqliteBackend,
×
619
                        MacaroonDB:    sqliteMacaroonBackend,
×
620
                        DecayedLogDB:  sqliteDecayedLogBackend,
×
621
                        TowerClientDB: sqliteTowerClientBackend,
×
622
                        TowerServerDB: sqliteTowerServerBackend,
×
623
                        // The wallet loader will attempt to use/create the
×
624
                        // wallet in the replicated remote DB if we're running
×
625
                        // in a clustered environment. This will ensure that all
×
626
                        // members of the cluster have access to the same wallet
×
627
                        // state.
×
628
                        WalletDB: btcwallet.LoaderWithExternalWalletDB(
×
629
                                sqliteWalletBackend,
×
630
                        ),
×
631
                        NativeSQLStore: nativeSQLStore,
×
632
                        CloseFuncs:     closeFuncs,
×
633
                }, nil
×
634
        }
635

636
        // We're using all bbolt based databases by default.
UNCOV
637
        boltBackend, err := kvdb.GetBoltBackend(&kvdb.BoltBackendConfig{
×
UNCOV
638
                DBPath:            chanDBPath,
×
UNCOV
639
                DBFileName:        ChannelDBName,
×
UNCOV
640
                DBTimeout:         db.Bolt.DBTimeout,
×
UNCOV
641
                NoFreelistSync:    db.Bolt.NoFreelistSync,
×
UNCOV
642
                AutoCompact:       db.Bolt.AutoCompact,
×
UNCOV
643
                AutoCompactMinAge: db.Bolt.AutoCompactMinAge,
×
UNCOV
644
        })
×
UNCOV
645
        if err != nil {
×
646
                return nil, fmt.Errorf("error opening bolt DB: %w", err)
×
647
        }
×
UNCOV
648
        closeFuncs[NSChannelDB] = boltBackend.Close
×
UNCOV
649

×
UNCOV
650
        macaroonBackend, err := kvdb.GetBoltBackend(&kvdb.BoltBackendConfig{
×
UNCOV
651
                DBPath:            walletDBPath,
×
UNCOV
652
                DBFileName:        MacaroonDBName,
×
UNCOV
653
                DBTimeout:         db.Bolt.DBTimeout,
×
UNCOV
654
                NoFreelistSync:    db.Bolt.NoFreelistSync,
×
UNCOV
655
                AutoCompact:       db.Bolt.AutoCompact,
×
UNCOV
656
                AutoCompactMinAge: db.Bolt.AutoCompactMinAge,
×
UNCOV
657
        })
×
UNCOV
658
        if err != nil {
×
659
                return nil, fmt.Errorf("error opening macaroon DB: %w", err)
×
660
        }
×
UNCOV
661
        closeFuncs[NSMacaroonDB] = macaroonBackend.Close
×
UNCOV
662

×
UNCOV
663
        decayedLogBackend, err := kvdb.GetBoltBackend(&kvdb.BoltBackendConfig{
×
UNCOV
664
                DBPath:            chanDBPath,
×
UNCOV
665
                DBFileName:        DecayedLogDbName,
×
UNCOV
666
                DBTimeout:         db.Bolt.DBTimeout,
×
UNCOV
667
                NoFreelistSync:    db.Bolt.NoFreelistSync,
×
UNCOV
668
                AutoCompact:       db.Bolt.AutoCompact,
×
UNCOV
669
                AutoCompactMinAge: db.Bolt.AutoCompactMinAge,
×
UNCOV
670
        })
×
UNCOV
671
        if err != nil {
×
672
                return nil, fmt.Errorf("error opening decayed log DB: %w", err)
×
673
        }
×
UNCOV
674
        closeFuncs[NSDecayedLogDB] = decayedLogBackend.Close
×
UNCOV
675

×
UNCOV
676
        // The tower client is optional and might not be enabled by the user. We
×
UNCOV
677
        // handle it being nil properly in the main server.
×
UNCOV
678
        var towerClientBackend kvdb.Backend
×
UNCOV
679
        if towerClientEnabled {
×
UNCOV
680
                towerClientBackend, err = kvdb.GetBoltBackend(
×
UNCOV
681
                        &kvdb.BoltBackendConfig{
×
UNCOV
682
                                DBPath:            chanDBPath,
×
UNCOV
683
                                DBFileName:        TowerClientDBName,
×
UNCOV
684
                                DBTimeout:         db.Bolt.DBTimeout,
×
UNCOV
685
                                NoFreelistSync:    db.Bolt.NoFreelistSync,
×
UNCOV
686
                                AutoCompact:       db.Bolt.AutoCompact,
×
UNCOV
687
                                AutoCompactMinAge: db.Bolt.AutoCompactMinAge,
×
UNCOV
688
                        },
×
UNCOV
689
                )
×
UNCOV
690
                if err != nil {
×
691
                        return nil, fmt.Errorf("error opening tower client "+
×
692
                                "DB: %v", err)
×
693
                }
×
UNCOV
694
                closeFuncs[NSTowerClientDB] = towerClientBackend.Close
×
695
        }
696

697
        // The tower server is optional and might not be enabled by the user. We
698
        // handle it being nil properly in the main server.
UNCOV
699
        var towerServerBackend kvdb.Backend
×
UNCOV
700
        if towerServerEnabled {
×
UNCOV
701
                towerServerBackend, err = kvdb.GetBoltBackend(
×
UNCOV
702
                        &kvdb.BoltBackendConfig{
×
UNCOV
703
                                DBPath:            towerServerDBPath,
×
UNCOV
704
                                DBFileName:        TowerServerDBName,
×
UNCOV
705
                                DBTimeout:         db.Bolt.DBTimeout,
×
UNCOV
706
                                NoFreelistSync:    db.Bolt.NoFreelistSync,
×
UNCOV
707
                                AutoCompact:       db.Bolt.AutoCompact,
×
UNCOV
708
                                AutoCompactMinAge: db.Bolt.AutoCompactMinAge,
×
UNCOV
709
                        },
×
UNCOV
710
                )
×
UNCOV
711
                if err != nil {
×
712
                        return nil, fmt.Errorf("error opening tower server "+
×
713
                                "DB: %v", err)
×
714
                }
×
UNCOV
715
                closeFuncs[NSTowerServerDB] = towerServerBackend.Close
×
716
        }
717

UNCOV
718
        returnEarly = false
×
UNCOV
719

×
UNCOV
720
        return &DatabaseBackends{
×
UNCOV
721
                GraphDB:       boltBackend,
×
UNCOV
722
                ChanStateDB:   boltBackend,
×
UNCOV
723
                HeightHintDB:  boltBackend,
×
UNCOV
724
                MacaroonDB:    macaroonBackend,
×
UNCOV
725
                DecayedLogDB:  decayedLogBackend,
×
UNCOV
726
                TowerClientDB: towerClientBackend,
×
UNCOV
727
                TowerServerDB: towerServerBackend,
×
UNCOV
728
                // When "running locally", LND will use the bbolt wallet.db to
×
UNCOV
729
                // store the wallet located in the chain data dir, parametrized
×
UNCOV
730
                // by the active network. The wallet loader has its own cleanup
×
UNCOV
731
                // method so we don't need to add anything to our map (in fact
×
UNCOV
732
                // nothing is opened just yet).
×
UNCOV
733
                WalletDB: btcwallet.LoaderWithLocalWalletDB(
×
UNCOV
734
                        walletDBPath, db.Bolt.NoFreelistSync, db.Bolt.DBTimeout,
×
UNCOV
735
                ),
×
UNCOV
736
                CloseFuncs: closeFuncs,
×
UNCOV
737
        }, nil
×
738
}
739

740
// warnExistingBoltDBs checks if there is an existing bbolt database in the
741
// given location and logs a warning if so.
742
func warnExistingBoltDBs(log btclog.Logger, dbType, dir, fileName string) {
×
743
        if lnrpc.FileExists(filepath.Join(dir, fileName)) {
×
744
                log.Warnf("Found existing bbolt database file in %s/%s while "+
×
745
                        "using database type %s. Existing data will NOT be "+
×
746
                        "migrated to %s automatically!", dir, fileName, dbType,
×
747
                        dbType)
×
748
        }
×
749
}
750

751
// Compile-time constraint to ensure Workers implements the Validator interface.
752
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