lnd/lncfg/db.go
2024-03-20 08:46:47 +01:00

738 lines
24 KiB
Go

package lncfg
import (
"context"
"fmt"
"path"
"path/filepath"
"time"
"github.com/btcsuite/btclog"
"github.com/lightningnetwork/lnd/kvdb"
"github.com/lightningnetwork/lnd/kvdb/etcd"
"github.com/lightningnetwork/lnd/kvdb/postgres"
"github.com/lightningnetwork/lnd/kvdb/sqlbase"
"github.com/lightningnetwork/lnd/kvdb/sqlite"
"github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lnwallet/btcwallet"
"github.com/lightningnetwork/lnd/sqldb"
)
const (
ChannelDBName = "channel.db"
MacaroonDBName = "macaroons.db"
DecayedLogDbName = "sphinxreplay.db"
TowerClientDBName = "wtclient.db"
TowerServerDBName = "watchtower.db"
WalletDBName = "wallet.db"
SqliteChannelDBName = "channel.sqlite"
SqliteChainDBName = "chain.sqlite"
SqliteNeutrinoDBName = "neutrino.sqlite"
SqliteTowerDBName = "watchtower.sqlite"
SqliteNativeDBName = "lnd.sqlite"
BoltBackend = "bolt"
EtcdBackend = "etcd"
PostgresBackend = "postgres"
SqliteBackend = "sqlite"
DefaultBatchCommitInterval = 500 * time.Millisecond
defaultPostgresMaxConnections = 50
defaultSqliteMaxConnections = 2
defaultSqliteBusyTimeout = 5 * time.Second
// NSChannelDB is the namespace name that we use for the combined graph
// and channel state DB.
NSChannelDB = "channeldb"
// NSMacaroonDB is the namespace name that we use for the macaroon DB.
NSMacaroonDB = "macaroondb"
// NSDecayedLogDB is the namespace name that we use for the sphinx
// replay a.k.a. decayed log DB.
NSDecayedLogDB = "decayedlogdb"
// NSTowerClientDB is the namespace name that we use for the watchtower
// client DB.
NSTowerClientDB = "towerclientdb"
// NSTowerServerDB is the namespace name that we use for the watchtower
// server DB.
NSTowerServerDB = "towerserverdb"
// NSWalletDB is the namespace name that we use for the wallet DB.
NSWalletDB = "walletdb"
// NSNeutrinoDB is the namespace name that we use for the neutrino DB.
NSNeutrinoDB = "neutrinodb"
)
// DB holds database configuration for LND.
//
//nolint:lll
type DB struct {
Backend string `long:"backend" description:"The selected database backend."`
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."`
Etcd *etcd.Config `group:"etcd" namespace:"etcd" description:"Etcd settings."`
Bolt *kvdb.BoltConfig `group:"bolt" namespace:"bolt" description:"Bolt settings."`
Postgres *sqldb.PostgresConfig `group:"postgres" namespace:"postgres" description:"Postgres settings."`
Sqlite *sqldb.SqliteConfig `group:"sqlite" namespace:"sqlite" description:"Sqlite settings."`
UseNativeSQL bool `long:"use-native-sql" description:"Use native SQL for tables that already support it."`
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."`
PruneRevocation bool `long:"prune-revocation" description:"Run the optional migration that prunes the revocation logs to save disk space."`
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."`
}
// DefaultDB creates and returns a new default DB config.
func DefaultDB() *DB {
return &DB{
Backend: BoltBackend,
BatchCommitInterval: DefaultBatchCommitInterval,
Bolt: &kvdb.BoltConfig{
NoFreelistSync: true,
AutoCompactMinAge: kvdb.DefaultBoltAutoCompactMinAge,
DBTimeout: kvdb.DefaultDBTimeout,
},
Etcd: &etcd.Config{
// Allow at most 32 MiB messages by default.
MaxMsgSize: 32768 * 1024,
},
Postgres: &sqldb.PostgresConfig{
MaxConnections: defaultPostgresMaxConnections,
},
Sqlite: &sqldb.SqliteConfig{
MaxConnections: defaultSqliteMaxConnections,
BusyTimeout: defaultSqliteBusyTimeout,
},
UseNativeSQL: false,
}
}
// Validate validates the DB config.
func (db *DB) Validate() error {
switch db.Backend {
case BoltBackend:
if db.UseNativeSQL {
return fmt.Errorf("cannot use native SQL with bolt " +
"backend")
}
case SqliteBackend:
case PostgresBackend:
if err := db.Postgres.Validate(); err != nil {
return err
}
case EtcdBackend:
if db.UseNativeSQL {
return fmt.Errorf("cannot use native SQL with etcd " +
"backend")
}
if !db.Etcd.Embedded && db.Etcd.Host == "" {
return fmt.Errorf("etcd host must be set")
}
default:
return fmt.Errorf("unknown backend, must be either '%v', "+
"'%v', '%v' or '%v'", BoltBackend, EtcdBackend,
PostgresBackend, SqliteBackend)
}
// The path finding uses a manual read transaction that's open for a
// potentially long time. That works fine with the locking model of
// bbolt but can lead to locks or rolled back transactions with etcd or
// postgres. And since we already have a smaller memory footprint for
// remote database setups (due to not needing to memory-map the bbolt DB
// files), we can keep the graph in memory instead. But for mobile
// devices the tradeoff between a smaller memory footprint and the
// longer time needed for path finding might be a desirable one.
if db.NoGraphCache && db.Backend != BoltBackend {
return fmt.Errorf("cannot use no-graph-cache with database "+
"backend '%v'", db.Backend)
}
return nil
}
// Init should be called upon start to pre-initialize database access dependent
// on configuration.
func (db *DB) Init(ctx context.Context, dbPath string) error {
// Start embedded etcd server if requested.
switch {
case db.Backend == EtcdBackend && db.Etcd.Embedded:
cfg, _, err := kvdb.StartEtcdTestBackend(
dbPath, db.Etcd.EmbeddedClientPort,
db.Etcd.EmbeddedPeerPort, db.Etcd.EmbeddedLogFile,
)
if err != nil {
return err
}
// Override the original config with the config for
// the embedded instance.
db.Etcd = cfg
case db.Backend == PostgresBackend:
sqlbase.Init(db.Postgres.MaxConnections)
case db.Backend == SqliteBackend:
sqlbase.Init(db.Sqlite.MaxConnections)
}
return nil
}
// DatabaseBackends is a two-tuple that holds the set of active database
// backends for the daemon. The two backends we expose are the graph database
// backend, and the channel state backend.
type DatabaseBackends struct {
// GraphDB points to the database backend that contains the less
// critical data that is accessed often, such as the channel graph and
// chain height hints.
GraphDB kvdb.Backend
// ChanStateDB points to a possibly networked replicated backend that
// contains the critical channel state related data.
ChanStateDB kvdb.Backend
// HeightHintDB points to a possibly networked replicated backend that
// contains the chain height hint related data.
HeightHintDB kvdb.Backend
// MacaroonDB points to a database backend that stores the macaroon root
// keys.
MacaroonDB kvdb.Backend
// DecayedLogDB points to a database backend that stores the decayed log
// data.
DecayedLogDB kvdb.Backend
// TowerClientDB points to a database backend that stores the watchtower
// client data. This might be nil if the watchtower client is disabled.
TowerClientDB kvdb.Backend
// TowerServerDB points to a database backend that stores the watchtower
// server data. This might be nil if the watchtower server is disabled.
TowerServerDB kvdb.Backend
// WalletDB is an option that instructs the wallet loader where to load
// the underlying wallet database from.
WalletDB btcwallet.LoaderOption
// NativeSQLStore is a pointer to a native SQL store that can be used
// for native SQL queries for tables that already support it. This may
// be nil if the use-native-sql flag was not set.
NativeSQLStore *sqldb.BaseDB
// Remote indicates whether the database backends are remote, possibly
// replicated instances or local bbolt or sqlite backed databases.
Remote bool
// CloseFuncs is a map of close functions for each of the initialized
// DB backends keyed by their namespace name.
CloseFuncs map[string]func() error
}
// GetPostgresConfigKVDB converts a sqldb.PostgresConfig to a kvdb
// postgres.Config.
func GetPostgresConfigKVDB(cfg *sqldb.PostgresConfig) *postgres.Config {
return &postgres.Config{
Dsn: cfg.Dsn,
Timeout: cfg.Timeout,
MaxConnections: cfg.MaxConnections,
}
}
// GetSqliteConfigKVDB converts a sqldb.SqliteConfig to a kvdb sqlite.Config.
func GetSqliteConfigKVDB(cfg *sqldb.SqliteConfig) *sqlite.Config {
return &sqlite.Config{
Timeout: cfg.Timeout,
BusyTimeout: cfg.BusyTimeout,
MaxConnections: cfg.MaxConnections,
PragmaOptions: cfg.PragmaOptions,
}
}
// GetBackends returns a set of kvdb.Backends as set in the DB config.
func (db *DB) GetBackends(ctx context.Context, chanDBPath,
walletDBPath, towerServerDBPath string, towerClientEnabled,
towerServerEnabled bool, logger btclog.Logger) (*DatabaseBackends,
error) {
// We keep track of all the kvdb backends we actually open and return a
// reference to their close function so they can be cleaned up properly
// on error or shutdown.
closeFuncs := make(map[string]func() error)
// If we need to return early because of an error, we invoke any close
// function that has been initialized so far.
returnEarly := true
defer func() {
if !returnEarly {
return
}
for _, closeFunc := range closeFuncs {
_ = closeFunc()
}
}()
switch db.Backend {
case EtcdBackend:
// As long as the graph data, channel state and height hint
// cache are all still in the channel.db file in bolt, we
// replicate the same behavior here and use the same etcd
// backend for those three sub DBs. But we namespace it properly
// to make such a split even easier in the future. This will
// break lnd for users that ran on etcd with 0.13.x since that
// code used the root namespace. We assume that nobody used etcd
// for mainnet just yet since that feature was clearly marked as
// experimental in 0.13.x.
etcdBackend, err := kvdb.Open(
kvdb.EtcdBackendName, ctx,
db.Etcd.CloneWithSubNamespace(NSChannelDB),
)
if err != nil {
return nil, fmt.Errorf("error opening etcd DB: %w", err)
}
closeFuncs[NSChannelDB] = etcdBackend.Close
etcdMacaroonBackend, err := kvdb.Open(
kvdb.EtcdBackendName, ctx,
db.Etcd.CloneWithSubNamespace(NSMacaroonDB),
)
if err != nil {
return nil, fmt.Errorf("error opening etcd macaroon "+
"DB: %v", err)
}
closeFuncs[NSMacaroonDB] = etcdMacaroonBackend.Close
etcdDecayedLogBackend, err := kvdb.Open(
kvdb.EtcdBackendName, ctx,
db.Etcd.CloneWithSubNamespace(NSDecayedLogDB),
)
if err != nil {
return nil, fmt.Errorf("error opening etcd decayed "+
"log DB: %v", err)
}
closeFuncs[NSDecayedLogDB] = etcdDecayedLogBackend.Close
etcdTowerClientBackend, err := kvdb.Open(
kvdb.EtcdBackendName, ctx,
db.Etcd.CloneWithSubNamespace(NSTowerClientDB),
)
if err != nil {
return nil, fmt.Errorf("error opening etcd tower "+
"client DB: %v", err)
}
closeFuncs[NSTowerClientDB] = etcdTowerClientBackend.Close
etcdTowerServerBackend, err := kvdb.Open(
kvdb.EtcdBackendName, ctx,
db.Etcd.CloneWithSubNamespace(NSTowerServerDB),
)
if err != nil {
return nil, fmt.Errorf("error opening etcd tower "+
"server DB: %v", err)
}
closeFuncs[NSTowerServerDB] = etcdTowerServerBackend.Close
etcdWalletBackend, err := kvdb.Open(
kvdb.EtcdBackendName, ctx,
db.Etcd.
CloneWithSubNamespace(NSWalletDB).
CloneWithSingleWriter(),
)
if err != nil {
return nil, fmt.Errorf("error opening etcd macaroon "+
"DB: %v", err)
}
closeFuncs[NSWalletDB] = etcdWalletBackend.Close
returnEarly = false
return &DatabaseBackends{
GraphDB: etcdBackend,
ChanStateDB: etcdBackend,
HeightHintDB: etcdBackend,
MacaroonDB: etcdMacaroonBackend,
DecayedLogDB: etcdDecayedLogBackend,
TowerClientDB: etcdTowerClientBackend,
TowerServerDB: etcdTowerServerBackend,
// The wallet loader will attempt to use/create the
// wallet in the replicated remote DB if we're running
// in a clustered environment. This will ensure that all
// members of the cluster have access to the same wallet
// state.
WalletDB: btcwallet.LoaderWithExternalWalletDB(
etcdWalletBackend,
),
Remote: true,
CloseFuncs: closeFuncs,
}, nil
case PostgresBackend:
// Convert the sqldb PostgresConfig to a kvdb postgres.Config.
// This is a temporary measure until we migrate all kvdb SQL
// users to native SQL.
postgresConfig := GetPostgresConfigKVDB(db.Postgres)
postgresBackend, err := kvdb.Open(
kvdb.PostgresBackendName, ctx,
postgresConfig, NSChannelDB,
)
if err != nil {
return nil, fmt.Errorf("error opening postgres graph "+
"DB: %v", err)
}
closeFuncs[NSChannelDB] = postgresBackend.Close
postgresMacaroonBackend, err := kvdb.Open(
kvdb.PostgresBackendName, ctx,
postgresConfig, NSMacaroonDB,
)
if err != nil {
return nil, fmt.Errorf("error opening postgres "+
"macaroon DB: %v", err)
}
closeFuncs[NSMacaroonDB] = postgresMacaroonBackend.Close
postgresDecayedLogBackend, err := kvdb.Open(
kvdb.PostgresBackendName, ctx,
postgresConfig, NSDecayedLogDB,
)
if err != nil {
return nil, fmt.Errorf("error opening postgres "+
"decayed log DB: %v", err)
}
closeFuncs[NSDecayedLogDB] = postgresDecayedLogBackend.Close
postgresTowerClientBackend, err := kvdb.Open(
kvdb.PostgresBackendName, ctx,
postgresConfig, NSTowerClientDB,
)
if err != nil {
return nil, fmt.Errorf("error opening postgres tower "+
"client DB: %v", err)
}
closeFuncs[NSTowerClientDB] = postgresTowerClientBackend.Close
postgresTowerServerBackend, err := kvdb.Open(
kvdb.PostgresBackendName, ctx,
postgresConfig, NSTowerServerDB,
)
if err != nil {
return nil, fmt.Errorf("error opening postgres tower "+
"server DB: %v", err)
}
closeFuncs[NSTowerServerDB] = postgresTowerServerBackend.Close
postgresWalletBackend, err := kvdb.Open(
kvdb.PostgresBackendName, ctx,
postgresConfig, NSWalletDB,
)
if err != nil {
return nil, fmt.Errorf("error opening postgres macaroon "+
"DB: %v", err)
}
closeFuncs[NSWalletDB] = postgresWalletBackend.Close
var nativeSQLStore *sqldb.BaseDB
if db.UseNativeSQL {
nativePostgresStore, err := sqldb.NewPostgresStore(
db.Postgres,
)
if err != nil {
return nil, fmt.Errorf("error opening "+
"native postgres store: %v", err)
}
nativeSQLStore = nativePostgresStore.BaseDB
closeFuncs[PostgresBackend] = nativePostgresStore.Close
}
// Warn if the user is trying to switch over to a Postgres DB
// while there is a wallet or channel bbolt DB still present.
warnExistingBoltDBs(
logger, "postgres", walletDBPath, WalletDBName,
)
warnExistingBoltDBs(
logger, "postgres", chanDBPath, ChannelDBName,
)
returnEarly = false
return &DatabaseBackends{
GraphDB: postgresBackend,
ChanStateDB: postgresBackend,
HeightHintDB: postgresBackend,
MacaroonDB: postgresMacaroonBackend,
DecayedLogDB: postgresDecayedLogBackend,
TowerClientDB: postgresTowerClientBackend,
TowerServerDB: postgresTowerServerBackend,
// The wallet loader will attempt to use/create the
// wallet in the replicated remote DB if we're running
// in a clustered environment. This will ensure that all
// members of the cluster have access to the same wallet
// state.
WalletDB: btcwallet.LoaderWithExternalWalletDB(
postgresWalletBackend,
),
NativeSQLStore: nativeSQLStore,
Remote: true,
CloseFuncs: closeFuncs,
}, nil
case SqliteBackend:
// Convert the sqldb SqliteConfig to a kvdb sqlite.Config.
// This is a temporary measure until we migrate all kvdb SQL
// users to native SQL.
sqliteConfig := GetSqliteConfigKVDB(db.Sqlite)
// Note that for sqlite, we put kv tables for the channel.db,
// wtclient.db and sphinxreplay.db all in the channel.sqlite db.
// The tables for wallet.db and macaroon.db are in the
// chain.sqlite db and watchtower.db tables are in the
// watchtower.sqlite db. The reason for the multiple sqlite dbs
// is twofold. The first reason is that it maintains the file
// structure that users are used to. The second reason is the
// fact that sqlite only supports one writer at a time which
// would cause deadlocks in the code due to the wallet db often
// being accessed during a write to another db.
sqliteBackend, err := kvdb.Open(
kvdb.SqliteBackendName, ctx, sqliteConfig, chanDBPath,
SqliteChannelDBName, NSChannelDB,
)
if err != nil {
return nil, fmt.Errorf("error opening sqlite graph "+
"DB: %v", err)
}
closeFuncs[NSChannelDB] = sqliteBackend.Close
sqliteMacaroonBackend, err := kvdb.Open(
kvdb.SqliteBackendName, ctx, sqliteConfig, walletDBPath,
SqliteChainDBName, NSMacaroonDB,
)
if err != nil {
return nil, fmt.Errorf("error opening sqlite "+
"macaroon DB: %v", err)
}
closeFuncs[NSMacaroonDB] = sqliteMacaroonBackend.Close
sqliteDecayedLogBackend, err := kvdb.Open(
kvdb.SqliteBackendName, ctx, sqliteConfig, chanDBPath,
SqliteChannelDBName, NSDecayedLogDB,
)
if err != nil {
return nil, fmt.Errorf("error opening sqlite decayed "+
"log DB: %v", err)
}
closeFuncs[NSDecayedLogDB] = sqliteDecayedLogBackend.Close
sqliteTowerClientBackend, err := kvdb.Open(
kvdb.SqliteBackendName, ctx, sqliteConfig, chanDBPath,
SqliteChannelDBName, NSTowerClientDB,
)
if err != nil {
return nil, fmt.Errorf("error opening sqlite tower "+
"client DB: %v", err)
}
closeFuncs[NSTowerClientDB] = sqliteTowerClientBackend.Close
sqliteTowerServerBackend, err := kvdb.Open(
kvdb.SqliteBackendName, ctx, sqliteConfig,
towerServerDBPath, SqliteTowerDBName, NSTowerServerDB,
)
if err != nil {
return nil, fmt.Errorf("error opening sqlite tower "+
"server DB: %v", err)
}
closeFuncs[NSTowerServerDB] = sqliteTowerServerBackend.Close
sqliteWalletBackend, err := kvdb.Open(
kvdb.SqliteBackendName, ctx, sqliteConfig, walletDBPath,
SqliteChainDBName, NSWalletDB,
)
if err != nil {
return nil, fmt.Errorf("error opening sqlite macaroon "+
"DB: %v", err)
}
closeFuncs[NSWalletDB] = sqliteWalletBackend.Close
var nativeSQLStore *sqldb.BaseDB
if db.UseNativeSQL {
nativeSQLiteStore, err := sqldb.NewSqliteStore(
db.Sqlite,
path.Join(chanDBPath, SqliteNativeDBName),
)
if err != nil {
return nil, fmt.Errorf("error opening "+
"native SQLite store: %v", err)
}
nativeSQLStore = nativeSQLiteStore.BaseDB
closeFuncs[SqliteBackend] = nativeSQLiteStore.Close
}
// Warn if the user is trying to switch over to a sqlite DB
// while there is a wallet or channel bbolt DB still present.
warnExistingBoltDBs(
logger, "sqlite", walletDBPath, WalletDBName,
)
warnExistingBoltDBs(
logger, "sqlite", chanDBPath, ChannelDBName,
)
returnEarly = false
return &DatabaseBackends{
GraphDB: sqliteBackend,
ChanStateDB: sqliteBackend,
HeightHintDB: sqliteBackend,
MacaroonDB: sqliteMacaroonBackend,
DecayedLogDB: sqliteDecayedLogBackend,
TowerClientDB: sqliteTowerClientBackend,
TowerServerDB: sqliteTowerServerBackend,
// The wallet loader will attempt to use/create the
// wallet in the replicated remote DB if we're running
// in a clustered environment. This will ensure that all
// members of the cluster have access to the same wallet
// state.
WalletDB: btcwallet.LoaderWithExternalWalletDB(
sqliteWalletBackend,
),
NativeSQLStore: nativeSQLStore,
CloseFuncs: closeFuncs,
}, nil
}
// We're using all bbolt based databases by default.
boltBackend, err := kvdb.GetBoltBackend(&kvdb.BoltBackendConfig{
DBPath: chanDBPath,
DBFileName: ChannelDBName,
DBTimeout: db.Bolt.DBTimeout,
NoFreelistSync: db.Bolt.NoFreelistSync,
AutoCompact: db.Bolt.AutoCompact,
AutoCompactMinAge: db.Bolt.AutoCompactMinAge,
})
if err != nil {
return nil, fmt.Errorf("error opening bolt DB: %w", err)
}
closeFuncs[NSChannelDB] = boltBackend.Close
macaroonBackend, err := kvdb.GetBoltBackend(&kvdb.BoltBackendConfig{
DBPath: walletDBPath,
DBFileName: MacaroonDBName,
DBTimeout: db.Bolt.DBTimeout,
NoFreelistSync: db.Bolt.NoFreelistSync,
AutoCompact: db.Bolt.AutoCompact,
AutoCompactMinAge: db.Bolt.AutoCompactMinAge,
})
if err != nil {
return nil, fmt.Errorf("error opening macaroon DB: %w", err)
}
closeFuncs[NSMacaroonDB] = macaroonBackend.Close
decayedLogBackend, err := kvdb.GetBoltBackend(&kvdb.BoltBackendConfig{
DBPath: chanDBPath,
DBFileName: DecayedLogDbName,
DBTimeout: db.Bolt.DBTimeout,
NoFreelistSync: db.Bolt.NoFreelistSync,
AutoCompact: db.Bolt.AutoCompact,
AutoCompactMinAge: db.Bolt.AutoCompactMinAge,
})
if err != nil {
return nil, fmt.Errorf("error opening decayed log DB: %w", err)
}
closeFuncs[NSDecayedLogDB] = decayedLogBackend.Close
// The tower client is optional and might not be enabled by the user. We
// handle it being nil properly in the main server.
var towerClientBackend kvdb.Backend
if towerClientEnabled {
towerClientBackend, err = kvdb.GetBoltBackend(
&kvdb.BoltBackendConfig{
DBPath: chanDBPath,
DBFileName: TowerClientDBName,
DBTimeout: db.Bolt.DBTimeout,
NoFreelistSync: db.Bolt.NoFreelistSync,
AutoCompact: db.Bolt.AutoCompact,
AutoCompactMinAge: db.Bolt.AutoCompactMinAge,
},
)
if err != nil {
return nil, fmt.Errorf("error opening tower client "+
"DB: %v", err)
}
closeFuncs[NSTowerClientDB] = towerClientBackend.Close
}
// The tower server is optional and might not be enabled by the user. We
// handle it being nil properly in the main server.
var towerServerBackend kvdb.Backend
if towerServerEnabled {
towerServerBackend, err = kvdb.GetBoltBackend(
&kvdb.BoltBackendConfig{
DBPath: towerServerDBPath,
DBFileName: TowerServerDBName,
DBTimeout: db.Bolt.DBTimeout,
NoFreelistSync: db.Bolt.NoFreelistSync,
AutoCompact: db.Bolt.AutoCompact,
AutoCompactMinAge: db.Bolt.AutoCompactMinAge,
},
)
if err != nil {
return nil, fmt.Errorf("error opening tower server "+
"DB: %v", err)
}
closeFuncs[NSTowerServerDB] = towerServerBackend.Close
}
returnEarly = false
return &DatabaseBackends{
GraphDB: boltBackend,
ChanStateDB: boltBackend,
HeightHintDB: boltBackend,
MacaroonDB: macaroonBackend,
DecayedLogDB: decayedLogBackend,
TowerClientDB: towerClientBackend,
TowerServerDB: towerServerBackend,
// When "running locally", LND will use the bbolt wallet.db to
// store the wallet located in the chain data dir, parametrized
// by the active network. The wallet loader has its own cleanup
// method so we don't need to add anything to our map (in fact
// nothing is opened just yet).
WalletDB: btcwallet.LoaderWithLocalWalletDB(
walletDBPath, db.Bolt.NoFreelistSync, db.Bolt.DBTimeout,
),
CloseFuncs: closeFuncs,
}, nil
}
// warnExistingBoltDBs checks if there is an existing bbolt database in the
// given location and logs a warning if so.
func warnExistingBoltDBs(log btclog.Logger, dbType, dir, fileName string) {
if lnrpc.FileExists(filepath.Join(dir, fileName)) {
log.Warnf("Found existing bbolt database file in %s/%s while "+
"using database type %s. Existing data will NOT be "+
"migrated to %s automatically!", dir, fileName, dbType,
dbType)
}
}
// Compile-time constraint to ensure Workers implements the Validator interface.
var _ Validator = (*DB)(nil)