aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Chow <github@achow101.com>2022-11-28 17:10:44 -0500
committerfanquake <fanquake@gmail.com>2023-02-27 14:14:14 +0000
commitccc72fecd7287471bf8c3858a4e6c2ddadb64863 (patch)
treef37aabf85dec091f51e2c51fed6d5736842a94f2
parent50dd8b13dfc070b550680617e76eff1c09af3a58 (diff)
downloadbitcoin-ccc72fecd7287471bf8c3858a4e6c2ddadb64863.tar.xz
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: 7fd125b27d48e410509f3009e2eb9fa5cd6729dd
-rw-r--r--src/wallet/rpc/wallet.cpp14
-rw-r--r--src/wallet/wallet.cpp17
-rw-r--r--src/wallet/wallet.h2
-rwxr-xr-xtest/functional/wallet_migration.py1
4 files changed, 23 insertions, 11 deletions
diff --git a/src/wallet/rpc/wallet.cpp b/src/wallet/rpc/wallet.cpp
index 2773a7ed59..e8743cd2f6 100644
--- a/src/wallet/rpc/wallet.cpp
+++ b/src/wallet/rpc/wallet.cpp
@@ -713,6 +713,7 @@ static RPCHelpMan migratewallet()
HELP_REQUIRING_PASSPHRASE,
{
{"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."},
+ {"passphrase", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "The wallet passphrase"},
},
RPCResult{
RPCResult::Type::OBJ, "", "",
@@ -741,15 +742,14 @@ static RPCHelpMan migratewallet()
wallet_name = request.params[0].get_str();
}
- WalletContext& context = EnsureWalletContext(request.context);
- {
- std::shared_ptr<CWallet> wallet = GetWallet(context, wallet_name);
- if (wallet && wallet->IsCrypted()) {
- throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: migratewallet on encrypted wallets is currently unsupported.");
- }
+ SecureString wallet_pass;
+ wallet_pass.reserve(100);
+ if (!request.params[1].isNull()) {
+ wallet_pass = std::string_view{request.params[1].get_str()};
}
- util::Result<MigrationResult> res = MigrateLegacyToDescriptor(wallet_name, context);
+ WalletContext& context = EnsureWalletContext(request.context);
+ util::Result<MigrationResult> res = MigrateLegacyToDescriptor(wallet_name, wallet_pass, context);
if (!res) {
throw JSONRPCError(RPC_WALLET_ERROR, util::ErrorString(res).original);
}
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index e5f730f71b..b957055c0f 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -3767,7 +3767,7 @@ std::optional<MigrationData> CWallet::GetDescriptorsForLegacy(bilingual_str& err
std::optional<MigrationData> res = legacy_spkm->MigrateToDescriptor();
if (res == std::nullopt) {
- error = _("Error: Unable to produce descriptors for this legacy wallet. Make sure the wallet is unlocked first");
+ error = _("Error: Unable to produce descriptors for this legacy wallet. Make sure to provide the wallet's passphrase if it is encrypted.");
return std::nullopt;
}
return res;
@@ -4057,7 +4057,7 @@ bool DoMigration(CWallet& wallet, WalletContext& context, bilingual_str& error,
return true;
}
-util::Result<MigrationResult> MigrateLegacyToDescriptor(const std::string& wallet_name, WalletContext& context)
+util::Result<MigrationResult> MigrateLegacyToDescriptor(const std::string& wallet_name, const SecureString& passphrase, WalletContext& context)
{
MigrationResult res;
bilingual_str error;
@@ -4107,6 +4107,19 @@ util::Result<MigrationResult> MigrateLegacyToDescriptor(const std::string& walle
{
LOCK(local_wallet->cs_wallet);
+ // Unlock the wallet if needed
+ if (local_wallet->IsLocked() && !local_wallet->Unlock(passphrase)) {
+ if (passphrase.find('\0') == std::string::npos) {
+ return util::Error{Untranslated("Error: Wallet decryption failed, the wallet passphrase was not provided or was incorrect.")};
+ } else {
+ return util::Error{Untranslated("Error: Wallet decryption failed, the wallet passphrase entered was incorrect. "
+ "The passphrase contains a null character (ie - a zero byte). "
+ "If this passphrase was set with a version of this software prior to 25.0, "
+ "please try again with only the characters up to — but not including — "
+ "the first null character.")};
+ }
+ }
+
// First change to using SQLite
if (!local_wallet->MigrateToSQLite(error)) return util::Error{error};
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index 405e531500..637e9e6d41 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -1006,7 +1006,7 @@ struct MigrationResult {
};
//! Do all steps to migrate a legacy wallet to a descriptor wallet
-util::Result<MigrationResult> MigrateLegacyToDescriptor(const std::string& wallet_name, WalletContext& context);
+util::Result<MigrationResult> MigrateLegacyToDescriptor(const std::string& wallet_name, const SecureString& passphrase, WalletContext& context);
} // namespace wallet
#endif // BITCOIN_WALLET_WALLET_H
diff --git a/test/functional/wallet_migration.py b/test/functional/wallet_migration.py
index 2af8b664b3..a70a3e7541 100755
--- a/test/functional/wallet_migration.py
+++ b/test/functional/wallet_migration.py
@@ -406,7 +406,6 @@ class WalletMigrationTest(BitcoinTestFramework):
wallet.encryptwallet("pass")
- assert_raises_rpc_error(-15, "Error: migratewallet on encrypted wallets is currently unsupported.", wallet.migratewallet)
# TODO: Fix migratewallet so that we can actually migrate encrypted wallets
def run_test(self):