mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-01-19 05:45:21 +01:00
multi: make watchtower client/server DBs remote compatible
The final database that needs to be made remote compatible is the watchtower server and client database. They are handled a bit differently because both of them are not always active, only when specifically turned on in the config.
This commit is contained in:
parent
1e27f491c7
commit
75531455da
67
lncfg/db.go
67
lncfg/db.go
@ -13,6 +13,8 @@ const (
|
|||||||
channelDBName = "channel.db"
|
channelDBName = "channel.db"
|
||||||
macaroonDBName = "macaroons.db"
|
macaroonDBName = "macaroons.db"
|
||||||
decayedLogDbName = "sphinxreplay.db"
|
decayedLogDbName = "sphinxreplay.db"
|
||||||
|
towerClientDBName = "wtclient.db"
|
||||||
|
towerServerDBName = "watchtower.db"
|
||||||
|
|
||||||
BoltBackend = "bolt"
|
BoltBackend = "bolt"
|
||||||
EtcdBackend = "etcd"
|
EtcdBackend = "etcd"
|
||||||
@ -28,6 +30,14 @@ const (
|
|||||||
// NSDecayedLogDB is the namespace name that we use for the sphinx
|
// NSDecayedLogDB is the namespace name that we use for the sphinx
|
||||||
// replay a.k.a. decayed log DB.
|
// replay a.k.a. decayed log DB.
|
||||||
NSDecayedLogDB = "decayedlogdb"
|
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"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DB holds database configuration for LND.
|
// DB holds database configuration for LND.
|
||||||
@ -117,6 +127,14 @@ type DatabaseBackends struct {
|
|||||||
// data.
|
// data.
|
||||||
DecayedLogDB kvdb.Backend
|
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
|
||||||
|
|
||||||
// Remote indicates whether the database backends are remote, possibly
|
// Remote indicates whether the database backends are remote, possibly
|
||||||
// replicated instances or local bbolt backed databases.
|
// replicated instances or local bbolt backed databases.
|
||||||
Remote bool
|
Remote bool
|
||||||
@ -128,7 +146,8 @@ type DatabaseBackends struct {
|
|||||||
|
|
||||||
// GetBackends returns a set of kvdb.Backends as set in the DB config.
|
// GetBackends returns a set of kvdb.Backends as set in the DB config.
|
||||||
func (db *DB) GetBackends(ctx context.Context, chanDBPath,
|
func (db *DB) GetBackends(ctx context.Context, chanDBPath,
|
||||||
walletDBPath string) (*DatabaseBackends, error) {
|
walletDBPath, towerServerDBPath string, towerClientEnabled,
|
||||||
|
towerServerEnabled bool) (*DatabaseBackends, error) {
|
||||||
|
|
||||||
// We keep track of all the kvdb backends we actually open and return a
|
// 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
|
// reference to their close function so they can be cleaned up properly
|
||||||
@ -164,6 +183,8 @@ func (db *DB) GetBackends(ctx context.Context, chanDBPath,
|
|||||||
HeightHintDB: etcdBackend,
|
HeightHintDB: etcdBackend,
|
||||||
MacaroonDB: etcdBackend,
|
MacaroonDB: etcdBackend,
|
||||||
DecayedLogDB: etcdBackend,
|
DecayedLogDB: etcdBackend,
|
||||||
|
TowerClientDB: etcdBackend,
|
||||||
|
TowerServerDB: etcdBackend,
|
||||||
Remote: true,
|
Remote: true,
|
||||||
CloseFuncs: closeFuncs,
|
CloseFuncs: closeFuncs,
|
||||||
}, nil
|
}, nil
|
||||||
@ -209,6 +230,48 @@ func (db *DB) GetBackends(ctx context.Context, chanDBPath,
|
|||||||
}
|
}
|
||||||
closeFuncs[NSDecayedLogDB] = decayedLogBackend.Close
|
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.SyncFreelist,
|
||||||
|
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.SyncFreelist,
|
||||||
|
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
|
returnEarly = false
|
||||||
return &DatabaseBackends{
|
return &DatabaseBackends{
|
||||||
GraphDB: boltBackend,
|
GraphDB: boltBackend,
|
||||||
@ -216,6 +279,8 @@ func (db *DB) GetBackends(ctx context.Context, chanDBPath,
|
|||||||
HeightHintDB: boltBackend,
|
HeightHintDB: boltBackend,
|
||||||
MacaroonDB: macaroonBackend,
|
MacaroonDB: macaroonBackend,
|
||||||
DecayedLogDB: decayedLogBackend,
|
DecayedLogDB: decayedLogBackend,
|
||||||
|
TowerClientDB: towerClientBackend,
|
||||||
|
TowerServerDB: towerServerBackend,
|
||||||
CloseFuncs: closeFuncs,
|
CloseFuncs: closeFuncs,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
81
lnd.go
81
lnd.go
@ -55,6 +55,7 @@ import (
|
|||||||
"github.com/lightningnetwork/lnd/tor"
|
"github.com/lightningnetwork/lnd/tor"
|
||||||
"github.com/lightningnetwork/lnd/walletunlocker"
|
"github.com/lightningnetwork/lnd/walletunlocker"
|
||||||
"github.com/lightningnetwork/lnd/watchtower"
|
"github.com/lightningnetwork/lnd/watchtower"
|
||||||
|
"github.com/lightningnetwork/lnd/watchtower/wtclient"
|
||||||
"github.com/lightningnetwork/lnd/watchtower/wtdb"
|
"github.com/lightningnetwork/lnd/watchtower/wtdb"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -769,23 +770,6 @@ func Main(cfg *Config, lisCfg ListenerCfg, interceptor signal.Interceptor) error
|
|||||||
"is proxying over Tor as well", cfg.Tor.StreamIsolation)
|
"is proxying over Tor as well", cfg.Tor.StreamIsolation)
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the watchtower client should be active, open the client database.
|
|
||||||
// This is done here so that Close always executes when lndMain returns.
|
|
||||||
var towerClientDB *wtdb.ClientDB
|
|
||||||
if cfg.WtClient.Active {
|
|
||||||
var err error
|
|
||||||
towerClientDB, err = wtdb.OpenClientDB(
|
|
||||||
cfg.graphDatabaseDir(), cfg.DB.Bolt.DBTimeout,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
err := fmt.Errorf("unable to open watchtower client "+
|
|
||||||
"database: %v", err)
|
|
||||||
ltndLog.Error(err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer towerClientDB.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
// If tor is active and either v2 or v3 onion services have been specified,
|
// If tor is active and either v2 or v3 onion services have been specified,
|
||||||
// make a tor controller and pass it into both the watchtower server and
|
// make a tor controller and pass it into both the watchtower server and
|
||||||
// the regular lnd server.
|
// the regular lnd server.
|
||||||
@ -810,24 +794,6 @@ func Main(cfg *Config, lisCfg ListenerCfg, interceptor signal.Interceptor) error
|
|||||||
|
|
||||||
var tower *watchtower.Standalone
|
var tower *watchtower.Standalone
|
||||||
if cfg.Watchtower.Active {
|
if cfg.Watchtower.Active {
|
||||||
// Segment the watchtower directory by chain and network.
|
|
||||||
towerDBDir := filepath.Join(
|
|
||||||
cfg.Watchtower.TowerDir,
|
|
||||||
cfg.registeredChains.PrimaryChain().String(),
|
|
||||||
lncfg.NormalizeNetwork(cfg.ActiveNetParams.Name),
|
|
||||||
)
|
|
||||||
|
|
||||||
towerDB, err := wtdb.OpenTowerDB(
|
|
||||||
towerDBDir, cfg.DB.Bolt.DBTimeout,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
err := fmt.Errorf("unable to open watchtower "+
|
|
||||||
"database: %v", err)
|
|
||||||
ltndLog.Error(err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer towerDB.Close()
|
|
||||||
|
|
||||||
towerKeyDesc, err := activeChainControl.KeyRing.DeriveKey(
|
towerKeyDesc, err := activeChainControl.KeyRing.DeriveKey(
|
||||||
keychain.KeyLocator{
|
keychain.KeyLocator{
|
||||||
Family: keychain.KeyFamilyTowerID,
|
Family: keychain.KeyFamilyTowerID,
|
||||||
@ -842,7 +808,7 @@ func Main(cfg *Config, lisCfg ListenerCfg, interceptor signal.Interceptor) error
|
|||||||
|
|
||||||
wtCfg := &watchtower.Config{
|
wtCfg := &watchtower.Config{
|
||||||
BlockFetcher: activeChainControl.ChainIO,
|
BlockFetcher: activeChainControl.ChainIO,
|
||||||
DB: towerDB,
|
DB: dbs.towerServerDB,
|
||||||
EpochRegistrar: activeChainControl.ChainNotifier,
|
EpochRegistrar: activeChainControl.ChainNotifier,
|
||||||
Net: cfg.net,
|
Net: cfg.net,
|
||||||
NewAddress: func() (btcutil.Address, error) {
|
NewAddress: func() (btcutil.Address, error) {
|
||||||
@ -894,9 +860,8 @@ func Main(cfg *Config, lisCfg ListenerCfg, interceptor signal.Interceptor) error
|
|||||||
// Set up the core server which will listen for incoming peer
|
// Set up the core server which will listen for incoming peer
|
||||||
// connections.
|
// connections.
|
||||||
server, err := newServer(
|
server, err := newServer(
|
||||||
cfg, cfg.Listeners, dbs, towerClientDB,
|
cfg, cfg.Listeners, dbs, activeChainControl, &idKeyDesc,
|
||||||
activeChainControl, &idKeyDesc, walletInitParams.ChansToRestore,
|
walletInitParams.ChansToRestore, chainedAcceptor, torController,
|
||||||
chainedAcceptor, torController,
|
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err := fmt.Errorf("unable to create server: %v", err)
|
err := fmt.Errorf("unable to create server: %v", err)
|
||||||
@ -1617,6 +1582,8 @@ type databaseInstances struct {
|
|||||||
heightHintDB kvdb.Backend
|
heightHintDB kvdb.Backend
|
||||||
macaroonDB kvdb.Backend
|
macaroonDB kvdb.Backend
|
||||||
decayedLogDB kvdb.Backend
|
decayedLogDB kvdb.Backend
|
||||||
|
towerClientDB wtclient.DB
|
||||||
|
towerServerDB watchtower.DB
|
||||||
}
|
}
|
||||||
|
|
||||||
// initializeDatabases extracts the current databases that we'll use for normal
|
// initializeDatabases extracts the current databases that we'll use for normal
|
||||||
@ -1637,7 +1604,11 @@ func initializeDatabases(ctx context.Context,
|
|||||||
startOpenTime := time.Now()
|
startOpenTime := time.Now()
|
||||||
|
|
||||||
databaseBackends, err := cfg.DB.GetBackends(
|
databaseBackends, err := cfg.DB.GetBackends(
|
||||||
ctx, cfg.graphDatabaseDir(), cfg.networkDir,
|
ctx, cfg.graphDatabaseDir(), cfg.networkDir, filepath.Join(
|
||||||
|
cfg.Watchtower.TowerDir,
|
||||||
|
cfg.registeredChains.PrimaryChain().String(),
|
||||||
|
lncfg.NormalizeNetwork(cfg.ActiveNetParams.Name),
|
||||||
|
), cfg.WtClient.Active, cfg.Watchtower.Active,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, fmt.Errorf("unable to obtain database "+
|
return nil, nil, fmt.Errorf("unable to obtain database "+
|
||||||
@ -1709,6 +1680,36 @@ func initializeDatabases(ctx context.Context,
|
|||||||
// using the same struct (and DB backend) instance.
|
// using the same struct (and DB backend) instance.
|
||||||
dbs.chanStateDB = dbs.graphDB
|
dbs.chanStateDB = dbs.graphDB
|
||||||
|
|
||||||
|
// Wrap the watchtower client DB and make sure we clean up.
|
||||||
|
if cfg.WtClient.Active {
|
||||||
|
dbs.towerClientDB, err = wtdb.OpenClientDB(
|
||||||
|
databaseBackends.TowerClientDB,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
cleanUp()
|
||||||
|
|
||||||
|
err := fmt.Errorf("unable to open %s database: %v",
|
||||||
|
lncfg.NSTowerClientDB, err)
|
||||||
|
ltndLog.Error(err)
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wrap the watchtower server DB and make sure we clean up.
|
||||||
|
if cfg.Watchtower.Active {
|
||||||
|
dbs.towerServerDB, err = wtdb.OpenTowerDB(
|
||||||
|
databaseBackends.TowerServerDB,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
cleanUp()
|
||||||
|
|
||||||
|
err := fmt.Errorf("unable to open %s database: %v",
|
||||||
|
lncfg.NSTowerServerDB, err)
|
||||||
|
ltndLog.Error(err)
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
openTime := time.Since(startOpenTime)
|
openTime := time.Since(startOpenTime)
|
||||||
ltndLog.Infof("Database(s) now open (time_to_open=%v)!", openTime)
|
ltndLog.Infof("Database(s) now open (time_to_open=%v)!", openTime)
|
||||||
|
|
||||||
|
@ -352,8 +352,7 @@ func noiseDial(idKey keychain.SingleKeyECDH,
|
|||||||
// newServer creates a new instance of the server which is to listen using the
|
// newServer creates a new instance of the server which is to listen using the
|
||||||
// passed listener address.
|
// passed listener address.
|
||||||
func newServer(cfg *Config, listenAddrs []net.Addr,
|
func newServer(cfg *Config, listenAddrs []net.Addr,
|
||||||
dbs *databaseInstances,
|
dbs *databaseInstances, cc *chainreg.ChainControl,
|
||||||
towerClientDB wtclient.DB, cc *chainreg.ChainControl,
|
|
||||||
nodeKeyDesc *keychain.KeyDescriptor,
|
nodeKeyDesc *keychain.KeyDescriptor,
|
||||||
chansToRestore walletunlocker.ChannelsToRecover,
|
chansToRestore walletunlocker.ChannelsToRecover,
|
||||||
chanPredicate chanacceptor.ChannelAcceptor,
|
chanPredicate chanacceptor.ChannelAcceptor,
|
||||||
@ -1306,7 +1305,7 @@ func newServer(cfg *Config, listenAddrs []net.Addr,
|
|||||||
SecretKeyRing: s.cc.KeyRing,
|
SecretKeyRing: s.cc.KeyRing,
|
||||||
Dial: cfg.net.Dial,
|
Dial: cfg.net.Dial,
|
||||||
AuthDial: authDial,
|
AuthDial: authDial,
|
||||||
DB: towerClientDB,
|
DB: dbs.towerClientDB,
|
||||||
Policy: policy,
|
Policy: policy,
|
||||||
ChainHash: *s.cfg.ActiveNetParams.GenesisHash,
|
ChainHash: *s.cfg.ActiveNetParams.GenesisHash,
|
||||||
MinBackoff: 10 * time.Second,
|
MinBackoff: 10 * time.Second,
|
||||||
@ -1329,7 +1328,7 @@ func newServer(cfg *Config, listenAddrs []net.Addr,
|
|||||||
SecretKeyRing: s.cc.KeyRing,
|
SecretKeyRing: s.cc.KeyRing,
|
||||||
Dial: cfg.net.Dial,
|
Dial: cfg.net.Dial,
|
||||||
AuthDial: authDial,
|
AuthDial: authDial,
|
||||||
DB: towerClientDB,
|
DB: dbs.towerClientDB,
|
||||||
Policy: anchorPolicy,
|
Policy: anchorPolicy,
|
||||||
ChainHash: *s.cfg.ActiveNetParams.GenesisHash,
|
ChainHash: *s.cfg.ActiveNetParams.GenesisHash,
|
||||||
MinBackoff: 10 * time.Second,
|
MinBackoff: 10 * time.Second,
|
||||||
|
@ -6,7 +6,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
"net"
|
"net"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/btcec"
|
"github.com/btcsuite/btcd/btcec"
|
||||||
"github.com/lightningnetwork/lnd/kvdb"
|
"github.com/lightningnetwork/lnd/kvdb"
|
||||||
@ -14,11 +13,6 @@ import (
|
|||||||
"github.com/lightningnetwork/lnd/watchtower/blob"
|
"github.com/lightningnetwork/lnd/watchtower/blob"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
|
||||||
// clientDBName is the filename of client database.
|
|
||||||
clientDBName = "wtclient.db"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// cSessionKeyIndexBkt is a top-level bucket storing:
|
// cSessionKeyIndexBkt is a top-level bucket storing:
|
||||||
// tower-id -> reserved-session-key-index (uint32).
|
// tower-id -> reserved-session-key-index (uint32).
|
||||||
@ -116,11 +110,43 @@ var (
|
|||||||
ErrLastTowerAddr = errors.New("cannot remove last tower address")
|
ErrLastTowerAddr = errors.New("cannot remove last tower address")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// NewBoltBackendCreator returns a function that creates a new bbolt backend for
|
||||||
|
// the watchtower database.
|
||||||
|
func NewBoltBackendCreator(active bool, dbPath,
|
||||||
|
dbFileName string) func(boltCfg *kvdb.BoltConfig) (kvdb.Backend, error) {
|
||||||
|
|
||||||
|
// If the watchtower client isn't active, we return a function that
|
||||||
|
// always returns a nil DB to make sure we don't create empty database
|
||||||
|
// files.
|
||||||
|
if !active {
|
||||||
|
return func(_ *kvdb.BoltConfig) (kvdb.Backend, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return func(boltCfg *kvdb.BoltConfig) (kvdb.Backend, error) {
|
||||||
|
cfg := &kvdb.BoltBackendConfig{
|
||||||
|
DBPath: dbPath,
|
||||||
|
DBFileName: dbFileName,
|
||||||
|
NoFreelistSync: !boltCfg.SyncFreelist,
|
||||||
|
AutoCompact: boltCfg.AutoCompact,
|
||||||
|
AutoCompactMinAge: boltCfg.AutoCompactMinAge,
|
||||||
|
DBTimeout: boltCfg.DBTimeout,
|
||||||
|
}
|
||||||
|
|
||||||
|
db, err := kvdb.GetBoltBackend(cfg)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("could not open boltdb: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return db, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ClientDB is single database providing a persistent storage engine for the
|
// ClientDB is single database providing a persistent storage engine for the
|
||||||
// wtclient.
|
// wtclient.
|
||||||
type ClientDB struct {
|
type ClientDB struct {
|
||||||
db kvdb.Backend
|
db kvdb.Backend
|
||||||
dbPath string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// OpenClientDB opens the client database given the path to the database's
|
// OpenClientDB opens the client database given the path to the database's
|
||||||
@ -130,22 +156,19 @@ type ClientDB struct {
|
|||||||
// migrations will be applied before returning. Any attempt to open a database
|
// migrations will be applied before returning. Any attempt to open a database
|
||||||
// with a version number higher that the latest version will fail to prevent
|
// with a version number higher that the latest version will fail to prevent
|
||||||
// accidental reversion.
|
// accidental reversion.
|
||||||
func OpenClientDB(dbPath string, dbTimeout time.Duration) (*ClientDB, error) {
|
func OpenClientDB(db kvdb.Backend) (*ClientDB, error) {
|
||||||
bdb, firstInit, err := createDBIfNotExist(
|
firstInit, err := isFirstInit(db)
|
||||||
dbPath, clientDBName, dbTimeout,
|
|
||||||
)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
clientDB := &ClientDB{
|
clientDB := &ClientDB{
|
||||||
db: bdb,
|
db: db,
|
||||||
dbPath: dbPath,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
err = initOrSyncVersions(clientDB, firstInit, clientDBVersions)
|
err = initOrSyncVersions(clientDB, firstInit, clientDBVersions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
bdb.Close()
|
db.Close()
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -156,7 +179,7 @@ func OpenClientDB(dbPath string, dbTimeout time.Duration) (*ClientDB, error) {
|
|||||||
// missing, this will trigger a ErrUninitializedDB error.
|
// missing, this will trigger a ErrUninitializedDB error.
|
||||||
err = kvdb.Update(clientDB.db, initClientDBBuckets, func() {})
|
err = kvdb.Update(clientDB.db, initClientDBBuckets, func() {})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
bdb.Close()
|
db.Close()
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -771,6 +771,7 @@ func checkAckedUpdates(t *testing.T, session *wtdb.ClientSession,
|
|||||||
// and the mock implementation. This ensures that all databases function
|
// and the mock implementation. This ensures that all databases function
|
||||||
// identically, especially in the negative paths.
|
// identically, especially in the negative paths.
|
||||||
func TestClientDB(t *testing.T) {
|
func TestClientDB(t *testing.T) {
|
||||||
|
dbCfg := &kvdb.BoltConfig{DBTimeout: kvdb.DefaultDBTimeout}
|
||||||
dbs := []struct {
|
dbs := []struct {
|
||||||
name string
|
name string
|
||||||
init clientDBInit
|
init clientDBInit
|
||||||
@ -784,9 +785,15 @@ func TestClientDB(t *testing.T) {
|
|||||||
err)
|
err)
|
||||||
}
|
}
|
||||||
|
|
||||||
db, err := wtdb.OpenClientDB(
|
bdb, err := wtdb.NewBoltBackendCreator(
|
||||||
path, kvdb.DefaultDBTimeout,
|
true, path, "wtclient.db",
|
||||||
)
|
)(dbCfg)
|
||||||
|
if err != nil {
|
||||||
|
os.RemoveAll(path)
|
||||||
|
t.Fatalf("unable to open db: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
db, err := wtdb.OpenClientDB(bdb)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
os.RemoveAll(path)
|
os.RemoveAll(path)
|
||||||
t.Fatalf("unable to open db: %v", err)
|
t.Fatalf("unable to open db: %v", err)
|
||||||
@ -809,18 +816,30 @@ func TestClientDB(t *testing.T) {
|
|||||||
err)
|
err)
|
||||||
}
|
}
|
||||||
|
|
||||||
db, err := wtdb.OpenClientDB(
|
bdb, err := wtdb.NewBoltBackendCreator(
|
||||||
path, kvdb.DefaultDBTimeout,
|
true, path, "wtclient.db",
|
||||||
)
|
)(dbCfg)
|
||||||
|
if err != nil {
|
||||||
|
os.RemoveAll(path)
|
||||||
|
t.Fatalf("unable to open db: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
db, err := wtdb.OpenClientDB(bdb)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
os.RemoveAll(path)
|
os.RemoveAll(path)
|
||||||
t.Fatalf("unable to open db: %v", err)
|
t.Fatalf("unable to open db: %v", err)
|
||||||
}
|
}
|
||||||
db.Close()
|
db.Close()
|
||||||
|
|
||||||
db, err = wtdb.OpenClientDB(
|
bdb, err = wtdb.NewBoltBackendCreator(
|
||||||
path, kvdb.DefaultDBTimeout,
|
true, path, "wtclient.db",
|
||||||
)
|
)(dbCfg)
|
||||||
|
if err != nil {
|
||||||
|
os.RemoveAll(path)
|
||||||
|
t.Fatalf("unable to open db: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
db, err = wtdb.OpenClientDB(bdb)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
os.RemoveAll(path)
|
os.RemoveAll(path)
|
||||||
t.Fatalf("unable to reopen db: %v", err)
|
t.Fatalf("unable to reopen db: %v", err)
|
||||||
|
@ -3,18 +3,10 @@ package wtdb
|
|||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"errors"
|
"errors"
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/lightningnetwork/lnd/kvdb"
|
"github.com/lightningnetwork/lnd/kvdb"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
|
||||||
// dbFilePermission requests read+write access to the db file.
|
|
||||||
dbFilePermission = 0600
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// metadataBkt stores all the meta information concerning the state of
|
// metadataBkt stores all the meta information concerning the state of
|
||||||
// the database.
|
// the database.
|
||||||
@ -35,67 +27,19 @@ var (
|
|||||||
byteOrder = binary.BigEndian
|
byteOrder = binary.BigEndian
|
||||||
)
|
)
|
||||||
|
|
||||||
// fileExists returns true if the file exists, and false otherwise.
|
// isFirstInit returns true if the given database has not yet been initialized,
|
||||||
func fileExists(path string) bool {
|
// e.g. no metadata bucket is present yet.
|
||||||
if _, err := os.Stat(path); err != nil {
|
func isFirstInit(db kvdb.Backend) (bool, error) {
|
||||||
if os.IsNotExist(err) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// createDBIfNotExist opens the boltdb database at dbPath/name, creating one if
|
|
||||||
// one doesn't exist. The boolean returned indicates if the database did not
|
|
||||||
// exist before, or if it has been created but no version metadata exists within
|
|
||||||
// it.
|
|
||||||
func createDBIfNotExist(dbPath, name string,
|
|
||||||
dbTimeout time.Duration) (kvdb.Backend, bool, error) {
|
|
||||||
|
|
||||||
path := filepath.Join(dbPath, name)
|
|
||||||
|
|
||||||
// If the database file doesn't exist, this indicates we much initialize
|
|
||||||
// a fresh database with the latest version.
|
|
||||||
firstInit := !fileExists(path)
|
|
||||||
if firstInit {
|
|
||||||
// Ensure all parent directories are initialized.
|
|
||||||
err := os.MkdirAll(dbPath, 0700)
|
|
||||||
if err != nil {
|
|
||||||
return nil, false, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Specify bbolt freelist options to reduce heap pressure in case the
|
|
||||||
// freelist grows to be very large.
|
|
||||||
bdb, err := kvdb.Create(
|
|
||||||
kvdb.BoltBackendName, path, true, dbTimeout,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return nil, false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the file existed previously, we'll now check to see that the
|
|
||||||
// metadata bucket is properly initialized. It could be the case that
|
|
||||||
// the database was created, but we failed to actually populate any
|
|
||||||
// metadata. If the metadata bucket does not actually exist, we'll
|
|
||||||
// set firstInit to true so that we can treat is initialize the bucket.
|
|
||||||
if !firstInit {
|
|
||||||
var metadataExists bool
|
var metadataExists bool
|
||||||
err = kvdb.View(bdb, func(tx kvdb.RTx) error {
|
err := kvdb.View(db, func(tx kvdb.RTx) error {
|
||||||
metadataExists = tx.ReadBucket(metadataBkt) != nil
|
metadataExists = tx.ReadBucket(metadataBkt) != nil
|
||||||
return nil
|
return nil
|
||||||
}, func() {
|
}, func() {
|
||||||
metadataExists = false
|
metadataExists = false
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if !metadataExists {
|
return !metadataExists, nil
|
||||||
firstInit = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return bdb, firstInit, nil
|
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,6 @@ package wtdb
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"errors"
|
"errors"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||||
"github.com/lightningnetwork/lnd/chainntnfs"
|
"github.com/lightningnetwork/lnd/chainntnfs"
|
||||||
@ -11,11 +10,6 @@ import (
|
|||||||
"github.com/lightningnetwork/lnd/watchtower/blob"
|
"github.com/lightningnetwork/lnd/watchtower/blob"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
|
||||||
// towerDBName is the filename of tower database.
|
|
||||||
towerDBName = "watchtower.db"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// sessionsBkt is a bucket containing all negotiated client sessions.
|
// sessionsBkt is a bucket containing all negotiated client sessions.
|
||||||
// session id -> session
|
// session id -> session
|
||||||
@ -57,7 +51,6 @@ var (
|
|||||||
// wtserver and lookout subsystems.
|
// wtserver and lookout subsystems.
|
||||||
type TowerDB struct {
|
type TowerDB struct {
|
||||||
db kvdb.Backend
|
db kvdb.Backend
|
||||||
dbPath string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// OpenTowerDB opens the tower database given the path to the database's
|
// OpenTowerDB opens the tower database given the path to the database's
|
||||||
@ -67,22 +60,19 @@ type TowerDB struct {
|
|||||||
// migrations will be applied before returning. Any attempt to open a database
|
// migrations will be applied before returning. Any attempt to open a database
|
||||||
// with a version number higher that the latest version will fail to prevent
|
// with a version number higher that the latest version will fail to prevent
|
||||||
// accidental reversion.
|
// accidental reversion.
|
||||||
func OpenTowerDB(dbPath string, dbTimeout time.Duration) (*TowerDB, error) {
|
func OpenTowerDB(db kvdb.Backend) (*TowerDB, error) {
|
||||||
bdb, firstInit, err := createDBIfNotExist(
|
firstInit, err := isFirstInit(db)
|
||||||
dbPath, towerDBName, dbTimeout,
|
|
||||||
)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
towerDB := &TowerDB{
|
towerDB := &TowerDB{
|
||||||
db: bdb,
|
db: db,
|
||||||
dbPath: dbPath,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
err = initOrSyncVersions(towerDB, firstInit, towerDBVersions)
|
err = initOrSyncVersions(towerDB, firstInit, towerDBVersions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
bdb.Close()
|
db.Close()
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,7 +83,7 @@ func OpenTowerDB(dbPath string, dbTimeout time.Duration) (*TowerDB, error) {
|
|||||||
// missing, this will trigger a ErrUninitializedDB error.
|
// missing, this will trigger a ErrUninitializedDB error.
|
||||||
err = kvdb.Update(towerDB.db, initTowerDBBuckets, func() {})
|
err = kvdb.Update(towerDB.db, initTowerDBBuckets, func() {})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
bdb.Close()
|
db.Close()
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -630,6 +630,7 @@ var stateUpdateInvalidBlobSize = stateUpdateTest{
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestTowerDB(t *testing.T) {
|
func TestTowerDB(t *testing.T) {
|
||||||
|
dbCfg := &kvdb.BoltConfig{DBTimeout: kvdb.DefaultDBTimeout}
|
||||||
dbs := []struct {
|
dbs := []struct {
|
||||||
name string
|
name string
|
||||||
init dbInit
|
init dbInit
|
||||||
@ -643,9 +644,15 @@ func TestTowerDB(t *testing.T) {
|
|||||||
err)
|
err)
|
||||||
}
|
}
|
||||||
|
|
||||||
db, err := wtdb.OpenTowerDB(
|
bdb, err := wtdb.NewBoltBackendCreator(
|
||||||
path, kvdb.DefaultDBTimeout,
|
true, path, "watchtower.db",
|
||||||
)
|
)(dbCfg)
|
||||||
|
if err != nil {
|
||||||
|
os.RemoveAll(path)
|
||||||
|
t.Fatalf("unable to open db: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
db, err := wtdb.OpenTowerDB(bdb)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
os.RemoveAll(path)
|
os.RemoveAll(path)
|
||||||
t.Fatalf("unable to open db: %v", err)
|
t.Fatalf("unable to open db: %v", err)
|
||||||
@ -668,9 +675,15 @@ func TestTowerDB(t *testing.T) {
|
|||||||
err)
|
err)
|
||||||
}
|
}
|
||||||
|
|
||||||
db, err := wtdb.OpenTowerDB(
|
bdb, err := wtdb.NewBoltBackendCreator(
|
||||||
path, kvdb.DefaultDBTimeout,
|
true, path, "watchtower.db",
|
||||||
)
|
)(dbCfg)
|
||||||
|
if err != nil {
|
||||||
|
os.RemoveAll(path)
|
||||||
|
t.Fatalf("unable to open db: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
db, err := wtdb.OpenTowerDB(bdb)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
os.RemoveAll(path)
|
os.RemoveAll(path)
|
||||||
t.Fatalf("unable to open db: %v", err)
|
t.Fatalf("unable to open db: %v", err)
|
||||||
@ -680,9 +693,15 @@ func TestTowerDB(t *testing.T) {
|
|||||||
// Open the db again, ensuring we test a
|
// Open the db again, ensuring we test a
|
||||||
// different path during open and that all
|
// different path during open and that all
|
||||||
// buckets remain initialized.
|
// buckets remain initialized.
|
||||||
db, err = wtdb.OpenTowerDB(
|
bdb, err = wtdb.NewBoltBackendCreator(
|
||||||
path, kvdb.DefaultDBTimeout,
|
true, path, "watchtower.db",
|
||||||
)
|
)(dbCfg)
|
||||||
|
if err != nil {
|
||||||
|
os.RemoveAll(path)
|
||||||
|
t.Fatalf("unable to open db: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
db, err = wtdb.OpenTowerDB(bdb)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
os.RemoveAll(path)
|
os.RemoveAll(path)
|
||||||
t.Fatalf("unable to open db: %v", err)
|
t.Fatalf("unable to open db: %v", err)
|
||||||
|
Loading…
Reference in New Issue
Block a user