Skip to content

Commit

Permalink
merge bitcoin#15761: Replace -upgradewallet startup option with upgra…
Browse files Browse the repository at this point in the history
…dewallet RPC
  • Loading branch information
kwvg authored and PastaPastaPasta committed Feb 17, 2023
1 parent 3588195 commit 5f10b3e
Show file tree
Hide file tree
Showing 6 changed files with 64 additions and 46 deletions.
1 change: 1 addition & 0 deletions src/rpc/client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "getspecialtxes", 3, "skip" },
{ "getspecialtxes", 4, "verbosity" },
{ "disconnectnode", 1, "nodeid" },
{ "upgradewallet", 0, "version" },
// Echo with conversion (For testing only)
{ "echojson", 0, "arg0" },
{ "echojson", 1, "arg1" },
Expand Down
9 changes: 0 additions & 9 deletions src/wallet/init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@ void WalletInit::AddWalletOptions(ArgsManager& argsman) const
argsman.AddArg("-rescan=<mode>", "Rescan the block chain for missing wallet transactions on startup"
" (1 = start from wallet creation time, 2 = start from genesis block)", ArgsManager::ALLOW_ANY, OptionsCategory::WALLET);
argsman.AddArg("-spendzeroconfchange", strprintf("Spend unconfirmed change when sending transactions (default: %u)", DEFAULT_SPEND_ZEROCONF_CHANGE), ArgsManager::ALLOW_ANY, OptionsCategory::WALLET);
argsman.AddArg("-upgradewallet", "Upgrade wallet to latest format on startup", ArgsManager::ALLOW_ANY, OptionsCategory::WALLET);
argsman.AddArg("-wallet=<path>", "Specify wallet path to load at startup. Can be used multiple times to load multiple wallets. Path is to a directory containing wallet data and log files. If the path is not absolute, it is interpreted relative to <walletdir>. This only loads existing wallets and does not create new ones. For backwards compatibility this also accepts names of existing top-level data files in <walletdir>.", ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::WALLET);
argsman.AddArg("-walletbackupsdir=<dir>", "Specify full path to directory for automatic wallet backups (must exist)", ArgsManager::ALLOW_ANY, OptionsCategory::WALLET);
argsman.AddArg("-walletbroadcast", strprintf("Make the wallet broadcast transactions (default: %u)", DEFAULT_WALLETBROADCAST), ArgsManager::ALLOW_ANY, OptionsCategory::WALLET);
Expand Down Expand Up @@ -129,8 +128,6 @@ bool WalletInit::ParameterInteraction() const
return InitError(_("You can not start a masternode with wallet enabled."));
}

const bool is_multiwallet = gArgs.GetArgs("-wallet").size() > 1;

if (gArgs.GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY) && gArgs.SoftSetBoolArg("-walletbroadcast", false)) {
LogPrintf("%s: parameter interaction: -blocksonly=1 -> setting -walletbroadcast=0\n", __func__);
}
Expand All @@ -146,12 +143,6 @@ bool WalletInit::ParameterInteraction() const
gArgs.ForceRemoveArg("rescan");
}

if (is_multiwallet) {
if (gArgs.GetBoolArg("-upgradewallet", false)) {
return InitError(strprintf(_("%s is only allowed with a single wallet file"), "-upgradewallet"));
}
}

if (gArgs.GetBoolArg("-sysperms", false))
return InitError(Untranslated("-sysperms is not allowed in combination with enabled wallet functionality"));

