diff --git a/client.go b/client.go index 34b55c9..70309a6 100644 --- a/client.go +++ b/client.go @@ -121,11 +121,9 @@ type ClientConfig struct { } // NewClient returns a new instance to initiate swaps with. -func NewClient(dbDir string, cfg *ClientConfig) (*Client, func(), error) { - store, err := loopdb.NewBoltSwapStore(dbDir, cfg.Lnd.ChainParams) - if err != nil { - return nil, nil, err - } +func NewClient(dbDir string, loopDB loopdb.SwapStore, + cfg *ClientConfig) (*Client, func(), error) { + lsatStore, err := lsat.NewFileStore(dbDir) if err != nil { return nil, nil, err @@ -139,7 +137,7 @@ func NewClient(dbDir string, cfg *ClientConfig) (*Client, func(), error) { config := &clientConfig{ LndServices: cfg.Lnd, Server: swapServerClient, - Store: store, + Store: loopDB, LsatStore: lsatStore, CreateExpiryTimer: func(d time.Duration) <-chan time.Time { return time.NewTimer(d).C @@ -153,7 +151,7 @@ func NewClient(dbDir string, cfg *ClientConfig) (*Client, func(), error) { executor := newExecutor(&executorConfig{ lnd: cfg.Lnd, - store: store, + store: loopDB, sweeper: sweeper, createExpiryTimer: config.CreateExpiryTimer, loopOutMaxParts: cfg.LoopOutMaxParts, @@ -185,7 +183,7 @@ func NewClient(dbDir string, cfg *ClientConfig) (*Client, func(), error) { cleanup := func() { swapServerClient.stop() - store.Close() + loopDB.Close() } return client, cleanup, nil diff --git a/loopd/config.go b/loopd/config.go index 991040f..7ed020b 100644 --- a/loopd/config.go +++ b/loopd/config.go @@ -11,6 +11,7 @@ import ( "github.com/btcsuite/btcd/btcutil" "github.com/lightninglabs/aperture/lsat" + "github.com/lightninglabs/loop/loopdb" "github.com/lightningnetwork/lnd/cert" "github.com/lightningnetwork/lnd/lncfg" "github.com/lightningnetwork/lnd/lnrpc" @@ -28,11 +29,19 @@ var ( defaultLogDirname = "logs" defaultLogFilename = "loopd.log" + defaultSqliteDatabaseFileName = "loop_sqlite.db" + defaultLogDir = filepath.Join(LoopDirBase, defaultLogDirname) defaultConfigFile = filepath.Join( LoopDirBase, DefaultNetwork, defaultConfigFilename, ) + // defaultSqliteDatabasePath is the default path under which we store + // the SQLite database file. + defaultSqliteDatabasePath = filepath.Join( + LoopDirBase, DefaultNetwork, defaultSqliteDatabaseFileName, + ) + defaultMaxLogFiles = 3 defaultMaxLogFileSize = 10 defaultLoopOutMaxParts = uint32(5) @@ -47,6 +56,12 @@ var ( // TLS key. DefaultTLSKeyFilename = "tls.key" + // DatabaseBackendSqlite is the name of the SQLite database backend. + DatabaseBackendSqlite = "sqlite" + + // DatabaseBackendPostgres is the name of the Postgres database backend. + DatabaseBackendPostgres = "postgres" + defaultSelfSignedOrganization = "loop autogenerated cert" // defaultLndMacaroon is the default macaroon file we use if the old, @@ -127,6 +142,10 @@ type Config struct { ConfigFile string `long:"configfile" description:"Path to configuration file."` DataDir string `long:"datadir" description:"Directory for loopdb."` + DatabaseBackend string `long:"databasebackend" description:"The database backend to use for storing all asset related data." choice:"sqlite" choice:"postgres"` + Sqlite *loopdb.SqliteConfig `group:"sqlite" namespace:"sqlite"` + Postgres *loopdb.PostgresConfig `group:"postgres" namespace:"postgres"` + TLSCertPath string `long:"tlscertpath" description:"Path to write the TLS certificate for loop's RPC and REST services."` TLSKeyPath string `long:"tlskeypath" description:"Path to write the TLS private key for loop's RPC and REST services."` TLSExtraIPs []string `long:"tlsextraip" description:"Adds an extra IP to the generated certificate."` @@ -172,9 +191,13 @@ func DefaultConfig() Config { Server: &loopServerConfig{ NoTLS: false, }, - LoopDir: LoopDirBase, - ConfigFile: defaultConfigFile, - DataDir: LoopDirBase, + LoopDir: LoopDirBase, + ConfigFile: defaultConfigFile, + DataDir: LoopDirBase, + DatabaseBackend: DatabaseBackendSqlite, + Sqlite: &loopdb.SqliteConfig{ + DatabaseFileName: defaultSqliteDatabasePath, + }, LogDir: defaultLogDir, MaxLogFiles: defaultMaxLogFiles, MaxLogFileSize: defaultMaxLogFileSize, @@ -276,6 +299,14 @@ func Validate(cfg *Config) error { ) } + // We'll also update the database file location as well, if it wasn't + // set. + if cfg.Sqlite.DatabaseFileName == defaultSqliteDatabasePath { + cfg.Sqlite.DatabaseFileName = filepath.Join( + cfg.DataDir, defaultSqliteDatabaseFileName, + ) + } + // If either of these directories do not exist, create them. if err := os.MkdirAll(cfg.DataDir, os.ModePerm); err != nil { return err diff --git a/loopd/utils.go b/loopd/utils.go index cb0c267..46457c2 100644 --- a/loopd/utils.go +++ b/loopd/utils.go @@ -2,34 +2,67 @@ package loopd import ( "context" + "fmt" "github.com/btcsuite/btcd/btcutil" "github.com/lightninglabs/lndclient" "github.com/lightninglabs/loop" "github.com/lightninglabs/loop/liquidity" + "github.com/lightninglabs/loop/loopdb" "github.com/lightninglabs/loop/swap" "github.com/lightningnetwork/lnd/clock" "github.com/lightningnetwork/lnd/ticker" ) // getClient returns an instance of the swap client. -func getClient(config *Config, lnd *lndclient.LndServices) (*loop.Client, +func getClient(cfg *Config, lnd *lndclient.LndServices) (*loop.Client, func(), error) { clientConfig := &loop.ClientConfig{ - ServerAddress: config.Server.Host, - ProxyAddress: config.Server.Proxy, - SwapServerNoTLS: config.Server.NoTLS, - TLSPathServer: config.Server.TLSPath, + ServerAddress: cfg.Server.Host, + ProxyAddress: cfg.Server.Proxy, + SwapServerNoTLS: cfg.Server.NoTLS, + TLSPathServer: cfg.Server.TLSPath, Lnd: lnd, - MaxLsatCost: btcutil.Amount(config.MaxLSATCost), - MaxLsatFee: btcutil.Amount(config.MaxLSATFee), - LoopOutMaxParts: config.LoopOutMaxParts, - TotalPaymentTimeout: config.TotalPaymentTimeout, - MaxPaymentRetries: config.MaxPaymentRetries, + MaxLsatCost: btcutil.Amount(cfg.MaxLSATCost), + MaxLsatFee: btcutil.Amount(cfg.MaxLSATFee), + LoopOutMaxParts: cfg.LoopOutMaxParts, + TotalPaymentTimeout: cfg.TotalPaymentTimeout, + MaxPaymentRetries: cfg.MaxPaymentRetries, } - swapClient, cleanUp, err := loop.NewClient(config.DataDir, clientConfig) + // Now that we know where the database will live, we'll go ahead and + // open up the default implementation of it. + var ( + db loopdb.SwapStore + err error + ) + switch cfg.DatabaseBackend { + case DatabaseBackendSqlite: + log.Infof("Opening sqlite3 database at: %v", + cfg.Sqlite.DatabaseFileName) + db, err = loopdb.NewSqliteStore( + cfg.Sqlite, clientConfig.Lnd.ChainParams, + ) + + case DatabaseBackendPostgres: + log.Infof("Opening postgres database at: %v", + cfg.Postgres.DSN(true)) + db, err = loopdb.NewPostgresStore( + cfg.Postgres, clientConfig.Lnd.ChainParams, + ) + + default: + return nil, nil, fmt.Errorf("unknown database backend: %s", + cfg.DatabaseBackend) + } + if err != nil { + return nil, nil, fmt.Errorf("unable to open database: %v", err) + } + + swapClient, cleanUp, err := loop.NewClient( + cfg.DataDir, db, clientConfig, + ) if err != nil { return nil, nil, err }