fix(migrate): correct fund-adjacent migrate-to-seed bugs (W3-1, W3-2, W3-4)

Migrate-to-seed (legacy -> mnemonic wallet) moves real funds; three correctness fixes:

- W3-1 (High): beginAdoptSeedWallet swapped a hardcoded datadir/wallet.dat instead of the
  ACTIVE wallet file. With a non-default active wallet (e.g. wallet-2.dat) it installed the
  swept seed wallet into an unloaded wallet.dat and left the daemon reloading the emptied
  legacy wallet — swept funds only recoverable via the seed phrase. Now swaps
  datadir + "/" + getActiveWalletFile(), captured on the main thread (switching is blocked
  during migration, so no race).

- W3-2 (High): SeedWalletCreator::create() ran remove_all(<config>/seed-migrate)
  unconditionally at the start, so a prior migration that swept funds into the temp wallet
  but was abandoned/crashed before adopting would have that fund-bearing wallet destroyed.
  It now refuses (with a clear message) when DRAGONX/wallet.dat already exists — a completed
  migration removes the dir on adopt, so a leftover means an unfinished one.

- W3-4 (Med): switchToWallet blocked switching only while the migration dialog was open;
  closing it via "Later" mid-migration dropped the guard. Now also blocks while
  getSeedMigrationPending().

Build-clean; ctest 1/1. Remaining P1-A: W3-3 (persist the sweep opid). See
docs/wallet-hardening.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-08-02 14:53:58 -05:00
parent 8c12b27c0a
commit 03c1b63e03
3 changed files with 28 additions and 4 deletions

View File

@@ -54,6 +54,16 @@ SeedWalletResult SeedWalletCreator::create(bool keepDatadir,
// RPC port. So the wallet lives in <base>/DRAGONX; `base` is the migration root we clean up.
const std::string base = util::Platform::getConfigDir() + "/seed-migrate";
const std::string dataDir = base + "/DRAGONX";
// W3-2: never blindly wipe a pre-existing temp seed wallet. A prior migration that swept funds into
// it but was abandoned or crashed before adopting would otherwise have its (fund-bearing) wallet
// destroyed here. A completed migration removes this dir on adopt, so a leftover means an unfinished
// one — refuse and point the user at it rather than silently destroying it.
if (fs::exists(dataDir + "/wallet.dat")) {
r.error = "A previous seed migration looks unfinished — its temporary wallet is still at\n" + base +
"\nResume or cancel it first. If you are certain its funds are already in your main "
"wallet, delete that folder and try again.";
return r;
}
fs::remove_all(base, ec);
fs::create_directories(dataDir, ec);
if (ec) { r.error = "Could not create the temporary wallet directory."; return r; }