From e1e740bb9307d5e8607af0c8b657596e025fd01e Mon Sep 17 00:00:00 2001 From: ziggie Date: Fri, 22 Nov 2024 13:06:41 +0100 Subject: [PATCH] multi: add sql backend support --- Makefile | 5 +- cmd/chantools/chanbackup.go | 15 +- cmd/chantools/deletepayments.go | 16 +- cmd/chantools/dropchannelgraph.go | 18 +- cmd/chantools/dropgraphzombies.go | 16 +- cmd/chantools/dumpchannels.go | 15 +- cmd/chantools/forceclose.go | 16 +- cmd/chantools/migratedb.go | 18 +- cmd/chantools/removechannel.go | 18 +- cmd/chantools/rescueclosed.go | 57 ++++--- cmd/chantools/rescuefunding.go | 26 ++- cmd/chantools/root.go | 65 +++++++- go.mod | 16 +- go.sum | 24 +++ lnd/channeldb.go | 267 +++++++++++++++++++++++++++--- 15 files changed, 494 insertions(+), 98 deletions(-) diff --git a/Makefile b/Makefile index 44855b5..143817f 100644 --- a/Makefile +++ b/Makefile @@ -44,6 +44,9 @@ DOCKER_TOOLS = docker run \ TEST_FLAGS = -test.timeout=20m +DEV_TAGS = kvdb_postgres kvdb_sqlite + + UNIT := $(GOLIST) | $(XARGS) env $(GOTEST) $(TEST_FLAGS) LDFLAGS := -X main.Commit=$(shell git describe --tags) RELEASE_LDFLAGS := -s -w -buildid= $(LDFLAGS) @@ -70,7 +73,7 @@ build: install: @$(call print, "Installing chantools.") - $(GOINSTALL) -ldflags "$(LDFLAGS)" ./... + $(GOINSTALL) -tags="$(DEV_TAGS)" -ldflags "$(LDFLAGS)" ./... release: @$(call print, "Creating release of chantools.") diff --git a/cmd/chantools/chanbackup.go b/cmd/chantools/chanbackup.go index 2cfb980..98190c8 100644 --- a/cmd/chantools/chanbackup.go +++ b/cmd/chantools/chanbackup.go @@ -3,6 +3,7 @@ package main import ( "errors" "fmt" + "path/filepath" "github.com/lightninglabs/chantools/lnd" "github.com/lightningnetwork/lnd/chanbackup" @@ -54,11 +55,17 @@ func (c *chanBackupCommand) Execute(_ *cobra.Command, _ []string) error { return errors.New("backup file is required") } - // Check that we have a channel DB. - if c.ChannelDB == "" { - return errors.New("channel DB is required") + var opts []lnd.DBOption + + // In case the channel DB is specified, we get the graph dir from it. + if c.ChannelDB != "" { + graphDir := filepath.Dir(c.ChannelDB) + opts = append(opts, lnd.WithCustomGraphDir(graphDir)) } - db, err := lnd.OpenDB(c.ChannelDB, true) + + dbConfig := GetDBConfig() + + db, err := lnd.OpenChannelDB(dbConfig, chainParams.Name, opts...) if err != nil { return fmt.Errorf("error opening rescue DB: %w", err) } diff --git a/cmd/chantools/deletepayments.go b/cmd/chantools/deletepayments.go index 17b4275..9c497e3 100644 --- a/cmd/chantools/deletepayments.go +++ b/cmd/chantools/deletepayments.go @@ -1,8 +1,8 @@ package main import ( - "errors" "fmt" + "path/filepath" "github.com/lightninglabs/chantools/lnd" "github.com/spf13/cobra" @@ -44,11 +44,17 @@ run lnd ` + lndVersion + ` or later after using this command!'`, } func (c *deletePaymentsCommand) Execute(_ *cobra.Command, _ []string) error { - // Check that we have a channel DB. - if c.ChannelDB == "" { - return errors.New("channel DB is required") + var opts []lnd.DBOption + + // In case the channel DB is specified, we get the graph dir from it. + if c.ChannelDB != "" { + graphDir := filepath.Dir(c.ChannelDB) + opts = append(opts, lnd.WithCustomGraphDir(graphDir)) } - db, err := lnd.OpenDB(c.ChannelDB, false) + + dbConfig := GetDBConfig() + + db, err := lnd.OpenChannelDB(dbConfig, chainParams.Name, opts...) if err != nil { return fmt.Errorf("error opening rescue DB: %w", err) } diff --git a/cmd/chantools/dropchannelgraph.go b/cmd/chantools/dropchannelgraph.go index d7f2b8d..664eff0 100644 --- a/cmd/chantools/dropchannelgraph.go +++ b/cmd/chantools/dropchannelgraph.go @@ -5,6 +5,7 @@ import ( "encoding/hex" "errors" "fmt" + "path/filepath" "time" "github.com/btcsuite/btcd/btcec/v2" @@ -60,8 +61,8 @@ chantools dropchannelgraph \ RunE: cc.Execute, } cc.cmd.Flags().StringVar( - &cc.ChannelDB, "channeldb", "", "lnd channel.db file to drop "+ - "channels from", + &cc.ChannelDB, "channeldb", "", "lnd's channel database file "+ + "to drop channels from", ) cc.cmd.Flags().Uint64Var( &cc.SingleChannel, "single_channel", 0, "the single channel "+ @@ -81,11 +82,16 @@ chantools dropchannelgraph \ } func (c *dropChannelGraphCommand) Execute(_ *cobra.Command, _ []string) error { - // Check that we have a channel DB. - if c.ChannelDB == "" { - return errors.New("channel DB is required") + dbConfig := GetDBConfig() + var opts []lnd.DBOption + + // In case the channel DB is specified, we get the graph dir from it. + if c.ChannelDB != "" { + graphDir := filepath.Dir(c.ChannelDB) + opts = append(opts, lnd.WithCustomGraphDir(graphDir)) } - db, err := lnd.OpenDB(c.ChannelDB, false) + + db, err := lnd.OpenChannelDB(dbConfig, chainParams.Name, opts...) if err != nil { return fmt.Errorf("error opening rescue DB: %w", err) } diff --git a/cmd/chantools/dropgraphzombies.go b/cmd/chantools/dropgraphzombies.go index 7daf893..a3dd8d7 100644 --- a/cmd/chantools/dropgraphzombies.go +++ b/cmd/chantools/dropgraphzombies.go @@ -1,8 +1,8 @@ package main import ( - "errors" "fmt" + "path/filepath" "github.com/lightninglabs/chantools/lnd" "github.com/lightningnetwork/lnd/channeldb" @@ -51,11 +51,17 @@ run lnd ` + lndVersion + ` or later after using this command!'`, } func (c *dropGraphZombiesCommand) Execute(_ *cobra.Command, _ []string) error { - // Check that we have a channel DB. - if c.ChannelDB == "" { - return errors.New("channel DB is required") + var opts []lnd.DBOption + + // In case the channel DB is specified, we get the graph dir from it. + if c.ChannelDB != "" { + graphDir := filepath.Dir(c.ChannelDB) + opts = append(opts, lnd.WithCustomGraphDir(graphDir)) } - db, err := lnd.OpenDB(c.ChannelDB, false) + + dbConfig := GetDBConfig() + + db, err := lnd.OpenChannelDB(dbConfig, chainParams.Name, opts...) if err != nil { return fmt.Errorf("error opening rescue DB: %w", err) } diff --git a/cmd/chantools/dumpchannels.go b/cmd/chantools/dumpchannels.go index f7b59ed..9d20e1c 100644 --- a/cmd/chantools/dumpchannels.go +++ b/cmd/chantools/dumpchannels.go @@ -3,6 +3,7 @@ package main import ( "errors" "fmt" + "path/filepath" "github.com/davecgh/go-spew/spew" "github.com/lightninglabs/chantools/dump" @@ -53,11 +54,17 @@ given lnd channel.db gile in a human readable format.`, } func (c *dumpChannelsCommand) Execute(_ *cobra.Command, _ []string) error { - // Check that we have a channel DB. - if c.ChannelDB == "" { - return errors.New("channel DB is required") + var opts []lnd.DBOption + + // In case the channel DB is specified, we get the graph dir from it. + if c.ChannelDB != "" { + graphDir := filepath.Dir(c.ChannelDB) + opts = append(opts, lnd.WithCustomGraphDir(graphDir)) } - db, err := lnd.OpenDB(c.ChannelDB, true) + + dbConfig := GetDBConfig() + + db, err := lnd.OpenChannelDB(dbConfig, chainParams.Name, opts...) if err != nil { return fmt.Errorf("error opening rescue DB: %w", err) } diff --git a/cmd/chantools/forceclose.go b/cmd/chantools/forceclose.go index 9e4cc57..d6b2e9f 100644 --- a/cmd/chantools/forceclose.go +++ b/cmd/chantools/forceclose.go @@ -4,10 +4,10 @@ import ( "bytes" "encoding/hex" "encoding/json" - "errors" "fmt" "io" "os" + "path/filepath" "time" "github.com/btcsuite/btcd/btcutil/hdkeychain" @@ -78,11 +78,17 @@ func (c *forceCloseCommand) Execute(_ *cobra.Command, _ []string) error { return fmt.Errorf("error reading root key: %w", err) } - // Check that we have a channel DB. - if c.ChannelDB == "" { - return errors.New("rescue DB is required") + var opts []lnd.DBOption + + // In case the channel DB is specified, we get the graph dir from it. + if c.ChannelDB != "" { + graphDir := filepath.Dir(c.ChannelDB) + opts = append(opts, lnd.WithCustomGraphDir(graphDir)) } - db, err := lnd.OpenDB(c.ChannelDB, true) + + dbConfig := GetDBConfig() + + db, err := lnd.OpenChannelDB(dbConfig, chainParams.Name, opts...) if err != nil { return fmt.Errorf("error opening rescue DB: %w", err) } diff --git a/cmd/chantools/migratedb.go b/cmd/chantools/migratedb.go index 6ef9880..fb3fc2f 100644 --- a/cmd/chantools/migratedb.go +++ b/cmd/chantools/migratedb.go @@ -1,8 +1,8 @@ package main import ( - "errors" "fmt" + "path/filepath" "github.com/lightninglabs/chantools/lnd" "github.com/spf13/cobra" @@ -40,13 +40,19 @@ run lnd ` + lndVersion + ` or later after using this command!'`, } func (c *migrateDBCommand) Execute(_ *cobra.Command, _ []string) error { - // Check that we have a channel DB. - if c.ChannelDB == "" { - return errors.New("channel DB is required") + var opts []lnd.DBOption + + // In case the channel DB is specified, we get the graph dir from it. + if c.ChannelDB != "" { + graphDir := filepath.Dir(c.ChannelDB) + opts = append(opts, lnd.WithCustomGraphDir(graphDir)) } - db, err := lnd.OpenDB(c.ChannelDB, false) + + dbConfig := GetDBConfig() + + db, err := lnd.OpenChannelDB(dbConfig, chainParams.Name, opts...) if err != nil { - return fmt.Errorf("error opening DB: %w", err) + return fmt.Errorf("error opening rescue DB: %w", err) } return db.Close() diff --git a/cmd/chantools/removechannel.go b/cmd/chantools/removechannel.go index 15697ff..4b01fe1 100644 --- a/cmd/chantools/removechannel.go +++ b/cmd/chantools/removechannel.go @@ -1,8 +1,8 @@ package main import ( - "errors" "fmt" + "path/filepath" "strconv" "strings" @@ -52,13 +52,19 @@ run lnd ` + lndVersion + ` or later after using this command!`, } func (c *removeChannelCommand) Execute(_ *cobra.Command, _ []string) error { - // Check that we have a channel DB. - if c.ChannelDB == "" { - return errors.New("channel DB is required") + var opts []lnd.DBOption + + // In case the channel DB is specified, we get the graph dir from it. + if c.ChannelDB != "" { + graphDir := filepath.Dir(c.ChannelDB) + opts = append(opts, lnd.WithCustomGraphDir(graphDir)) } - db, err := lnd.OpenDB(c.ChannelDB, false) + + dbConfig := GetDBConfig() + + db, err := lnd.OpenChannelDB(dbConfig, chainParams.Name, opts...) if err != nil { - return fmt.Errorf("error opening channel DB: %w", err) + return fmt.Errorf("error opening rescue DB: %w", err) } defer func() { if err := db.Close(); err != nil { diff --git a/cmd/chantools/rescueclosed.go b/cmd/chantools/rescueclosed.go index 9e9dd94..594698a 100644 --- a/cmd/chantools/rescueclosed.go +++ b/cmd/chantools/rescueclosed.go @@ -7,6 +7,7 @@ import ( "errors" "fmt" "os" + "path/filepath" "regexp" "time" @@ -122,30 +123,13 @@ func (c *rescueClosedCommand) Execute(_ *cobra.Command, _ []string) error { return fmt.Errorf("error reading root key: %w", err) } + cmdErr := errors.New("you either need to specify --channeldb and " + + "--fromsummary or --force_close_addr and " + + "--commit_point but not a mixture of them") + // What way of recovery has the user chosen? From summary and DB or from // address and commit point? switch { - case c.ChannelDB != "": - db, err := lnd.OpenDB(c.ChannelDB, true) - if err != nil { - return fmt.Errorf("error opening rescue DB: %w", err) - } - - // Parse channel entries from any of the possible input files. - entries, err := c.inputs.parseInputType() - if err != nil { - return err - } - - commitPoints, err := commitPointsFromDB(db.ChannelStateDB()) - if err != nil { - return fmt.Errorf("error reading commit points from "+ - "db: %w", err) - } - return rescueClosedChannels( - c.NumKeys, extendedKey, entries, commitPoints, - ) - case c.Addr != "": // First parse address to get targetPubKeyHash from it later. targetAddr, err := btcutil.DecodeAddress(c.Addr, chainParams) @@ -185,6 +169,37 @@ func (c *rescueClosedCommand) Execute(_ *cobra.Command, _ []string) error { ) default: + var opts []lnd.DBOption + + // In case the channel DB is specified, we get the graph dir + // from it. + if c.ChannelDB != "" { + graphDir := filepath.Dir(c.ChannelDB) + opts = append(opts, lnd.WithCustomGraphDir(graphDir)) + } + + dbConfig := GetDBConfig() + + db, err := lnd.OpenChannelDB(dbConfig, chainParams.Name, opts...) + if err != nil { + return fmt.Errorf("error opening rescue DB: %w, %v", + err, cmdErr) + } + + // Parse channel entries from any of the possible input files. + entries, err := c.inputs.parseInputType() + if err != nil { + return err + } + + commitPoints, err := commitPointsFromDB(db.ChannelStateDB()) + if err != nil { + return fmt.Errorf("error reading commit points from "+ + "db: %w", err) + } + return rescueClosedChannels( + c.NumKeys, extendedKey, entries, commitPoints, + ) return errors.New("you either need to specify --channeldb and " + "--fromsummary or --force_close_addr and " + "--commit_point but not a mixture of them") diff --git a/cmd/chantools/rescuefunding.go b/cmd/chantools/rescuefunding.go index bb89f38..156953f 100644 --- a/cmd/chantools/rescuefunding.go +++ b/cmd/chantools/rescuefunding.go @@ -5,6 +5,7 @@ import ( "encoding/hex" "errors" "fmt" + "path/filepath" "github.com/btcsuite/btcd/btcec/v2" "github.com/btcsuite/btcd/btcutil" @@ -151,18 +152,27 @@ func (c *rescueFundingCommand) Execute(_ *cobra.Command, _ []string) error { // Check that we have a channel DB or manual keys. switch { - case (c.ChannelDB == "" || c.DBChannelPoint == "") && - c.RemotePubKey == "": + case c.DBChannelPoint == "" && c.RemotePubKey == "": + return errors.New("need to specify either channel point or " + + "both local and remote pubkey") + + case c.DBChannelPoint != "": + var opts []lnd.DBOption + + // In case the channel DB is specified, we get the graph dir + // from it. + if c.ChannelDB != "" { + graphDir := filepath.Dir(c.ChannelDB) + opts = append(opts, lnd.WithCustomGraphDir(graphDir)) + } - return errors.New("need to specify either channel DB and " + - "channel point or both local and remote pubkey") + dbConfig := GetDBConfig() - case c.ChannelDB != "" && c.DBChannelPoint != "": - db, err := lnd.OpenDB(c.ChannelDB, true) + db, err := lnd.OpenChannelDB(dbConfig, chainParams.Name, opts...) if err != nil { - return fmt.Errorf("error opening rescue DB: %w", err) + return fmt.Errorf("error opening rescue DB: %w, %v", + err) } - // Parse channel point of channel to rescue as known to the DB. databaseOp, err = lnd.ParseOutpoint(c.DBChannelPoint) if err != nil { diff --git a/cmd/chantools/root.go b/cmd/chantools/root.go index b712c2e..29114b0 100644 --- a/cmd/chantools/root.go +++ b/cmd/chantools/root.go @@ -7,9 +7,11 @@ import ( "fmt" "io" "os" + "path/filepath" "strings" "time" + "github.com/btcsuite/btcd/btcutil" "github.com/btcsuite/btcd/btcutil/hdkeychain" "github.com/btcsuite/btcd/chaincfg" "github.com/btcsuite/btclog" @@ -19,7 +21,10 @@ import ( "github.com/lightningnetwork/lnd/build" "github.com/lightningnetwork/lnd/chanbackup" "github.com/lightningnetwork/lnd/channeldb" + "github.com/lightningnetwork/lnd/kvdb/postgres" + "github.com/lightningnetwork/lnd/kvdb/sqlite" "github.com/lightningnetwork/lnd/peer" + "github.com/ory/viper" "github.com/spf13/cobra" ) @@ -50,6 +55,8 @@ var ( logWriter = build.NewRotatingLogWriter() log = build.NewSubLogger("CHAN", genSubLogger(logWriter)) chainParams = &chaincfg.MainNetParams + // defaultDataDir is the default data directory for lnd. + defaultDataDir = btcutil.AppDataDir("lnd", false) ) var rootCmd = &cobra.Command{ @@ -96,6 +103,24 @@ func main() { &Signet, "signet", "s", false, "Indicates if the public "+ "signet parameters should be used", ) + rootCmd.PersistentFlags().String("db.backend", "bolt", "The selected database backend (bolt/etcd/postgres/sqlite)") + + // Bolt settings + rootCmd.PersistentFlags().Duration("db.bolt.dbtimeout", 10*time.Second, "Specify the timeout value used when opening the database") + rootCmd.PersistentFlags().String("db.bolt.data-dir", defaultDataDir, "Lnd data dir where bolt dbs are located") + rootCmd.PersistentFlags().String("db.bolt.tower-dir", defaultDataDir, "Lnd watchtower dir where bolt dbs are located") + + // Sqlite settings + rootCmd.PersistentFlags().String("db.sqlite.data-dir", defaultDataDir, "Lnd data dir where sqlite dbs are located") + rootCmd.PersistentFlags().String("db.sqlite.tower-dir", defaultDataDir, "Lnd watchtower dir where sqlite dbs are located") + rootCmd.PersistentFlags().Duration("db.sqlite.timeout", 10*time.Second, "Specify the timeout value used when opening the database") + + // Postgres settings + rootCmd.PersistentFlags().String("db.postgres.dsn", "", "Postgres connection string") + rootCmd.PersistentFlags().Duration("db.postgres.timeout", 10*time.Second, "Specify the timeout value used when opening the database") + + // Bind flags to viper + viper.BindPFlags(rootCmd.PersistentFlags()) rootCmd.AddCommand( newChanBackupCommand(), @@ -275,9 +300,20 @@ func (f *inputFlags) parseInputType() ([]*dataformat.SummaryEntry, error) { target = &dataformat.SummaryEntryFile{} case f.FromChannelDB != "": - db, err := lnd.OpenDB(f.FromChannelDB, true) + var opts []lnd.DBOption + + // In case the channel DB is specified, we get the graph dir + // from it. + if f.FromChannelDB != "" { + graphDir := filepath.Dir(f.FromChannelDB) + opts = append(opts, lnd.WithCustomGraphDir(graphDir)) + } + + dbConfig := GetDBConfig() + + db, err := lnd.OpenChannelDB(dbConfig, chainParams.Name, opts...) if err != nil { - return nil, fmt.Errorf("error opening channel DB: %w", + return nil, fmt.Errorf("error opening rescue DB: %w", err) } target = &dataformat.ChannelDBFile{DB: db.ChannelStateDB()} @@ -365,3 +401,28 @@ func newExplorerAPI(apiURL string) *btc.ExplorerAPI { // Otherwise use the provided URL. return &btc.ExplorerAPI{BaseURL: apiURL} } + +// GetDBConfig returns the database configuration from viper/cobra flags +func GetDBConfig() lnd.DB { + return lnd.DB{ + Backend: viper.GetString("db.backend"), + Bolt: &lnd.Bolt{ + DBTimeout: viper.GetDuration("db.bolt.dbtimeout"), + DataDir: viper.GetString("db.bolt.data-dir"), + TowerDir: viper.GetString("db.bolt.tower-dir"), + }, + Sqlite: &lnd.Sqlite{ + DataDir: viper.GetString("db.sqlite.data-dir"), + TowerDir: viper.GetString("db.sqlite.tower-dir"), + Config: &sqlite.Config{ + MaxConnections: viper.GetInt("db.sqlite.timeout"), + }, + }, + Postgres: &postgres.Config{ + Dsn: viper.GetString("db.postgres.dsn"), + MaxConnections: viper.GetInt("db.postgres.max-connections"), + Timeout: viper.GetDuration("db.postgres.timeout"), + }, + // Add Etcd config if needed + } +} diff --git a/go.mod b/go.mod index 379ccb1..d93ac76 100644 --- a/go.mod +++ b/go.mod @@ -35,7 +35,10 @@ require ( golang.org/x/oauth2 v0.14.0 ) -require github.com/tv42/zbase32 v0.0.0-20220222190657-f76a9fc892fa +require ( + github.com/ory/viper v1.7.5 + github.com/tv42/zbase32 v0.0.0-20220222190657-f76a9fc892fa +) require ( github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect @@ -53,6 +56,7 @@ require ( github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792 // indirect github.com/btcsuite/winsvc v1.0.0 // indirect github.com/cenkalti/backoff/v4 v4.1.3 // indirect + github.com/cespare/xxhash v1.1.0 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/containerd/continuity v0.3.0 // indirect github.com/coreos/go-semver v0.3.0 // indirect @@ -60,6 +64,7 @@ require ( github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect github.com/decred/dcrd/crypto/blake256 v1.0.1 // indirect github.com/decred/dcrd/lru v1.1.2 // indirect + github.com/dgraph-io/ristretto v0.0.1 // indirect github.com/docker/cli v20.10.17+incompatible // indirect github.com/docker/docker v24.0.9+incompatible // indirect github.com/docker/go-connections v0.4.0 // indirect @@ -68,6 +73,7 @@ require ( github.com/fergusstrange/embedded-postgres v1.25.0 // indirect github.com/fortytw2/leaktest v1.3.0 // indirect github.com/frankban/quicktest v1.14.3 // indirect + github.com/fsnotify/fsnotify v1.5.4 // indirect github.com/go-errors/errors v1.0.1 // indirect github.com/go-logr/logr v1.3.0 // indirect github.com/go-logr/stdr v1.2.2 // indirect @@ -86,6 +92,7 @@ require ( github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect + github.com/hashicorp/hcl v1.0.0 // indirect github.com/imdario/mergo v0.3.13 // indirect github.com/inconshreveable/mousetrap v1.0.0 // indirect github.com/jackc/chunkreader/v2 v2.0.1 // indirect @@ -121,6 +128,7 @@ require ( github.com/lightningnetwork/lnd/sqldb v1.0.4 // indirect github.com/lightningnetwork/lnd/tlv v1.2.6 // indirect github.com/ltcsuite/ltcd v0.0.0-20191228044241-92166e412499 // indirect + github.com/magiconair/properties v1.8.1 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect github.com/miekg/dns v1.1.43 // indirect @@ -133,6 +141,7 @@ require ( github.com/opencontainers/image-spec v1.0.2 // indirect github.com/opencontainers/runc v1.1.14 // indirect github.com/ory/dockertest/v3 v3.10.0 // indirect + github.com/pelletier/go-toml v1.2.0 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_golang v1.11.1 // indirect @@ -146,8 +155,12 @@ require ( github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect github.com/sirupsen/logrus v1.9.2 // indirect github.com/soheilhy/cmux v0.1.5 // indirect + github.com/spf13/afero v1.9.2 // indirect + github.com/spf13/cast v1.3.0 // indirect + github.com/spf13/jwalterweatherman v1.0.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/stretchr/objx v0.5.2 // indirect + github.com/subosito/gotenv v1.2.0 // indirect github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 // indirect github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802 // indirect github.com/xdg-go/stringprep v1.0.4 // indirect @@ -193,6 +206,7 @@ require ( google.golang.org/grpc v1.59.0 // indirect google.golang.org/protobuf v1.33.0 // indirect gopkg.in/errgo.v1 v1.0.1 // indirect + gopkg.in/ini.v1 v1.51.0 // indirect gopkg.in/macaroon-bakery.v2 v2.1.0 // indirect gopkg.in/macaroon.v2 v2.1.0 // indirect gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect diff --git a/go.sum b/go.sum index cb50828..91e9620 100644 --- a/go.sum +++ b/go.sum @@ -613,6 +613,7 @@ github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migc github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= +github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/Yawning/aez v0.0.0-20211027044916-e49e68abd344 h1:cDVUiFo+npB0ZASqnw4q90ylaVAbnYyx0JYqK4YcGok= github.com/Yawning/aez v0.0.0-20211027044916-e49e68abd344/go.mod h1:9pIqrY6SXNL8vjRQE5Hd/OL5GyK/9MrGUWs87z/eFfk= @@ -695,6 +696,7 @@ github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054 h1:uH66TXeswKn5PW5zdZ39xEwfS9an067BirqA+P4QaLI= github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= +github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= @@ -758,7 +760,11 @@ github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0/go.mod h1:v57UDF4pDQJcEfFUCRop3 github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218= github.com/decred/dcrd/lru v1.1.2 h1:KdCzlkxppuoIDGEvCGah1fZRicrDH36IipvlB1ROkFY= github.com/decred/dcrd/lru v1.1.2/go.mod h1:gEdCVgXs1/YoBvFWt7Scgknbhwik3FgVSzlnCcXL2N8= +github.com/dgraph-io/ristretto v0.0.1 h1:cJwdnj42uV8Jg4+KLrYovLiCgIfz9wtWm6E6KA+1tLs= +github.com/dgraph-io/ristretto v0.0.1/go.mod h1:T40EBc7CJke8TkpiYfGGKAeFjSaxuFXhuXRyumBd6RE= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA= +github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/dhui/dktest v0.4.0 h1:z05UmuXZHO/bgj/ds2bGMBu8FI4WA+Ag/m3ghL+om7M= github.com/dhui/dktest v0.4.0/go.mod h1:v/Dbz1LgCBOi2Uki2nUqLBGa83hWBGFMu5MrgMDCc78= @@ -982,6 +988,7 @@ github.com/googleapis/gax-go/v2 v2.7.0/go.mod h1:TEop28CZZQ2y+c0VxMUmu1lV+fQx57Q github.com/googleapis/gax-go/v2 v2.7.1/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI= github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= @@ -1025,6 +1032,7 @@ github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= @@ -1110,6 +1118,7 @@ github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnr github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a/go.mod h1:UJSiEoRfvx3hP73CvoARgeLjaIOjybY9vj8PUPPFGeU= github.com/juju/clock v0.0.0-20220203021603-d9deb868a28a h1:Az/6CM/P5guGHNy7r6TkOCctv3lDmN3W1uhku7QMupk= @@ -1153,6 +1162,7 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxv github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= @@ -1217,6 +1227,7 @@ github.com/lunixbochs/vtclean v0.0.0-20160125035106-4fbf7632a2c6/go.mod h1:pHhQN github.com/lyft/protoc-gen-star v0.6.0/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= github.com/lyft/protoc-gen-star v0.6.1/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= github.com/lyft/protoc-gen-star/v2 v2.0.1/go.mod h1:RcCdONR2ScXaYnQC5tUzxzlpA3WVYF7/opLeUgcQs/o= +github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mattn/go-colorable v0.0.6/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= @@ -1290,7 +1301,10 @@ github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFSt github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= github.com/ory/dockertest/v3 v3.10.0 h1:4K3z2VMe8Woe++invjaTB7VRyQXQy5UY+loujO4aNE4= github.com/ory/dockertest/v3 v3.10.0/go.mod h1:nr57ZbRWMqfsdGdFNLHz5jjNdDb7VVFnzAeW1n5N1Lg= +github.com/ory/viper v1.7.5 h1:+xVdq7SU3e1vNaCsk/ixsfxE4zylk1TJUiJrY647jUE= +github.com/ory/viper v1.7.5/go.mod h1:ypOuyJmEUb3oENywQZRgeAMwqgOyDqwboO1tj3DjTaM= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/phpdave11/gofpdf v1.4.2/go.mod h1:zpO6xFn9yxo3YLyMvW8HcKWVdbNqgIfOOp2dXMnm1mY= github.com/phpdave11/gofpdi v1.0.12/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= @@ -1367,19 +1381,25 @@ github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6Mwd github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.9.2 h1:oxx1eChJGI6Uks2ZC4W1zpLlVgqB8ner4EuQwV4Ik1Y= github.com/sirupsen/logrus v1.9.2/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js= github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72 h1:qLC7fQah7D6K1B0ujays3HV9gkFtllcxhzImRR7ArPQ= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= +github.com/spf13/afero v1.9.2 h1:j49Hj62F0n+DaZ1dDCvhABaPNSGNkt32oRFxI33IEMw= github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= +github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v1.1.3 h1:xghbfqPkxzxP3C/f3n5DdpAbdKLj4ZE4BWQI362l53M= github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo= +github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= @@ -1404,6 +1424,7 @@ github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= @@ -1523,6 +1544,7 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190618222545-ea8f1a30c443/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= @@ -1746,6 +1768,7 @@ golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -2205,6 +2228,7 @@ gopkg.in/errgo.v1 v1.0.1/go.mod h1:3NjfXwocQRYAPTq4/fzX+CwUhPRcR/azYRhj8G+LqMo= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= +gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/macaroon-bakery.v2 v2.1.0 h1:9Jw/+9XHBSutkaeVpWhDx38IcSNLJwWUICkOK98DHls= gopkg.in/macaroon-bakery.v2 v2.1.0/go.mod h1:B4/T17l+ZWGwxFSZQmlBwp25x+og7OkhETfr3S9MbIA= diff --git a/lnd/channeldb.go b/lnd/channeldb.go index b83758f..14ee256 100644 --- a/lnd/channeldb.go +++ b/lnd/channeldb.go @@ -1,28 +1,247 @@ package lnd import ( + "context" "errors" "fmt" "io" "os" + "path/filepath" "time" "github.com/btcsuite/btcwallet/walletdb" "github.com/lightningnetwork/lnd/channeldb" "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/lncfg" "go.etcd.io/bbolt" ) +// Bolt specifies the settings for the bolt database. +type Bolt struct { + DBTimeout time.Duration + DataDir string + TowerDir string +} + +// Sqlite specifies the settings for the sqlite database. +type Sqlite struct { + DataDir string + TowerDir string + Config *sqlite.Config +} + +// DB specifies the settings for all different database backends. +type DB struct { + Backend string + Etcd *etcd.Config + Bolt *Bolt + Postgres *postgres.Config + Sqlite *Sqlite +} + const ( + // DefaultOpenTimeout is the default timeout for opening a database. DefaultOpenTimeout = time.Second * 10 ) -func OpenDB(dbPath string, readonly bool) (*channeldb.DB, error) { - backend, err := openDB(dbPath, false, readonly, DefaultOpenTimeout) +// Init should be called upon start to pre-initialize database for sql +// backends. If max connections are not set, the amount of connections will be +// unlimited however we only use one connection during the migration. +func (db DB) Init() error { + // Start embedded etcd server if requested. + switch { + case db.Backend == lncfg.PostgresBackend: + sqlbase.Init(db.Postgres.MaxConnections) + + case db.Backend == lncfg.SqliteBackend: + sqlbase.Init(db.Sqlite.Config.MaxConnections) + } + + return nil +} + +// DBOption is a functional option for configuring the database. +type DBOption func(*dbOptions) + +type dbOptions struct { + customGraphDir string +} + +// WithCustomGraphDir sets a custom directory for the graph database. +func WithCustomGraphDir(dir string) DBOption { + return func(opts *dbOptions) { + opts.customGraphDir = dir + } +} + +func openDB(cfg DB, prefix, network string, opts ...DBOption) (kvdb.Backend, error) { + backend := cfg.Backend + + // Init the db connections for sql backends. + err := cfg.Init() + if err != nil { + return nil, err + } + + options := &dbOptions{} + for _, opt := range opts { + opt(options) + } + + // Settings to open a particular db backend. + var args []interface{} + + switch backend { + case lncfg.BoltBackend: + // Directories where the db files are located. + var graphDir string + if options.customGraphDir != "" { + graphDir = options.customGraphDir + } else { + graphDir = filepath.Join( + cfg.Bolt.DataDir, "graph", network, + ) + } + + walletDir := filepath.Join( + cfg.Bolt.DataDir, "chain", "bitcoin", network, + ) + towerServerDir := filepath.Join( + cfg.Bolt.TowerDir, "bitcoin", network, + ) + + // Path to the db file. + var path string + switch prefix { + case lncfg.NSChannelDB: + path = filepath.Join(graphDir, lncfg.ChannelDBName) + + case lncfg.NSMacaroonDB: + path = filepath.Join(walletDir, lncfg.MacaroonDBName) + + case lncfg.NSDecayedLogDB: + path = filepath.Join(graphDir, lncfg.DecayedLogDbName) + + case lncfg.NSTowerClientDB: + path = filepath.Join(graphDir, lncfg.TowerClientDBName) + + case lncfg.NSTowerServerDB: + path = filepath.Join( + towerServerDir, lncfg.TowerServerDBName, + ) + + case lncfg.NSWalletDB: + path = filepath.Join(walletDir, lncfg.WalletDBName) + } + + const ( + noFreelistSync = true + timeout = time.Minute + ) + + args = []interface{}{ + path, noFreelistSync, timeout, + } + backend = kvdb.BoltBackendName + // log("Opening bbolt backend at %s for prefix '%s'", path, prefix) + + case kvdb.EtcdBackendName: + args = []interface{}{ + context.Background(), + cfg.Etcd.CloneWithSubNamespace(prefix), + } + + case kvdb.PostgresBackendName: + args = []interface{}{ + context.Background(), + &postgres.Config{ + Dsn: cfg.Postgres.Dsn, + Timeout: time.Minute, + MaxConnections: 10, + }, + prefix, + } + + case kvdb.SqliteBackendName: + // Directories where the db files are located. + var graphDir string + if options.customGraphDir != "" { + graphDir = options.customGraphDir + } else { + graphDir = filepath.Join( + cfg.Bolt.DataDir, "graph", network, + ) + } + walletDir := filepath.Join( + cfg.Sqlite.DataDir, "chain", "bitcoin", network, + ) + towerServerDir := filepath.Join( + cfg.Sqlite.TowerDir, "bitcoin", network, + ) + graphDir = cfg.Sqlite.DataDir + + var dbName string + var path string + switch prefix { + case lncfg.NSChannelDB: + path = graphDir + dbName = lncfg.SqliteChannelDBName + case lncfg.NSMacaroonDB: + path = walletDir + dbName = lncfg.SqliteChainDBName + + case lncfg.NSDecayedLogDB: + path = graphDir + dbName = lncfg.SqliteChannelDBName + + case lncfg.NSTowerClientDB: + path = graphDir + dbName = lncfg.SqliteChannelDBName + + case lncfg.NSTowerServerDB: + path = towerServerDir + dbName = lncfg.SqliteChannelDBName + + case lncfg.NSWalletDB: + path = walletDir + dbName = lncfg.SqliteChainDBName + + case lncfg.NSNeutrinoDB: + dbName = lncfg.SqliteNeutrinoDBName + } + + args = []interface{}{ + context.Background(), + &sqlite.Config{ + Timeout: time.Minute, + }, + path, + dbName, + prefix, + } + + default: + return nil, fmt.Errorf("unknown backend: %v", backend) + } + + return kvdb.Open(backend, args...) +} + +// OpenChannelDB opens the channel database for all supported backends. +func OpenChannelDB(cfg DB, network string, + opts ...DBOption) (*channeldb.DB, error) { + + backend, err := openDB(cfg, lncfg.NSChannelDB, network, opts...) + + // For the bbolt backend, we signal a detailed error message if the + // database is locked by another process. if errors.Is(err, bbolt.ErrTimeout) { - return nil, fmt.Errorf("error opening %s: make sure lnd is "+ - "not running, database is locked by another process", - dbPath) + return nil, fmt.Errorf("error opening boltDB: make sure lnd " + + "is not running, database is locked by another process") } if err != nil { return nil, err @@ -30,7 +249,7 @@ func OpenDB(dbPath string, readonly bool) (*channeldb.DB, error) { return channeldb.CreateWithBackend( backend, channeldb.OptionSetUseGraphCache(false), - channeldb.OptionNoMigration(readonly), + channeldb.OptionNoMigration(true), ) } @@ -477,24 +696,24 @@ func fileExists(name string) bool { return true } -// openDB opens the database at the provided path. walletdb.ErrDbDoesNotExist -// is returned if the database doesn't exist and the create flag is not set. -func openDB(dbPath string, noFreelistSync bool, - readonly bool, timeout time.Duration) (kvdb.Backend, error) { +// // openDB opens the database at the provided path. walletdb.ErrDbDoesNotExist +// // is returned if the database doesn't exist and the create flag is not set. +// func openDB(dbPath string, noFreelistSync bool, +// readonly bool, timeout time.Duration) (kvdb.Backend, error) { - if !fileExists(dbPath) { - return nil, walletdb.ErrDbDoesNotExist - } +// if !fileExists(dbPath) { +// return nil, walletdb.ErrDbDoesNotExist +// } - // Specify bbolt freelist options to reduce heap pressure in case the - // freelist grows to be very large. - options := &bbolt.Options{ - NoFreelistSync: noFreelistSync, - FreelistType: bbolt.FreelistMapType, - Timeout: timeout, - ReadOnly: readonly, - } +// // Specify bbolt freelist options to reduce heap pressure in case the +// // freelist grows to be very large. +// options := &bbolt.Options{ +// NoFreelistSync: noFreelistSync, +// FreelistType: bbolt.FreelistMapType, +// Timeout: timeout, +// ReadOnly: readonly, +// } - boltDB, err := bbolt.Open(dbPath, 0600, options) - return &backend{db: boltDB}, convertErr(err) -} +// boltDB, err := bbolt.Open(dbPath, 0600, options) +// return &backend{db: boltDB}, convertErr(err) +// }