Skip to content

Commit ccc72fe

Browse files
achow101fanquake
authored andcommitted
wallet: Be able to unlock the wallet for migration
Since migration reloads the wallet, the wallet will always be locked unless the passphrase is given. migratewallet can now take the passphrase in order to unlock the wallet for migration. Github-Pull: #26595 Rebased-From: 7fd125b
1 parent 50dd8b1 commit ccc72fe

File tree

4 files changed

+23
-11
lines changed

4 files changed

+23
-11
lines changed

src/wallet/rpc/wallet.cpp

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -713,6 +713,7 @@ static RPCHelpMan migratewallet()
713713
HELP_REQUIRING_PASSPHRASE,
714714
{
715715
{"wallet_name", RPCArg::Type::STR, RPCArg::DefaultHint{"the wallet name from the RPC endpoint"}, "The name of the wallet to migrate. If provided both here and in the RPC endpoint, the two must be identical."},
716+
{"passphrase", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "The wallet passphrase"},
716717
},
717718
RPCResult{
718719
RPCResult::Type::OBJ, "", "",
@@ -741,15 +742,14 @@ static RPCHelpMan migratewallet()
741742
wallet_name = request.params[0].get_str();
742743
}
743744

744-
WalletContext& context = EnsureWalletContext(request.context);
745-
{
746-
std::shared_ptr<CWallet> wallet = GetWallet(context, wallet_name);
747-
if (wallet && wallet->IsCrypted()) {
748-
throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: migratewallet on encrypted wallets is currently unsupported.");
749-
}
745+
SecureString wallet_pass;
746+
wallet_pass.reserve(100);
747+
if (!request.params[1].isNull()) {
748+
wallet_pass = std::string_view{request.params[1].get_str()};
750749
}
751750

752-
util::Result<MigrationResult> res = MigrateLegacyToDescriptor(wallet_name, context);
751+
WalletContext& context = EnsureWalletContext(request.context);
752+
util::Result<MigrationResult> res = MigrateLegacyToDescriptor(wallet_name, wallet_pass, context);
753753
if (!res) {
754754
throw JSONRPCError(RPC_WALLET_ERROR, util::ErrorString(res).original);
755755
}

src/wallet/wallet.cpp

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3767,7 +3767,7 @@ std::optional<MigrationData> CWallet::GetDescriptorsForLegacy(bilingual_str& err
37673767

37683768
std::optional<MigrationData> res = legacy_spkm->MigrateToDescriptor();
37693769
if (res == std::nullopt) {
3770-
error = _("Error: Unable to produce descriptors for this legacy wallet. Make sure the wallet is unlocked first");
3770+
error = _("Error: Unable to produce descriptors for this legacy wallet. Make sure to provide the wallet's passphrase if it is encrypted.");
37713771
return std::nullopt;
37723772
}
37733773
return res;
@@ -4057,7 +4057,7 @@ bool DoMigration(CWallet& wallet, WalletContext& context, bilingual_str& error,
40574057
return true;
40584058
}
40594059

4060-
util::Result<MigrationResult> MigrateLegacyToDescriptor(const std::string& wallet_name, WalletContext& context)
4060+
util::Result<MigrationResult> MigrateLegacyToDescriptor(const std::string& wallet_name, const SecureString& passphrase, WalletContext& context)
40614061
{
40624062
MigrationResult res;
40634063
bilingual_str error;
@@ -4107,6 +4107,19 @@ util::Result<MigrationResult> MigrateLegacyToDescriptor(const std::string& walle
41074107
{
41084108
LOCK(local_wallet->cs_wallet);
41094109

4110+
// Unlock the wallet if needed
4111+
if (local_wallet->IsLocked() && !local_wallet->Unlock(passphrase)) {
4112+
if (passphrase.find('\0') == std::string::npos) {
4113+
return util::Error{Untranslated("Error: Wallet decryption failed, the wallet passphrase was not provided or was incorrect.")};
4114+
} else {
4115+
return util::Error{Untranslated("Error: Wallet decryption failed, the wallet passphrase entered was incorrect. "
4116+
"The passphrase contains a null character (ie - a zero byte). "
4117+
"If this passphrase was set with a version of this software prior to 25.0, "
4118+
"please try again with only the characters up to — but not including — "
4119+
"the first null character.")};
4120+
}
4121+
}
4122+
41104123
// First change to using SQLite
41114124
if (!local_wallet->MigrateToSQLite(error)) return util::Error{error};
41124125

src/wallet/wallet.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1006,7 +1006,7 @@ struct MigrationResult {
10061006
};
10071007

10081008
//! Do all steps to migrate a legacy wallet to a descriptor wallet
1009-
util::Result<MigrationResult> MigrateLegacyToDescriptor(const std::string& wallet_name, WalletContext& context);
1009+
util::Result<MigrationResult> MigrateLegacyToDescriptor(const std::string& wallet_name, const SecureString& passphrase, WalletContext& context);
10101010
} // namespace wallet
10111011

10121012
#endif // BITCOIN_WALLET_WALLET_H

test/functional/wallet_migration.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -406,7 +406,6 @@ def test_encrypted(self):
406406

407407
wallet.encryptwallet("pass")
408408

409-
assert_raises_rpc_error(-15, "Error: migratewallet on encrypted wallets is currently unsupported.", wallet.migratewallet)
410409
# TODO: Fix migratewallet so that we can actually migrate encrypted wallets
411410

412411
def run_test(self):

0 commit comments

Comments
 (0)