Skip to content

Commit

Permalink
wallet: Allow MigrateLegacyToDescriptor to take a wallet name
Browse files Browse the repository at this point in the history
An overload of MigrateLegacyToDescriptor is added which takes the wallet
name. The original that took a wallet pointer is still available, it
just gets the name, closes the wallet, and calls the new overload.

Github-Pull: #26595
Reabsed-From: dbfa345
  • Loading branch information
achow101 authored and fanquake committed Feb 27, 2023
1 parent ab3bd45 commit 648b062
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 21 deletions.
14 changes: 9 additions & 5 deletions src/wallet/rpc/wallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -727,16 +727,20 @@ static RPCHelpMan migratewallet()
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
std::shared_ptr<CWallet> wallet = GetWalletForJSONRPCRequest(request);
if (!wallet) return NullUniValue;
std::string wallet_name;
{
std::shared_ptr<CWallet> wallet = GetWalletForJSONRPCRequest(request);
if (!wallet) return NullUniValue;

if (wallet->IsCrypted()) {
throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: migratewallet on encrypted wallets is currently unsupported.");
if (wallet->IsCrypted()) {
throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: migratewallet on encrypted wallets is currently unsupported.");
}
wallet_name = wallet->GetName();
}

WalletContext& context = EnsureWalletContext(request.context);

util::Result<MigrationResult> res = MigrateLegacyToDescriptor(std::move(wallet), context);
util::Result<MigrationResult> res = MigrateLegacyToDescriptor(wallet_name, context);
if (!res) {
throw JSONRPCError(RPC_WALLET_ERROR, util::ErrorString(res).original);
}
Expand Down
37 changes: 22 additions & 15 deletions src/wallet/wallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4057,27 +4057,19 @@ bool DoMigration(CWallet& wallet, WalletContext& context, bilingual_str& error,
return true;
}

util::Result<MigrationResult> MigrateLegacyToDescriptor(std::shared_ptr<CWallet>&& wallet, WalletContext& context)
util::Result<MigrationResult> MigrateLegacyToDescriptor(const std::string& wallet_name, WalletContext& context)
{
MigrationResult res;
bilingual_str error;
std::vector<bilingual_str> warnings;

// Make a backup of the DB
std::string wallet_name = wallet->GetName();
fs::path this_wallet_dir = fs::absolute(fs::PathFromString(wallet->GetDatabase().Filename())).parent_path();
fs::path backup_filename = fs::PathFromString(strprintf("%s-%d.legacy.bak", wallet_name, GetTime()));
fs::path backup_path = this_wallet_dir / backup_filename;
if (!wallet->BackupWallet(fs::PathToString(backup_path))) {
return util::Error{_("Error: Unable to make a backup of your wallet")};
}
res.backup_path = backup_path;

// Unload the wallet so that nothing else tries to use it while we're changing it
if (!RemoveWallet(context, wallet, /*load_on_start=*/std::nullopt, warnings)) {
return util::Error{_("Unable to unload the wallet before migrating")};
// If the wallet is still loaded, unload it so that nothing else tries to use it while we're changing it
if (auto wallet = GetWallet(context, wallet_name)) {
if (!RemoveWallet(context, wallet, /*load_on_start=*/std::nullopt, warnings)) {
return util::Error{_("Unable to unload the wallet before migrating")};
}
UnloadWallet(std::move(wallet));
}
UnloadWallet(std::move(wallet));

// Load the wallet but only in the context of this function.
// No signals should be connected nor should anything else be aware of this wallet
Expand All @@ -4091,11 +4083,26 @@ util::Result<MigrationResult> MigrateLegacyToDescriptor(std::shared_ptr<CWallet>
return util::Error{Untranslated("Wallet file verification failed.") + Untranslated(" ") + error};
}

// Make the local wallet
std::shared_ptr<CWallet> local_wallet = CWallet::Create(empty_context, wallet_name, std::move(database), options.create_flags, error, warnings);
if (!local_wallet) {
return util::Error{Untranslated("Wallet loading failed.") + Untranslated(" ") + error};
}

// Before anything else, check if there is something to migrate.
if (!local_wallet->GetLegacyScriptPubKeyMan()) {
return util::Error{_("Error: This wallet is already a descriptor wallet")};
}

// Make a backup of the DB
fs::path this_wallet_dir = fs::absolute(fs::PathFromString(local_wallet->GetDatabase().Filename())).parent_path();
fs::path backup_filename = fs::PathFromString(strprintf("%s-%d.legacy.bak", wallet_name, GetTime()));
fs::path backup_path = this_wallet_dir / backup_filename;
if (!local_wallet->BackupWallet(fs::PathToString(backup_path))) {
return util::Error{_("Error: Unable to make a backup of your wallet")};
}
res.backup_path = backup_path;

bool success = false;
{
LOCK(local_wallet->cs_wallet);
Expand Down
2 changes: 1 addition & 1 deletion src/wallet/wallet.h
Original file line number Diff line number Diff line change
Expand Up @@ -1006,7 +1006,7 @@ struct MigrationResult {
};

//! Do all steps to migrate a legacy wallet to a descriptor wallet
util::Result<MigrationResult> MigrateLegacyToDescriptor(std::shared_ptr<CWallet>&& wallet, WalletContext& context);
util::Result<MigrationResult> MigrateLegacyToDescriptor(const std::string& wallet_name, WalletContext& context);
} // namespace wallet

#endif // BITCOIN_WALLET_WALLET_H

0 comments on commit 648b062

Please sign in to comment.