Skip to content

Commit 6cabc74

Browse files
authored
Merge pull request #8831 from bhandras/sql-invoice-migration
invoices: migrate KV invoices to native SQL for users of KV SQL backends
2 parents 49affa2 + b1a462d commit 6cabc74

37 files changed

+2762
-210
lines changed

config_builder.go

Lines changed: 61 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ import (
5151
"github.com/lightningnetwork/lnd/rpcperms"
5252
"github.com/lightningnetwork/lnd/signal"
5353
"github.com/lightningnetwork/lnd/sqldb"
54+
"github.com/lightningnetwork/lnd/sqldb/sqlc"
5455
"github.com/lightningnetwork/lnd/sweep"
5556
"github.com/lightningnetwork/lnd/walletunlocker"
5657
"github.com/lightningnetwork/lnd/watchtower"
@@ -60,6 +61,16 @@ import (
6061
"gopkg.in/macaroon-bakery.v2/bakery"
6162
)
6263

64+
const (
65+
// invoiceMigrationBatchSize is the number of invoices that will be
66+
// migrated in a single batch.
67+
invoiceMigrationBatchSize = 1000
68+
69+
// invoiceMigration is the version of the migration that will be used to
70+
// migrate invoices from the kvdb to the sql database.
71+
invoiceMigration = 7
72+
)
73+
6374
// GrpcRegistrar is an interface that must be satisfied by an external subserver
6475
// that wants to be able to register its own gRPC server onto lnd's main
6576
// grpc.Server instance.
@@ -932,10 +943,10 @@ type DatabaseInstances struct {
932943
// the btcwallet's loader.
933944
WalletDB btcwallet.LoaderOption
934945

935-
// NativeSQLStore is a pointer to a native SQL store that can be used
936-
// for native SQL queries for tables that already support it. This may
937-
// be nil if the use-native-sql flag was not set.
938-
NativeSQLStore *sqldb.BaseDB
946+
// NativeSQLStore holds a reference to the native SQL store that can
947+
// be used for native SQL queries for tables that already support it.
948+
// This may be nil if the use-native-sql flag was not set.
949+
NativeSQLStore sqldb.DB
939950
}
940951

941952
// DefaultDatabaseBuilder is a type that builds the default database backends
@@ -1038,7 +1049,7 @@ func (d *DefaultDatabaseBuilder) BuildDatabase(
10381049
if err != nil {
10391050
cleanUp()
10401051

1041-
err := fmt.Errorf("unable to open graph DB: %w", err)
1052+
err = fmt.Errorf("unable to open graph DB: %w", err)
10421053
d.logger.Error(err)
10431054

10441055
return nil, nil, err
@@ -1072,51 +1083,69 @@ func (d *DefaultDatabaseBuilder) BuildDatabase(
10721083
case err != nil:
10731084
cleanUp()
10741085

1075-
err := fmt.Errorf("unable to open graph DB: %w", err)
1086+
err = fmt.Errorf("unable to open graph DB: %w", err)
10761087
d.logger.Error(err)
10771088
return nil, nil, err
10781089
}
10791090

1080-
// Instantiate a native SQL invoice store if the flag is set.
1091+
// Instantiate a native SQL store if the flag is set.
10811092
if d.cfg.DB.UseNativeSQL {
1082-
// KV invoice db resides in the same database as the channel
1083-
// state DB. Let's query the database to see if we have any
1084-
// invoices there. If we do, we won't allow the user to start
1085-
// lnd with native SQL enabled, as we don't currently migrate
1086-
// the invoices to the new database schema.
1087-
invoiceSlice, err := dbs.ChanStateDB.QueryInvoices(
1088-
ctx, invoices.InvoiceQuery{
1089-
NumMaxInvoices: 1,
1090-
},
1091-
)
1092-
if err != nil {
1093-
cleanUp()
1094-
d.logger.Errorf("Unable to query KV invoice DB: %v",
1095-
err)
1093+
migrations := sqldb.GetMigrations()
1094+
1095+
// If the user has not explicitly disabled the SQL invoice
1096+
// migration, attach the custom migration function to invoice
1097+
// migration (version 7). Even if this custom migration is
1098+
// disabled, the regular native SQL store migrations will still
1099+
// run. If the database version is already above this custom
1100+
// migration's version (7), it will be skipped permanently,
1101+
// regardless of the flag.
1102+
if !d.cfg.DB.SkipSQLInvoiceMigration {
1103+
migrationFn := func(tx *sqlc.Queries) error {
1104+
return invoices.MigrateInvoicesToSQL(
1105+
ctx, dbs.ChanStateDB.Backend,
1106+
dbs.ChanStateDB, tx,
1107+
invoiceMigrationBatchSize,
1108+
)
1109+
}
10961110

1097-
return nil, nil, err
1111+
// Make sure we attach the custom migration function to
1112+
// the correct migration version.
1113+
for i := 0; i < len(migrations); i++ {
1114+
if migrations[i].Version != invoiceMigration {
1115+
continue
1116+
}
1117+
1118+
migrations[i].MigrationFn = migrationFn
1119+
}
10981120
}
10991121

1100-
if len(invoiceSlice.Invoices) > 0 {
1122+
// We need to apply all migrations to the native SQL store
1123+
// before we can use it.
1124+
err = dbs.NativeSQLStore.ApplyAllMigrations(ctx, migrations)
1125+
if err != nil {
11011126
cleanUp()
1102-
err := fmt.Errorf("found invoices in the KV invoice " +
1103-
"DB, migration to native SQL is not yet " +
1104-
"supported")
1127+
err = fmt.Errorf("faild to run migrations for the "+
1128+
"native SQL store: %w", err)
11051129
d.logger.Error(err)
11061130

11071131
return nil, nil, err
11081132
}
11091133

1134+
// With the DB ready and migrations applied, we can now create
1135+
// the base DB and transaction executor for the native SQL
1136+
// invoice store.
1137+
baseDB := dbs.NativeSQLStore.GetBaseDB()
11101138
executor := sqldb.NewTransactionExecutor(
1111-
dbs.NativeSQLStore,
1112-
func(tx *sql.Tx) invoices.SQLInvoiceQueries {
1113-
return dbs.NativeSQLStore.WithTx(tx)
1139+
baseDB, func(tx *sql.Tx) invoices.SQLInvoiceQueries {
1140+
return baseDB.WithTx(tx)
11141141
},
11151142
)
11161143

1117-
dbs.InvoiceDB = invoices.NewSQLStore(
1144+
sqlInvoiceDB := invoices.NewSQLStore(
11181145
executor, clock.NewDefaultClock(),
11191146
)
1147+
1148+
dbs.InvoiceDB = sqlInvoiceDB
11201149
} else {
11211150
dbs.InvoiceDB = dbs.ChanStateDB
11221151
}
@@ -1129,7 +1158,7 @@ func (d *DefaultDatabaseBuilder) BuildDatabase(
11291158
if err != nil {
11301159
cleanUp()
11311160

1132-
err := fmt.Errorf("unable to open %s database: %w",
1161+
err = fmt.Errorf("unable to open %s database: %w",
11331162
lncfg.NSTowerClientDB, err)
11341163
d.logger.Error(err)
11351164
return nil, nil, err
@@ -1144,7 +1173,7 @@ func (d *DefaultDatabaseBuilder) BuildDatabase(
11441173
if err != nil {
11451174
cleanUp()
11461175

1147-
err := fmt.Errorf("unable to open %s database: %w",
1176+
err = fmt.Errorf("unable to open %s database: %w",
11481177
lncfg.NSTowerServerDB, err)
11491178
d.logger.Error(err)
11501179
return nil, nil, err

docs/release-notes/release-notes-0.19.0.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,11 @@ The underlying functionality between those two options remain the same.
264264
transactions can run at once, increasing efficiency. Includes several bugfixes
265265
to allow this to work properly.
266266

267+
* [Migrate KV invoices to
268+
SQL](https://github.com/lightningnetwork/lnd/pull/8831) as part of a larger
269+
effort to support SQL databases natively in LND.
270+
271+
267272
## Code Health
268273

269274
* A code refactor that [moves all the graph related DB code out of the
@@ -292,6 +297,7 @@ The underlying functionality between those two options remain the same.
292297

293298
* Abdullahi Yunus
294299
* Alex Akselrod
300+
* Andras Banki-Horvath
295301
* Animesh Bilthare
296302
* Boris Nagaev
297303
* Carla Kirk-Cohen

go.mod

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ require (
138138
github.com/opencontainers/image-spec v1.0.2 // indirect
139139
github.com/opencontainers/runc v1.1.12 // indirect
140140
github.com/ory/dockertest/v3 v3.10.0 // indirect
141-
github.com/pmezard/go-difflib v1.0.0 // indirect
141+
github.com/pmezard/go-difflib v1.0.0
142142
github.com/prometheus/client_model v0.2.0 // indirect
143143
github.com/prometheus/common v0.26.0 // indirect
144144
github.com/prometheus/procfs v0.6.0 // indirect
@@ -207,6 +207,10 @@ replace github.com/gogo/protobuf => github.com/gogo/protobuf v1.3.2
207207
// allows us to specify that as an option.
208208
replace google.golang.org/protobuf => github.com/lightninglabs/protobuf-go-hex-display v1.30.0-hex-display
209209

210+
// Temporary replace until https://github.com/lightningnetwork/lnd/pull/8831 is
211+
// merged.
212+
replace github.com/lightningnetwork/lnd/sqldb => ./sqldb
213+
210214
// If you change this please also update docs/INSTALL.md and GO_VERSION in
211215
// Makefile (then run `make lint` to see where else it needs to be updated as
212216
// well).

go.sum

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -464,8 +464,6 @@ github.com/lightningnetwork/lnd/kvdb v1.4.12 h1:Y0WY5Tbjyjn6eCYh068qkWur5oFtioJl
464464
github.com/lightningnetwork/lnd/kvdb v1.4.12/go.mod h1:hx9buNcxsZpZwh8m1sjTQwy2SOeBoWWOZ3RnOQkMsxI=
465465
github.com/lightningnetwork/lnd/queue v1.1.1 h1:99ovBlpM9B0FRCGYJo6RSFDlt8/vOkQQZznVb18iNMI=
466466
github.com/lightningnetwork/lnd/queue v1.1.1/go.mod h1:7A6nC1Qrm32FHuhx/mi1cieAiBZo5O6l8IBIoQxvkz4=
467-
github.com/lightningnetwork/lnd/sqldb v1.0.6 h1:LJdDSVdN33bVBIefsaJlPW9PDAm6GrXlyFucmzSJ3Ts=
468-
github.com/lightningnetwork/lnd/sqldb v1.0.6/go.mod h1:OG09zL/PHPaBJefp4HsPz2YLUJ+zIQHbpgCtLnOx8I4=
469467
github.com/lightningnetwork/lnd/ticker v1.1.1 h1:J/b6N2hibFtC7JLV77ULQp++QLtCwT6ijJlbdiZFbSM=
470468
github.com/lightningnetwork/lnd/ticker v1.1.1/go.mod h1:waPTRAAcwtu7Ji3+3k+u/xH5GHovTsCoSVpho0KDvdA=
471469
github.com/lightningnetwork/lnd/tlv v1.3.0 h1:exS/KCPEgpOgviIttfiXAPaUqw2rHQrnUOpP7HPBPiY=

invoices/invoices.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,11 @@ func (r InvoiceRef) Modifier() RefModifier {
187187
return r.refModifier
188188
}
189189

190+
// IsHashOnly returns true if the invoice ref only contains a payment hash.
191+
func (r InvoiceRef) IsHashOnly() bool {
192+
return r.payHash != nil && r.payAddr == nil && r.setID == nil
193+
}
194+
190195
// String returns a human-readable representation of an InvoiceRef.
191196
func (r InvoiceRef) String() string {
192197
var ids []string

0 commit comments

Comments
 (0)