From 8d20e2a23be9f950c80ca9e2add927fbcf2641cd Mon Sep 17 00:00:00 2001 From: Andras Banki-Horvath Date: Tue, 17 Sep 2024 15:18:12 +0200 Subject: [PATCH] lnd: run invoice migration on startup This commit runs the invoice migration if the user has a KV SQL backend configured. --- config_builder.go | 95 ++++++++++++++++++++--------------- invoices/testdata/channel.db | Bin 1048576 -> 1048576 bytes lncfg/db.go | 5 +- sample-lnd.conf | 3 ++ sqldb/migrations.go | 9 ++++ 5 files changed, 71 insertions(+), 41 deletions(-) diff --git a/config_builder.go b/config_builder.go index b5e19e5dc..45a923e05 100644 --- a/config_builder.go +++ b/config_builder.go @@ -51,6 +51,7 @@ import ( "github.com/lightningnetwork/lnd/rpcperms" "github.com/lightningnetwork/lnd/signal" "github.com/lightningnetwork/lnd/sqldb" + "github.com/lightningnetwork/lnd/sqldb/sqlc" "github.com/lightningnetwork/lnd/sweep" "github.com/lightningnetwork/lnd/walletunlocker" "github.com/lightningnetwork/lnd/watchtower" @@ -60,6 +61,16 @@ import ( "gopkg.in/macaroon-bakery.v2/bakery" ) +const ( + // invoiceMigrationBatchSize is the number of invoices that will be + // migrated in a single batch. + invoiceMigrationBatchSize = 1000 + + // invoiceMigration is the version of the migration that will be used to + // migrate invoices from the kvdb to the sql database. + invoiceMigration = 7 +) + // GrpcRegistrar is an interface that must be satisfied by an external subserver // that wants to be able to register its own gRPC server onto lnd's main // grpc.Server instance. @@ -1038,7 +1049,7 @@ func (d *DefaultDatabaseBuilder) BuildDatabase( if err != nil { cleanUp() - err := fmt.Errorf("unable to open graph DB: %w", err) + err = fmt.Errorf("unable to open graph DB: %w", err) d.logger.Error(err) return nil, nil, err @@ -1072,65 +1083,69 @@ func (d *DefaultDatabaseBuilder) BuildDatabase( case err != nil: cleanUp() - err := fmt.Errorf("unable to open graph DB: %w", err) + err = fmt.Errorf("unable to open graph DB: %w", err) d.logger.Error(err) return nil, nil, err } - // Instantiate a native SQL invoice store if the flag is set. + // Instantiate a native SQL store if the flag is set. if d.cfg.DB.UseNativeSQL { + migrations := sqldb.GetMigrations() + + // If the user has not explicitly disabled the SQL invoice + // migration, attach the custom migration function to invoice + // migration (version 7). Even if this custom migration is + // disabled, the regular native SQL store migrations will still + // run. If the database version is already above this custom + // migration's version (7), it will be skipped permanently, + // regardless of the flag. + if !d.cfg.DB.SkipSQLInvoiceMigration { + migrationFn := func(tx *sqlc.Queries) error { + return invoices.MigrateInvoicesToSQL( + ctx, dbs.ChanStateDB.Backend, + dbs.ChanStateDB, tx, + invoiceMigrationBatchSize, + ) + } + + // Make sure we attach the custom migration function to + // the correct migration version. + for i := 0; i < len(migrations); i++ { + if migrations[i].Version != invoiceMigration { + continue + } + + migrations[i].MigrationFn = migrationFn + } + } + // We need to apply all migrations to the native SQL store // before we can use it. - err := dbs.NativeSQLStore.ApplyAllMigrations( - ctx, sqldb.GetMigrations(), - ) + err = dbs.NativeSQLStore.ApplyAllMigrations(ctx, migrations) if err != nil { cleanUp() - err := fmt.Errorf("unable to apply migrations: %w", err) - d.logger.Error(err) - - return nil, nil, err - } - - // KV invoice db resides in the same database as the channel - // state DB. Let's query the database to see if we have any - // invoices there. If we do, we won't allow the user to start - // lnd with native SQL enabled, as we don't currently migrate - // the invoices to the new database schema. - invoiceSlice, err := dbs.ChanStateDB.QueryInvoices( - ctx, invoices.InvoiceQuery{ - NumMaxInvoices: 1, - }, - ) - if err != nil { - cleanUp() - d.logger.Errorf("Unable to query KV invoice DB: %v", - err) - - return nil, nil, err - } - - if len(invoiceSlice.Invoices) > 0 { - cleanUp() - err := fmt.Errorf("found invoices in the KV invoice " + - "DB, migration to native SQL is not yet " + - "supported") + err = fmt.Errorf("faild to run migrations for the "+ + "native SQL store: %w", err) d.logger.Error(err) return nil, nil, err } + // With the DB ready and migrations applied, we can now create + // the base DB and transaction executor for the native SQL + // invoice store. baseDB := dbs.NativeSQLStore.GetBaseDB() executor := sqldb.NewTransactionExecutor( - baseDB, - func(tx *sql.Tx) invoices.SQLInvoiceQueries { + baseDB, func(tx *sql.Tx) invoices.SQLInvoiceQueries { return baseDB.WithTx(tx) }, ) - dbs.InvoiceDB = invoices.NewSQLStore( + sqlInvoiceDB := invoices.NewSQLStore( executor, clock.NewDefaultClock(), ) + + dbs.InvoiceDB = sqlInvoiceDB } else { dbs.InvoiceDB = dbs.ChanStateDB } @@ -1143,7 +1158,7 @@ func (d *DefaultDatabaseBuilder) BuildDatabase( if err != nil { cleanUp() - err := fmt.Errorf("unable to open %s database: %w", + err = fmt.Errorf("unable to open %s database: %w", lncfg.NSTowerClientDB, err) d.logger.Error(err) return nil, nil, err @@ -1158,7 +1173,7 @@ func (d *DefaultDatabaseBuilder) BuildDatabase( if err != nil { cleanUp() - err := fmt.Errorf("unable to open %s database: %w", + err = fmt.Errorf("unable to open %s database: %w", lncfg.NSTowerServerDB, err) d.logger.Error(err) return nil, nil, err diff --git a/invoices/testdata/channel.db b/invoices/testdata/channel.db index 78741eae9c63a6284b389e9c6b14f71fa4d32aa9..69397f529dd11a2bcab9d1fa8e64e78d18b0d29b 100644 GIT binary patch delta 406 zcmZo@aA;_7n4rL@I8jkvK!cG14C>x)Gc9iXY`8ISz5V3>_KFZ$b*SvcEfaR+D6fbI z$xb&o!^F9nqk*YmGS>kj_<(c=l)o3q7X`8vp!`QbJ`V$fGu(i85CMh|r~*5n?c6~22`HaY zgn%jvt$}Y@1AhYmEhkHc delta 153 zcmZo@aA;_7n4rL@Fi}xnK!uS34EpDMi%e9}jN2Hv-hT3bdqs$>DpdBDgWbW