Skip to content

Commit 7fd125b

Browse files
committed
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.
1 parent 6bdbc5f commit 7fd125b

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
@@ -724,6 +724,7 @@ static RPCHelpMan migratewallet()
724724
HELP_REQUIRING_PASSPHRASE,
725725
{
726726
{"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."},
727+
{"passphrase", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "The wallet passphrase"},
727728
},
728729
RPCResult{
729730
RPCResult::Type::OBJ, "", "",
@@ -752,15 +753,14 @@ static RPCHelpMan migratewallet()
752753
wallet_name = request.params[0].get_str();
753754
}
754755

755-
WalletContext& context = EnsureWalletContext(request.context);
756-
{
757-
std::shared_ptr<CWallet> wallet = GetWallet(context, wallet_name);
758-
if (wallet && wallet->IsCrypted()) {
759-
throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: migratewallet on encrypted wallets is currently unsupported.");
760-
}
756+
SecureString wallet_pass;
757+
wallet_pass.reserve(100);
758+
if (!request.params[1].isNull()) {
759+
wallet_pass = std::string_view{request.params[1].get_str()};
761760
}
762761

763-
util::Result<MigrationResult> res = MigrateLegacyToDescriptor(wallet_name, context);
762+
WalletContext& context = EnsureWalletContext(request.context);
763+
util::Result<MigrationResult> res = MigrateLegacyToDescriptor(wallet_name, wallet_pass, context);
764764
if (!res) {
765765
throw JSONRPCError(RPC_WALLET_ERROR, util::ErrorString(res).original);
766766
}

src/wallet/wallet.cpp

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

38763876
std::optional<MigrationData> res = legacy_spkm->MigrateToDescriptor();
38773877
if (res == std::nullopt) {
3878-
error = _("Error: Unable to produce descriptors for this legacy wallet. Make sure the wallet is unlocked first");
3878+
error = _("Error: Unable to produce descriptors for this legacy wallet. Make sure to provide the wallet's passphrase if it is encrypted.");
38793879
return std::nullopt;
38803880
}
38813881
return res;
@@ -4165,7 +4165,7 @@ bool DoMigration(CWallet& wallet, WalletContext& context, bilingual_str& error,
41654165
return true;
41664166
}
41674167

4168-
util::Result<MigrationResult> MigrateLegacyToDescriptor(const std::string& wallet_name, WalletContext& context)
4168+
util::Result<MigrationResult> MigrateLegacyToDescriptor(const std::string& wallet_name, const SecureString& passphrase, WalletContext& context)
41694169
{
41704170
MigrationResult res;
41714171
bilingual_str error;
@@ -4215,6 +4215,19 @@ util::Result<MigrationResult> MigrateLegacyToDescriptor(const std::string& walle
42154215
{
42164216
LOCK(local_wallet->cs_wallet);
42174217

4218+
// Unlock the wallet if needed
4219+
if (local_wallet->IsLocked() && !local_wallet->Unlock(passphrase)) {
4220+
if (passphrase.find('\0') == std::string::npos) {
4221+
return util::Error{Untranslated("Error: Wallet decryption failed, the wallet passphrase was not provided or was incorrect.")};
4222+
} else {
4223+
return util::Error{Untranslated("Error: Wallet decryption failed, the wallet passphrase entered was incorrect. "
4224+
"The passphrase contains a null character (ie - a zero byte). "
4225+
"If this passphrase was set with a version of this software prior to 25.0, "
4226+
"please try again with only the characters up to — but not including — "
4227+
"the first null character.")};
4228+
}
4229+
}
4230+
42184231
// First change to using SQLite
42194232
if (!local_wallet->MigrateToSQLite(error)) return util::Error{error};
42204233

src/wallet/wallet.h

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

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

10131013
#endif // BITCOIN_WALLET_WALLET_H

test/functional/wallet_migration.py

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

404404
wallet.encryptwallet("pass")
405405

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

409408
def run_test(self):

0 commit comments

Comments
 (0)