Skip to content

Commit

Permalink
wallet: Reload watchonly and solvables wallets after migration
Browse files Browse the repository at this point in the history
When migrating, create the watchonly and solvables wallets without a
context. Then unload and reload them after migration completes, as we do
for the actual wallet.
  • Loading branch information
achow101 committed Oct 10, 2023
1 parent 7583b30 commit c171fc2
Showing 1 changed file with 46 additions and 10 deletions.
56 changes: 46 additions & 10 deletions src/wallet/wallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4079,6 +4079,10 @@ bool DoMigration(CWallet& wallet, WalletContext& context, bilingual_str& error,
DatabaseOptions options;
options.require_existing = false;
options.require_create = true;
options.require_format = DatabaseFormat::SQLITE;

WalletContext empty_context;
empty_context.args = context.args;

// Make the wallets
options.create_flags = WALLET_FLAG_DISABLE_PRIVATE_KEYS | WALLET_FLAG_BLANK_WALLET | WALLET_FLAG_DESCRIPTORS;
Expand All @@ -4094,8 +4098,14 @@ bool DoMigration(CWallet& wallet, WalletContext& context, bilingual_str& error,
DatabaseStatus status;
std::vector<bilingual_str> warnings;
std::string wallet_name = wallet.GetName() + "_watchonly";
data->watchonly_wallet = CreateWallet(context, wallet_name, std::nullopt, options, status, error, warnings);
if (status != DatabaseStatus::SUCCESS) {
std::unique_ptr<WalletDatabase> database = MakeWalletDatabase(wallet_name, options, status, error);
if (!database) {
error = strprintf(_("Wallet file creation failed: %s"), error);
return false;
}

data->watchonly_wallet = CWallet::Create(empty_context, wallet_name, std::move(database), options.create_flags, error, warnings);
if (!data->watchonly_wallet) {
error = _("Error: Failed to create new watchonly wallet");
return false;
}
Expand Down Expand Up @@ -4125,8 +4135,14 @@ bool DoMigration(CWallet& wallet, WalletContext& context, bilingual_str& error,
DatabaseStatus status;
std::vector<bilingual_str> warnings;
std::string wallet_name = wallet.GetName() + "_solvables";
data->solvable_wallet = CreateWallet(context, wallet_name, std::nullopt, options, status, error, warnings);
if (status != DatabaseStatus::SUCCESS) {
std::unique_ptr<WalletDatabase> database = MakeWalletDatabase(wallet_name, options, status, error);
if (!database) {
error = strprintf(_("Wallet file creation failed: %s"), error);
return false;
}

data->solvable_wallet = CWallet::Create(empty_context, wallet_name, std::move(database), options.create_flags, error, warnings);
if (!data->solvable_wallet) {
error = _("Error: Failed to create new watchonly wallet");
return false;
}
Expand Down Expand Up @@ -4229,21 +4245,41 @@ util::Result<MigrationResult> MigrateLegacyToDescriptor(const std::string& walle
success = DoMigration(*local_wallet, context, error, res);
}

// In case of reloading failure, we need to remember the wallet dirs to remove
std::set<fs::path> wallet_dirs;
if (success) {
// Migration successful, unload the wallet locally, then reload it.
// Migration successful, unload all wallets locally, then reload them.
assert(local_wallet.use_count() == 1);
wallet_dirs.insert(fs::PathFromString(local_wallet->GetDatabase().Filename()).parent_path());
local_wallet.reset();
res.wallet = LoadWallet(context, wallet_name, /*load_on_start=*/std::nullopt, options, status, error, warnings);
res.wallet_name = wallet_name;
} else {
success = res.wallet != nullptr;
}
if (success && res.watchonly_wallet) {
assert(res.watchonly_wallet.use_count() == 1);
std::string watchonly_wallet_name = res.watchonly_wallet->GetName();
wallet_dirs.insert(fs::PathFromString(res.watchonly_wallet->GetDatabase().Filename()).parent_path());
res.watchonly_wallet.reset();
res.watchonly_wallet = LoadWallet(context, watchonly_wallet_name, /*load_on_start=*/std::nullopt, options, status, error, warnings);
success = res.watchonly_wallet != nullptr;
}
if (success && res.solvables_wallet) {
assert(res.solvables_wallet.use_count() == 1);
std::string solvables_wallet_name = res.solvables_wallet->GetName();
wallet_dirs.insert(fs::PathFromString(res.solvables_wallet->GetDatabase().Filename()).parent_path());
res.solvables_wallet.reset();
res.solvables_wallet = LoadWallet(context, solvables_wallet_name, /*load_on_start=*/std::nullopt, options, status, error, warnings);
success = res.solvables_wallet != nullptr;
}
if (!success) {
// Migration failed, cleanup
// Copy the backup to the actual wallet dir
fs::path temp_backup_location = fsbridge::AbsPathJoin(GetWalletDir(), backup_filename);
fs::copy_file(backup_path, temp_backup_location, fs::copy_options::none);

// Remember this wallet's walletdir to remove after unloading
std::vector<fs::path> wallet_dirs;
wallet_dirs.push_back(fs::PathFromString(local_wallet->GetDatabase().Filename()).parent_path());
wallet_dirs.insert(fs::PathFromString(local_wallet->GetDatabase().Filename()).parent_path());

// Unload the wallet locally
assert(local_wallet.use_count() == 1);
Expand All @@ -4256,7 +4292,7 @@ util::Result<MigrationResult> MigrateLegacyToDescriptor(const std::string& walle

// Get the directories to remove after unloading
for (std::shared_ptr<CWallet>& w : created_wallets) {
wallet_dirs.push_back(fs::PathFromString(w->GetDatabase().Filename()).parent_path());
wallet_dirs.insert(fs::PathFromString(w->GetDatabase().Filename()).parent_path());
}

// Unload the wallets
Expand All @@ -4269,7 +4305,7 @@ util::Result<MigrationResult> MigrateLegacyToDescriptor(const std::string& walle
}

// Delete the wallet directories
for (fs::path& dir : wallet_dirs) {
for (const fs::path& dir : wallet_dirs) {
fs::remove_all(dir);
}

Expand Down

0 comments on commit c171fc2

Please sign in to comment.