diff --git a/config_builder.go b/config_builder.go index 3fe62cd2a..07196b21c 100644 --- a/config_builder.go +++ b/config_builder.go @@ -1228,6 +1228,26 @@ func (d *DefaultDatabaseBuilder) BuildDatabase( return nil, nil, err } + + // Create the payments DB. + // + // NOTE: In the regular build, this will construct a kvdb + // backed payments backend. With the test_native_sql tag, it + // will build a SQL payments backend. + sqlPaymentsDB, err := d.getPaymentsStore( + baseDB, dbs.ChanStateDB.Backend, + paymentsdb.WithKeepFailedPaymentAttempts( + cfg.KeepFailedPaymentAttempts, + ), + ) + if err != nil { + err = fmt.Errorf("unable to get payments store: %w", + err) + + return nil, nil, err + } + + dbs.PaymentsDB = sqlPaymentsDB } else { // Check if the invoice bucket tombstone is set. If it is, we // need to return and ask the user switch back to using the @@ -1256,6 +1276,24 @@ func (d *DefaultDatabaseBuilder) BuildDatabase( if err != nil { return nil, nil, err } + + // Create the payments DB. + kvPaymentsDB, err := paymentsdb.NewKVStore( + dbs.ChanStateDB, + paymentsdb.WithKeepFailedPaymentAttempts( + cfg.KeepFailedPaymentAttempts, + ), + ) + if err != nil { + cleanUp() + + err = fmt.Errorf("unable to open payments DB: %w", err) + d.logger.Error(err) + + return nil, nil, err + } + + dbs.PaymentsDB = kvPaymentsDB } dbs.GraphDB, err = graphdb.NewChannelGraph(graphStore, chanGraphOpts...) @@ -1268,29 +1306,6 @@ func (d *DefaultDatabaseBuilder) BuildDatabase( return nil, nil, err } - // Mount the payments DB which is only KV for now. - // - // TODO(ziggie): Add support for SQL payments DB. - // Mount the payments DB for the KV store. - paymentsDBOptions := []paymentsdb.OptionModifier{ - paymentsdb.WithKeepFailedPaymentAttempts( - cfg.KeepFailedPaymentAttempts, - ), - } - kvPaymentsDB, err := paymentsdb.NewKVStore( - dbs.ChanStateDB, - paymentsDBOptions..., - ) - if err != nil { - cleanUp() - - err = fmt.Errorf("unable to open payments DB: %w", err) - d.logger.Error(err) - - return nil, nil, err - } - dbs.PaymentsDB = kvPaymentsDB - // Wrap the watchtower client DB and make sure we clean up. if cfg.WtClient.Active { dbs.TowerClientDB, err = wtdb.OpenClientDB( diff --git a/config_prod.go b/config_prod.go index 60dba8bb5..02b7d2aac 100644 --- a/config_prod.go +++ b/config_prod.go @@ -6,6 +6,8 @@ import ( "context" "github.com/lightningnetwork/lnd/kvdb" + paymentsdb "github.com/lightningnetwork/lnd/payments/db" + "github.com/lightningnetwork/lnd/sqldb" "github.com/lightningnetwork/lnd/sqldb/sqlc" ) @@ -24,3 +26,12 @@ func (d *DefaultDatabaseBuilder) getSQLMigration(ctx context.Context, return nil, false } + +// getPaymentsStore returns a paymentsdb.DB backed by a paymentsdb.KVStore +// implementation. +func (d *DefaultDatabaseBuilder) getPaymentsStore(_ *sqldb.BaseDB, + kvBackend kvdb.Backend, + opts ...paymentsdb.OptionModifier) (paymentsdb.DB, error) { + + return paymentsdb.NewKVStore(kvBackend, opts...) +} diff --git a/config_test_native_sql.go b/config_test_native_sql.go index 91589fa68..efc6ed81e 100644 --- a/config_test_native_sql.go +++ b/config_test_native_sql.go @@ -4,8 +4,12 @@ package lnd import ( "context" + "database/sql" "github.com/lightningnetwork/lnd/kvdb" + "github.com/lightningnetwork/lnd/lncfg" + paymentsdb "github.com/lightningnetwork/lnd/payments/db" + "github.com/lightningnetwork/lnd/sqldb" "github.com/lightningnetwork/lnd/sqldb/sqlc" ) @@ -25,3 +29,28 @@ func (d *DefaultDatabaseBuilder) getSQLMigration(_ context.Context, return nil, false } } + +// getPaymentsStore returns a paymentsdb.DB backed by a paymentsdb.SQLStore +// implementation. +func (d *DefaultDatabaseBuilder) getPaymentsStore(baseDB *sqldb.BaseDB, + kvBackend kvdb.Backend, + opts ...paymentsdb.OptionModifier) (paymentsdb.DB, error) { + + paymentsExecutor := sqldb.NewTransactionExecutor( + baseDB, func(tx *sql.Tx) paymentsdb.SQLQueries { + return baseDB.WithTx(tx) + }, + ) + + queryConfig := d.cfg.DB.Sqlite.QueryConfig + if d.cfg.DB.Backend == lncfg.PostgresBackend { + queryConfig = d.cfg.DB.Postgres.QueryConfig + } + + return paymentsdb.NewSQLStore( + &paymentsdb.SQLStoreConfig{ + QueryCfg: &queryConfig, + }, + paymentsExecutor, opts..., + ) +} diff --git a/payments/db/sql_store.go b/payments/db/sql_store.go new file mode 100644 index 000000000..12585caf6 --- /dev/null +++ b/payments/db/sql_store.go @@ -0,0 +1,67 @@ +package paymentsdb + +import ( + "fmt" + + "github.com/lightningnetwork/lnd/sqldb" +) + +// SQLQueries is a subset of the sqlc.Querier interface that can be used to +// execute queries against the SQL payments tables. +type SQLQueries interface { +} + +// BatchedSQLQueries is a version of the SQLQueries that's capable +// of batched database operations. +type BatchedSQLQueries interface { + SQLQueries + sqldb.BatchedTx[SQLQueries] +} + +// SQLStore represents a storage backend. +type SQLStore struct { + // TODO(ziggie): Remove the KVStore once all the interface functions are + // implemented. + KVStore + + cfg *SQLStoreConfig + db BatchedSQLQueries + + // keepFailedPaymentAttempts is a flag that indicates whether we should + // keep failed payment attempts in the database. + keepFailedPaymentAttempts bool +} + +// A compile-time constraint to ensure SQLStore implements DB. +var _ DB = (*SQLStore)(nil) + +// SQLStoreConfig holds the configuration for the SQLStore. +type SQLStoreConfig struct { + // QueryConfig holds configuration values for SQL queries. + QueryCfg *sqldb.QueryConfig +} + +// NewSQLStore creates a new SQLStore instance given an open +// BatchedSQLPaymentsQueries storage backend. +func NewSQLStore(cfg *SQLStoreConfig, db BatchedSQLQueries, + options ...OptionModifier) (*SQLStore, error) { + + opts := DefaultOptions() + for _, applyOption := range options { + applyOption(opts) + } + + if opts.NoMigration { + return nil, fmt.Errorf("the NoMigration option is not yet " + + "supported for SQL stores") + } + + return &SQLStore{ + cfg: cfg, + db: db, + keepFailedPaymentAttempts: opts.KeepFailedPaymentAttempts, + }, nil +} + +// A compile-time constraint to ensure SQLStore implements DB. +var _ DB = (*SQLStore)(nil)