From 269825732018fd8388056a6c89c656623f44faca Mon Sep 17 00:00:00 2001 From: 0xfandom Date: Fri, 1 May 2026 16:09:41 +0530 Subject: [PATCH] migrate-db: warn loudly before writing irreversible tombstones After a successful migration lndinit writes a tombstone marker into every source bbolt file. From that point lnd refuses to open those files, which is fine when the destination backend works but turns into unrecoverable data loss when the lnd binary that will run against the new backend was not compiled with the matching build tag (e.g. kvdb_sqlite). The user is left with tombstoned bbolt files and a destination backend that lnd cannot read. This is the "at minimum" mitigation requested in the issue: print a loud, multi-line WARN banner at the start of migrate-db that names the destination backend and tells the operator to confirm both that they have a backup of the bbolt files and that the target lnd binary supports the destination backend. A second per-DB WARN line is also printed immediately before each tombstone write so it shows up next to the affected prefix in the log. This is intentionally a logging-only change: no new flags, no behavioral or interface differences for existing callers. Pre-flight build-tag detection (option 1) and a deferred --finalize step (option 3) are real fixes worth their own design discussion and are not part of this PR. Refs #81 --- cmd_migrate_db.go | 48 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/cmd_migrate_db.go b/cmd_migrate_db.go index 9ec30a8..4a9326b 100644 --- a/cmd_migrate_db.go +++ b/cmd_migrate_db.go @@ -193,6 +193,15 @@ func (x *migrateDBCommand) Execute(_ []string) error { return fmt.Errorf("invalid database configuration: %w", err) } + // Print a loud warning before doing any work. A successful migration + // ends by writing a tombstone marker into every source bbolt file, + // after which lnd refuses to open them. If the lnd binary that will + // run against the destination DB was not compiled with the matching + // build tag (e.g. kvdb_sqlite, kvdb_postgres), the only way back to a + // working node is restoring the bbolt files from a backup taken + // BEFORE this command runs. + logTombstoneWarning(x.Dest.Backend) + // We keep track of the DBs that we have migrated. migratedDBs := []string{} @@ -524,6 +533,11 @@ func (x *migrateDBCommand) Execute(_ []string) error { return err } + logger.Warnf("Writing IRREVERSIBLE tombstone marker on "+ + "source DB with prefix `%s`. After this point lnd "+ + "will refuse to open this bbolt file; only a "+ + "pre-migration backup can restore it.", prefix) + if err := addMarker(srcDb, channeldb.TombstoneKey); err != nil { return err } @@ -998,3 +1012,37 @@ func getContext() context.Context { }() return ctxc } + +// logTombstoneWarning prints a multi-line WARN banner explaining that the +// migration will write irreversible tombstone markers into every source bbolt +// file. It is printed before any work happens so operators reviewing logs (or +// piping `lndinit migrate-db` output through tooling) cannot miss it. +func logTombstoneWarning(destBackend string) { + banner := []string{ + "################################################################", + "# #", + "# WARNING: lndinit migrate-db will write IRREVERSIBLE #", + "# tombstone markers into every source bbolt database file #", + "# after a successful migration. Once tombstoned, lnd will #", + "# refuse to open the bbolt files with the error: #", + "# #", + "# refusing to use db, it was marked with a tombstone #", + "# after successful data migration #", + "# #", + "# Before continuing, please confirm BOTH of the following: #", + "# #", + "# 1. You have a backup of every bbolt source DB file #", + "# (channel.db, wallet.db, macaroons.db, etc.). #", + "# 2. The lnd binary that will run against the destination #", + fmt.Sprintf("# backend was compiled with the %-23s#", destBackend+" build tag."), + "# #", + "# Without (2), lnd will fail on startup with `unknown #", + "# database type` and the only recovery path is restoring #", + "# the bbolt files from the backup taken in (1). #", + "# #", + "################################################################", + } + for _, line := range banner { + logger.Warn(line) + } +}