Skip to content

Commit 6608c36

Browse files
committed
rpc: Add unloadwallet RPC
1 parent 537efe1 commit 6608c36

File tree

3 files changed

+68
-4
lines changed

3 files changed

+68
-4
lines changed

src/wallet/rpcwallet.cpp

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3076,7 +3076,7 @@ static UniValue listwallets(const JSONRPCRequest& request)
30763076
return obj;
30773077
}
30783078

3079-
UniValue loadwallet(const JSONRPCRequest& request)
3079+
static UniValue loadwallet(const JSONRPCRequest& request)
30803080
{
30813081
if (request.fHelp || request.params.size() != 1)
30823082
throw std::runtime_error(
@@ -3123,7 +3123,7 @@ UniValue loadwallet(const JSONRPCRequest& request)
31233123
return obj;
31243124
}
31253125

3126-
UniValue createwallet(const JSONRPCRequest& request)
3126+
static UniValue createwallet(const JSONRPCRequest& request)
31273127
{
31283128
if (request.fHelp || request.params.size() != 1) {
31293129
throw std::runtime_error(
@@ -3170,6 +3170,55 @@ UniValue createwallet(const JSONRPCRequest& request)
31703170
return obj;
31713171
}
31723172

3173+
static UniValue unloadwallet(const JSONRPCRequest& request)
3174+
{
3175+
if (request.fHelp || request.params.size() > 1) {
3176+
throw std::runtime_error(
3177+
"unloadwallet ( \"wallet_name\" )\n"
3178+
"Unloads the wallet referenced by the request endpoint otherwise unloads the wallet specified in the argument.\n"
3179+
"Specifying the wallet name on a wallet endpoint is invalid."
3180+
"\nArguments:\n"
3181+
"1. \"wallet_name\" (string, optional) The name of the wallet to unload.\n"
3182+
"\nExamples:\n"
3183+
+ HelpExampleCli("unloadwallet", "wallet_name")
3184+
+ HelpExampleRpc("unloadwallet", "wallet_name")
3185+
);
3186+
}
3187+
3188+
std::string wallet_name;
3189+
if (GetWalletNameFromJSONRPCRequest(request, wallet_name)) {
3190+
if (!request.params[0].isNull()) {
3191+
throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot unload the requested wallet");
3192+
}
3193+
} else {
3194+
wallet_name = request.params[0].get_str();
3195+
}
3196+
3197+
std::shared_ptr<CWallet> wallet = GetWallet(wallet_name);
3198+
if (!wallet) {
3199+
throw JSONRPCError(RPC_WALLET_NOT_FOUND, "Requested wallet does not exist or is not loaded");
3200+
}
3201+
3202+
// Release the "main" shared pointer and prevent further notifications.
3203+
// Note that any attempt to load the same wallet would fail until the wallet
3204+
// is destroyed (see CheckUniqueFileid).
3205+
if (!RemoveWallet(wallet)) {
3206+
throw JSONRPCError(RPC_MISC_ERROR, "Requested wallet already unloaded");
3207+
}
3208+
UnregisterValidationInterface(wallet.get());
3209+
3210+
// The wallet can be in use so it's not possible to explicitly unload here.
3211+
// Just notify the unload intent so that all shared pointers are released.
3212+
// The wallet will be destroyed once the last shared pointer is released.
3213+
wallet->NotifyUnload();
3214+
3215+
// There's no point in waiting for the wallet to unload.
3216+
// At this point this method should never fail. The unloading could only
3217+
// fail due to an unexpected error which would cause a process termination.
3218+
3219+
return NullUniValue;
3220+
}
3221+
31733222
static UniValue resendwallettransactions(const JSONRPCRequest& request)
31743223
{
31753224
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
@@ -4405,6 +4454,7 @@ static const CRPCCommand commands[] =
44054454
{ "wallet", "settxfee", &settxfee, {"amount"} },
44064455
{ "wallet", "signmessage", &signmessage, {"address","message"} },
44074456
{ "wallet", "signrawtransactionwithwallet", &signrawtransactionwithwallet, {"hexstring","prevtxs","sighashtype"} },
4457+
{ "wallet", "unloadwallet", &unloadwallet, {"wallet_name"} },
44084458
{ "wallet", "walletlock", &walletlock, {} },
44094459
{ "wallet", "walletpassphrasechange", &walletpassphrasechange, {"oldpassphrase","newpassphrase"} },
44104460
{ "wallet", "walletpassphrase", &walletpassphrase, {"passphrase","timeout"} },

src/wallet/wallet.cpp

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,15 @@ std::shared_ptr<CWallet> GetWallet(const std::string& name)
7979
return nullptr;
8080
}
8181

82+
// Custom deleter for shared_ptr<CWallet>.
83+
static void ReleaseWallet(CWallet* wallet)
84+
{
85+
LogPrintf("Releasing wallet %s\n", wallet->GetName());
86+
wallet->BlockUntilSyncedToCurrentChain();
87+
wallet->Flush();
88+
delete wallet;
89+
}
90+
8291
const uint32_t BIP32_HARDENED_KEY_LIMIT = 0x80000000;
8392

8493
const uint256 CMerkleTx::ABANDON_HASH(uint256S("0000000000000000000000000000000000000000000000000000000000000001"));
@@ -1294,7 +1303,7 @@ void CWallet::BlockUntilSyncedToCurrentChain() {
12941303
LOCK(cs_main);
12951304
const CBlockIndex* initialChainTip = chainActive.Tip();
12961305

1297-
if (m_last_block_processed->GetAncestor(initialChainTip->nHeight) == initialChainTip) {
1306+
if (m_last_block_processed && m_last_block_processed->GetAncestor(initialChainTip->nHeight) == initialChainTip) {
12981307
return;
12991308
}
13001309
}
@@ -4057,7 +4066,9 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(const std::string& name,
40574066

40584067
int64_t nStart = GetTimeMillis();
40594068
bool fFirstRun = true;
4060-
std::shared_ptr<CWallet> walletInstance = std::make_shared<CWallet>(name, WalletDatabase::Create(path));
4069+
// TODO: Can't use std::make_shared because we need a custom deleter but
4070+
// should be possible to use std::allocate_shared.
4071+
std::shared_ptr<CWallet> walletInstance(new CWallet(name, WalletDatabase::Create(path)), ReleaseWallet);
40614072
DBErrors nLoadWalletRet = walletInstance->LoadWallet(fFirstRun);
40624073
if (nLoadWalletRet != DBErrors::LOAD_OK)
40634074
{

src/wallet/wallet.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1097,6 +1097,9 @@ class CWallet final : public CCryptoKeyStore, public CValidationInterface
10971097
//! Flush wallet (bitdb flush)
10981098
void Flush(bool shutdown=false);
10991099

1100+
/** Wallet is about to be unloaded */
1101+
boost::signals2::signal<void ()> NotifyUnload;
1102+
11001103
/**
11011104
* Address book entry changed.
11021105
* @note called with lock cs_wallet held.

0 commit comments

Comments
 (0)