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

lightningnetwork / lnd / 12343072627

15 Dec 2024 11:09PM UTC coverage: 57.504% (-1.1%) from 58.636%
12343072627

Pull #9315

github

yyforyongyu
contractcourt: offer outgoing htlc one block earlier before its expiry

We need to offer the outgoing htlc one block earlier to make sure when
the expiry height hits, the sweeper will not miss sweeping it in the
same block. This also means the outgoing contest resolver now only does
one thing - watch for preimage spend till height expiry-1, which can
easily be moved into the timeout resolver instead in the future.
Pull Request #9315: Implement `blockbeat`

1445 of 2007 new or added lines in 26 files covered. (72.0%)

19246 existing lines in 249 files now uncovered.

102342 of 177975 relevant lines covered (57.5%)

24772.24 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/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

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:ll
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