Expand Down
39 changes: 38 additions & 1 deletion src/wallet/rpcwallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2748,7 +2748,7 @@ static UniValue loadwallet(const JSONRPCRequest& request)
RPCHelpMan{"loadwallet",
"\nLoads a wallet from a wallet file or directory."
"\nNote that all wallet command-line options used when starting dashd will be"
"\napplied to the new wallet (eg -upgradewallet, rescan, etc).\n",
"\napplied to the new wallet (eg, rescan, etc).\n",
{
{"filename", RPCArg::Type::STR, RPCArg::Optional::NO, "The wallet directory or .dat file."},
{"load_on_startup", RPCArg::Type::BOOL, /* default */ "null", "Save wallet name to persistent settings and load on startup. True to add wallet to startup list, false to remove, null to leave unchanged."},
Expand Down Expand Up @@ -4064,6 +4064,42 @@ UniValue walletcreatefundedpsbt(const JSONRPCRequest& request)
return result;
}

static UniValue upgradewallet(const JSONRPCRequest& request)
{
RPCHelpMan{"upgradewallet",
"\nUpgrade the wallet. Upgrades to the latest version if no version number is specified\n"
"New keys may be generated and a new wallet backup will need to be made.",
{
{"version", RPCArg::Type::NUM, /* default */ strprintf("%d", FEATURE_LATEST), "The version number to upgrade to. Default is the latest wallet version"}
},
RPCResults{},
RPCExamples{
HelpExampleCli("upgradewallet", "120200")
+ HelpExampleRpc("upgradewallet", "120200")
}
}.Check(request);

std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
if (!wallet) return NullUniValue;
CWallet* const pwallet = wallet.get();

RPCTypeCheck(request.params, {UniValue::VNUM}, true);

EnsureWalletIsUnlocked(pwallet);

int version = 0;
if (!request.params[0].isNull()) {
version = request.params[0].get_int();
}

bilingual_str error;
std::vector<bilingual_str> warnings;
if (!pwallet->UpgradeWallet(version, error, warnings)) {
throw JSONRPCError(RPC_WALLET_ERROR, error.original);
}
return error.original;
}

// clang-format off
static const CRPCCommand commands[] =
{ // category name actor (function) argNames
Expand Down Expand Up @@ -4123,6 +4159,7 @@ static const CRPCCommand commands[] =
{ "wallet", "signmessage", &signmessage, {"address","message"} },
{ "wallet", "signrawtransactionwithwallet", &signrawtransactionwithwallet, {"hexstring","prevtxs","sighashtype"} },
{ "wallet", "unloadwallet", &unloadwallet, {"wallet_name", "load_on_startup"} },
{ "wallet", "upgradewallet", &upgradewallet, {"version"} },
{ "wallet", "upgradetohd", &upgradetohd, {"mnemonic", "mnemonicpassphrase", "walletpassphrase", "rescan"} },
{ "wallet", "walletlock", &walletlock, {} },
{ "wallet", "walletpassphrasechange", &walletpassphrasechange, {"oldpassphrase","newpassphrase"} },
Expand Down
41 changes: 22 additions & 19 deletions src/wallet/wallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4306,27 +4306,9 @@ std::shared_ptr<CWallet> CWallet::Create(interfaces::Chain& chain, const std::st
}
}

if (gArgs.GetBoolArg("-upgradewallet", fFirstRun))
{
int nMaxVersion = gArgs.GetArg("-upgradewallet", 0);
auto nMinVersion = DEFAULT_USE_HD_WALLET ? FEATURE_LATEST : FEATURE_COMPRPUBKEY;
if (nMaxVersion == 0) // the -upgradewallet without argument case
{
walletInstance->WalletLogPrintf("Performing wallet upgrade to %i\n", nMinVersion);
nMaxVersion = FEATURE_LATEST;
walletInstance->SetMinVersion(nMinVersion); // permanently upgrade the wallet immediately
}
else
walletInstance->WalletLogPrintf("Allowing wallet upgrade up to %i\n", nMaxVersion);
if (nMaxVersion < walletInstance->GetVersion())
{
return unload_wallet(_("Cannot downgrade wallet"));
}
walletInstance->SetMaxVersion(nMaxVersion);
}

if (fFirstRun)
{
walletInstance->SetMaxVersion(FEATURE_LATEST);
walletInstance->SetWalletFlags(wallet_creation_flags, false);
if (!(wallet_creation_flags & (WALLET_FLAG_DISABLE_PRIVATE_KEYS | WALLET_FLAG_BLANK_WALLET))) {
// Create new HD chain
Expand Down Expand Up @@ -4596,6 +4578,27 @@ std::shared_ptr<CWallet> CWallet::Create(interfaces::Chain& chain, const std::st
return walletInstance;
}

bool CWallet::UpgradeWallet(int version, bilingual_str& error, std::vector<bilingual_str>& warnings)
{
int nMaxVersion = version;
auto nMinVersion = DEFAULT_USE_HD_WALLET ? FEATURE_LATEST : FEATURE_COMPRPUBKEY;
if (nMaxVersion == 0) {
WalletLogPrintf("Performing wallet upgrade to %i\n", nMinVersion);
nMaxVersion = FEATURE_LATEST;
SetMinVersion(nMinVersion); // permanently upgrade the wallet immediately
} else {
WalletLogPrintf("Allowing wallet upgrade up to %i\n", nMaxVersion);
}

if (nMaxVersion < GetVersion()) {
error = Untranslated("Cannot downgrade wallet");
return false;
}

SetMaxVersion(nMaxVersion);
return true;
}

void CWallet::postInitProcess()
{
LOCK(cs_wallet);
Expand Down
3 changes: 3 additions & 0 deletions src/wallet/wallet.h
Original file line number Diff line number Diff line change
Expand Up @@ -1241,6 +1241,9 @@ class CWallet final : public WalletStorage, public interfaces::Chain::Notificati
LogPrintf(("%s " + fmt).c_str(), GetDisplayName(), parameters...);
};

/** Upgrade the wallet */
bool UpgradeWallet(int version, bilingual_str& error, std::vector<bilingual_str>& warnings);

/** Get last block processed height */
int GetLastBlockHeight() const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
{
Expand Down
17 changes: 0 additions & 17 deletions test/functional/wallet_multiwallet.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,10 +157,6 @@ def wallet_file(name):
open(not_a_dir, 'a', encoding="utf8").close()
self.nodes[0].assert_start_raises_init_error(['-walletdir=' + not_a_dir], 'Error: Specified -walletdir "' + not_a_dir + '" is not a directory')

self.log.info("Do not allow -upgradewallet with multiwallet")
self.nodes[0].assert_start_raises_init_error(['-upgradewallet', '-wallet=w1', '-wallet=w2'], "Error: -upgradewallet is only allowed with a single wallet file")
self.nodes[0].assert_start_raises_init_error(['-upgradewallet=1', '-wallet=w1', '-wallet=w2'], "Error: -upgradewallet is only allowed with a single wallet file")

# if wallets/ doesn't exist, datadir should be the default wallet dir
wallet_dir2 = data_dir('walletdir')
os.rename(wallet_dir(), wallet_dir2)
Expand Down Expand Up @@ -401,18 +397,5 @@ def wallet_file(name):
self.nodes[0].unloadwallet(wallet)
self.nodes[1].loadwallet(wallet)

# Fail to load if wallet is downgraded
shutil.copytree(os.path.join(self.options.data_wallets_dir, 'high_minversion'), wallet_dir('high_minversion'))
self.restart_node(0, extra_args=['-upgradewallet={}'.format(FEATURE_LATEST)])
assert {'name': 'high_minversion'} in self.nodes[0].listwalletdir()['wallets']
self.log.info("Fail -upgradewallet that results in downgrade")
assert_raises_rpc_error(
-4,
'Wallet loading failed. Error loading {}: Wallet requires newer version of {}'.format(
wallet_dir('high_minversion', 'wallet.dat'), "Dash Core"),
lambda: self.nodes[0].loadwallet(filename='high_minversion'),
)


if __name__ == '__main__':
MultiWalletTest().main()

0 comments on commit 5f10b3e

Please sign in to comment.