lnd+paymentsdb: introduce harness for the payment sql backend
What changed, and why it matters
This commit is purely preparatory infrastructure. It adds scaffolding for a future SQL-based payments database backend in LND, but explicitly does not implement any actual payment database methods yet. The new SQL store currently falls back to the existing key-value store implementation to satisfy build requirements. There is no security-relevant behavior change or vulnerability introduced in this patch.
No security action required. Treat as normal development/refactoring commit. Continue monitoring subsequent commits that actually implement SQL queries and migration logic for the payments backend.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The commit introduces a build-tag-gated harness for an upcoming SQL payments backend. In production builds (config_prod.go), getPaymentsStore returns the existing paymentsdb.KVStore. In test builds with the test_native_sql tag (config_test_native_sql.go), it returns a new paymentsdb.SQLStore that embeds KVStore and implements the DB interface by delegation. payments/db/sql_store.go defines the SQLStore struct, config, constructor, and empty SQLQueries/BatchedSQLQueries interfaces, with a TODO noting no interface methods are implemented. config_builder.go is refactored to call getPaymentsStore in both SQL and KV database branches instead of always constructing a KV store after the graph DB. No SQL queries or data access logic are added.
Changed components
lnd/config_builder.golnd/config_prod.golnd/config_test_native_sql.gopayments/db/sql_store.goInspect captured patch +144 / −22
diff --git a/config_builder.go b/config_builder.go
index 3fe62cd..07196b2 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,40 +1276,35 @@ func (d *DefaultDatabaseBuilder) BuildDatabase(
if err != nil {
return nil, nil, err
}
- }
- dbs.GraphDB, err = graphdb.NewChannelGraph(graphStore, chanGraphOpts...)
- if err != nil {
- cleanUp()
+ // Create the payments DB.
+ kvPaymentsDB, err := paymentsdb.NewKVStore(
+ dbs.ChanStateDB,
+ paymentsdb.WithKeepFailedPaymentAttempts(
+ cfg.KeepFailedPaymentAttempts,
+ ),
+ )
+ if err != nil {
+ cleanUp()
- err = fmt.Errorf("unable to open channel graph DB: %w", err)
- d.logger.Error(err)
+ err = fmt.Errorf("unable to open payments DB: %w", err)
+ d.logger.Error(err)
- return nil, nil, err
- }
+ 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,
- ),
+ dbs.PaymentsDB = kvPaymentsDB
}
- kvPaymentsDB, err := paymentsdb.NewKVStore(
- dbs.ChanStateDB,
- paymentsDBOptions...,
- )
+
+ dbs.GraphDB, err = graphdb.NewChannelGraph(graphStore, chanGraphOpts...)
if err != nil {
cleanUp()
- err = fmt.Errorf("unable to open payments DB: %w", err)
+ err = fmt.Errorf("unable to open channel graph 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 {
diff --git a/config_prod.go b/config_prod.go
index 60dba8b..02b7d2a 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 91589fa..efc6ed8 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 0000000..12585ca
--- /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)
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.