Skip to content

Commit 69c37f4

Browse files
committed
rpc: make sure upgradetohd always has the passphrase for UpgradeToHD
earlier it was possible to make it all the way to `EncryptSecret` without actually having the passphrase in hand until being told off by `CCrypter::SetKey`, we should avoid that. also, let's get rid of checks that `UpgradeToHD` is now taking responsibility for. no point in checking if the wallet is unlocked as it has no bearing on your ability to upgrade the wallet.
1 parent 619b640 commit 69c37f4

File tree

3 files changed

+18
-12
lines changed

3 files changed

+18
-12
lines changed

src/wallet/rpcwallet.cpp

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2779,11 +2779,13 @@ static RPCHelpMan upgradetohd()
27792779
{
27802780
return RPCHelpMan{"upgradetohd",
27812781
"\nUpgrades non-HD wallets to HD.\n"
2782+
"\nIf your wallet is encrypted, the wallet passphrase must be supplied. Supplying an incorrect"
2783+
"\npassphrase may result in your wallet getting locked.\n"
27822784
"\nWarning: You will need to make a new backup of your wallet after setting the HD wallet mnemonic.\n",
27832785
{
27842786
{"mnemonic", RPCArg::Type::STR, /* default */ "", "Mnemonic as defined in BIP39 to use for the new HD wallet. Use an empty string \"\" to generate a new random mnemonic."},
27852787
{"mnemonicpassphrase", RPCArg::Type::STR, /* default */ "", "Optional mnemonic passphrase as defined in BIP39"},
2786-
{"walletpassphrase", RPCArg::Type::STR, /* default */ "", "If your wallet is encrypted you must have your wallet passphrase here. If your wallet is not encrypted specifying wallet passphrase will trigger wallet encryption."},
2788+
{"walletpassphrase", RPCArg::Type::STR, /* default */ "", "If your wallet is encrypted you must have your wallet passphrase here. If your wallet is not encrypted, specifying wallet passphrase will trigger wallet encryption."},
27872789
{"rescan", RPCArg::Type::BOOL, /* default */ "false if mnemonic is empty", "Whether to rescan the blockchain for missing transactions or not"},
27882790
},
27892791
RPCResult{
@@ -2793,6 +2795,7 @@ static RPCHelpMan upgradetohd()
27932795
HelpExampleCli("upgradetohd", "")
27942796
+ HelpExampleCli("upgradetohd", "\"mnemonicword1 ... mnemonicwordN\"")
27952797
+ HelpExampleCli("upgradetohd", "\"mnemonicword1 ... mnemonicwordN\" \"mnemonicpassphrase\"")
2798+
+ HelpExampleCli("upgradetohd", "\"mnemonicword1 ... mnemonicwordN\" \"\" \"walletpassphrase\"")
27962799
+ HelpExampleCli("upgradetohd", "\"mnemonicword1 ... mnemonicwordN\" \"mnemonicpassphrase\" \"walletpassphrase\"")
27972800
},
27982801
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
@@ -2803,17 +2806,17 @@ static RPCHelpMan upgradetohd()
28032806
bool generate_mnemonic = request.params[0].isNull() || request.params[0].get_str().empty();
28042807
SecureString secureWalletPassphrase;
28052808
secureWalletPassphrase.reserve(100);
2806-
// TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
2807-
// Alternately, find a way to make request.params[0] mlock()'d to begin with.
2808-
if (!request.params[2].isNull()) {
2809-
secureWalletPassphrase = request.params[2].get_str().c_str();
2810-
if (!pwallet->Unlock(secureWalletPassphrase)) {
2811-
throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "The wallet passphrase entered was incorrect");
2809+
2810+
if (request.params[2].isNull()) {
2811+
if (pwallet->IsCrypted()) {
2812+
throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Wallet encrypted but passphrase not supplied to RPC.");
28122813
}
2814+
} else {
2815+
// TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
2816+
// Alternately, find a way to make request.params[0] mlock()'d to begin with.
2817+
secureWalletPassphrase = request.params[2].get_str().c_str();
28132818
}
28142819

2815-
EnsureWalletIsUnlocked(pwallet.get());
2816-
28172820
SecureString secureMnemonic;
28182821
secureMnemonic.reserve(256);
28192822
if (!generate_mnemonic) {
@@ -2825,6 +2828,7 @@ static RPCHelpMan upgradetohd()
28252828
if (!request.params[1].isNull()) {
28262829
secureMnemonicPassphrase = request.params[1].get_str().c_str();
28272830
}
2831+
28282832
// TODO: breaking changes kept for v21!
28292833
// instead upgradetohd let's use more straightforward 'sethdseed'
28302834
constexpr bool is_v21 = false;

src/wallet/wallet.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5683,7 +5683,9 @@ bool CWallet::GenerateNewHDChain(const SecureString& secureMnemonic, const Secur
56835683

56845684
// We got a gibberish key...
56855685
if (vMasterKey.empty()) {
5686-
throw std::runtime_error(strprintf("%s: supplied incorrect passphrase", __func__));
5686+
// Mimicking the error message of RPC_WALLET_PASSPHRASE_INCORRECT as it's possible
5687+
// that the user may see this error when interacting with the upgradetohd RPC
5688+
throw std::runtime_error("Error: The wallet passphrase entered was incorrect");
56875689
}
56885690

56895691
spk_man->GenerateNewHDChain(secureMnemonic, secureMnemonicPassphrase, vMasterKey);

test/functional/wallet_upgradetohd.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -190,8 +190,8 @@ def run_test(self):
190190
node.stop()
191191
node.wait_until_stopped()
192192
self.start_node(0, extra_args=['-rescan'])
193-
assert_raises_rpc_error(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.", node.upgradetohd, mnemonic)
194-
assert_raises_rpc_error(-14, "The wallet passphrase entered was incorrect", node.upgradetohd, mnemonic, "", "wrongpass")
193+
assert_raises_rpc_error(-13, "Error: Wallet encrypted but passphrase not supplied to RPC.", node.upgradetohd, mnemonic)
194+
assert_raises_rpc_error(-1, "Error: The wallet passphrase entered was incorrect", node.upgradetohd, mnemonic, "", "wrongpass")
195195
assert node.upgradetohd(mnemonic, "", walletpass)
196196
assert_raises_rpc_error(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.", node.dumphdinfo)
197197
node.walletpassphrase(walletpass, 100)

0 commit comments

Comments
 (0)