aboutsummaryrefslogtreecommitdiff
path: root/src/wallet/rpcwallet.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/wallet/rpcwallet.cpp')
-rw-r--r--src/wallet/rpcwallet.cpp98
1 files changed, 76 insertions, 22 deletions
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index 94c35e2cb1..3f2255d042 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -40,12 +40,21 @@
static const std::string WALLET_ENDPOINT_BASE = "/wallet/";
-std::shared_ptr<CWallet> GetWalletForJSONRPCRequest(const JSONRPCRequest& request)
+bool GetWalletNameFromJSONRPCRequest(const JSONRPCRequest& request, std::string& wallet_name)
{
if (request.URI.substr(0, WALLET_ENDPOINT_BASE.size()) == WALLET_ENDPOINT_BASE) {
// wallet endpoint was used
- std::string requestedWallet = urlDecode(request.URI.substr(WALLET_ENDPOINT_BASE.size()));
- std::shared_ptr<CWallet> pwallet = GetWallet(requestedWallet);
+ wallet_name = urlDecode(request.URI.substr(WALLET_ENDPOINT_BASE.size()));
+ return true;
+ }
+ return false;
+}
+
+std::shared_ptr<CWallet> GetWalletForJSONRPCRequest(const JSONRPCRequest& request)
+{
+ std::string wallet_name;
+ if (GetWalletNameFromJSONRPCRequest(request, wallet_name)) {
+ std::shared_ptr<CWallet> pwallet = GetWallet(wallet_name);
if (!pwallet) throw JSONRPCError(RPC_WALLET_NOT_FOUND, "Requested wallet does not exist or is not loaded");
return pwallet;
}
@@ -66,11 +75,6 @@ bool EnsureWalletIsAvailable(CWallet * const pwallet, bool avoidException)
if (pwallet) return true;
if (avoidException) return false;
if (!HasWallets()) {
- // Note: It isn't currently possible to trigger this error because
- // wallet RPC methods aren't registered unless a wallet is loaded. But
- // this error is being kept as a precaution, because it's possible in
- // the future that wallet RPC methods might get or remain registered
- // when no wallets are loaded.
throw JSONRPCError(
RPC_METHOD_NOT_FOUND, "Method not found (wallet method is disabled because no wallet is loaded)");
}
@@ -120,7 +124,7 @@ static void WalletTxToJSON(const CWalletTx& wtx, UniValue& entry)
}
entry.pushKV("bip125-replaceable", rbfStatus);
- for (const std::pair<std::string, std::string>& item : wtx.mapValue)
+ for (const std::pair<const std::string, std::string>& item : wtx.mapValue)
entry.pushKV(item.first, item.second);
}
@@ -343,7 +347,7 @@ static UniValue setlabel(const JSONRPCRequest& request)
// If so, delete the account record for it. Labels, unlike addresses, can be deleted,
// and if we wouldn't do this, the record would stick around forever.
bool found_address = false;
- for (const std::pair<CTxDestination, CAddressBookData>& item : pwallet->mapAddressBook) {
+ for (const std::pair<const CTxDestination, CAddressBookData>& item : pwallet->mapAddressBook) {
if (item.second.name == label) {
found_address = true;
break;
@@ -440,7 +444,7 @@ static UniValue getaddressesbyaccount(const JSONRPCRequest& request)
// Find all addresses that have the given account
UniValue ret(UniValue::VARR);
- for (const std::pair<CTxDestination, CAddressBookData>& item : pwallet->mapAddressBook) {
+ for (const std::pair<const CTxDestination, CAddressBookData>& item : pwallet->mapAddressBook) {
const CTxDestination& dest = item.first;
const std::string& strName = item.second.name;
if (strName == strAccount) {
@@ -753,7 +757,7 @@ static UniValue getreceivedbyaddress(const JSONRPCRequest& request)
// Tally
CAmount nAmount = 0;
- for (const std::pair<uint256, CWalletTx>& pairWtx : pwallet->mapWallet) {
+ for (const std::pair<const uint256, CWalletTx>& pairWtx : pwallet->mapWallet) {
const CWalletTx& wtx = pairWtx.second;
if (wtx.IsCoinBase() || !CheckFinalTx(*wtx.tx))
continue;
@@ -821,7 +825,7 @@ static UniValue getreceivedbylabel(const JSONRPCRequest& request)
// Tally
CAmount nAmount = 0;
- for (const std::pair<uint256, CWalletTx>& pairWtx : pwallet->mapWallet) {
+ for (const std::pair<const uint256, CWalletTx>& pairWtx : pwallet->mapWallet) {
const CWalletTx& wtx = pairWtx.second;
if (wtx.IsCoinBase() || !CheckFinalTx(*wtx.tx))
continue;
@@ -1527,7 +1531,7 @@ static UniValue ListReceived(CWallet * const pwallet, const UniValue& params, bo
// Tally
std::map<CTxDestination, tallyitem> mapTally;
- for (const std::pair<uint256, CWalletTx>& pairWtx : pwallet->mapWallet) {
+ for (const std::pair<const uint256, CWalletTx>& pairWtx : pwallet->mapWallet) {
const CWalletTx& wtx = pairWtx.second;
if (wtx.IsCoinBase() || !CheckFinalTx(*wtx.tx))
@@ -2106,13 +2110,13 @@ static UniValue listaccounts(const JSONRPCRequest& request)
includeWatchonly = includeWatchonly | ISMINE_WATCH_ONLY;
std::map<std::string, CAmount> mapAccountBalances;
- for (const std::pair<CTxDestination, CAddressBookData>& entry : pwallet->mapAddressBook) {
+ for (const std::pair<const CTxDestination, CAddressBookData>& entry : pwallet->mapAddressBook) {
if (IsMine(*pwallet, entry.first) & includeWatchonly) { // This address belongs to me
mapAccountBalances[entry.second.name] = 0;
}
}
- for (const std::pair<uint256, CWalletTx>& pairWtx : pwallet->mapWallet) {
+ for (const std::pair<const uint256, CWalletTx>& pairWtx : pwallet->mapWallet) {
const CWalletTx& wtx = pairWtx.second;
CAmount nFee;
std::string strSentAccount;
@@ -2141,7 +2145,7 @@ static UniValue listaccounts(const JSONRPCRequest& request)
mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
UniValue ret(UniValue::VOBJ);
- for (const std::pair<std::string, CAmount>& accountBalance : mapAccountBalances) {
+ for (const std::pair<const std::string, CAmount>& accountBalance : mapAccountBalances) {
ret.pushKV(accountBalance.first, ValueFromAmount(accountBalance.second));
}
return ret;
@@ -2250,7 +2254,7 @@ static UniValue listsinceblock(const JSONRPCRequest& request)
UniValue transactions(UniValue::VARR);
- for (const std::pair<uint256, CWalletTx>& pairWtx : pwallet->mapWallet) {
+ for (const std::pair<const uint256, CWalletTx>& pairWtx : pwallet->mapWallet) {
CWalletTx tx = pairWtx.second;
if (depth == -1 || tx.GetDepthInMainChain() < depth) {
@@ -3053,7 +3057,7 @@ static UniValue listwallets(const JSONRPCRequest& request)
return obj;
}
-UniValue loadwallet(const JSONRPCRequest& request)
+static UniValue loadwallet(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 1)
throw std::runtime_error(
@@ -3100,7 +3104,7 @@ UniValue loadwallet(const JSONRPCRequest& request)
return obj;
}
-UniValue createwallet(const JSONRPCRequest& request)
+static UniValue createwallet(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 1) {
throw std::runtime_error(
@@ -3147,6 +3151,55 @@ UniValue createwallet(const JSONRPCRequest& request)
return obj;
}
+static UniValue unloadwallet(const JSONRPCRequest& request)
+{
+ if (request.fHelp || request.params.size() > 1) {
+ throw std::runtime_error(
+ "unloadwallet ( \"wallet_name\" )\n"
+ "Unloads the wallet referenced by the request endpoint otherwise unloads the wallet specified in the argument.\n"
+ "Specifying the wallet name on a wallet endpoint is invalid."
+ "\nArguments:\n"
+ "1. \"wallet_name\" (string, optional) The name of the wallet to unload.\n"
+ "\nExamples:\n"
+ + HelpExampleCli("unloadwallet", "wallet_name")
+ + HelpExampleRpc("unloadwallet", "wallet_name")
+ );
+ }
+
+ std::string wallet_name;
+ if (GetWalletNameFromJSONRPCRequest(request, wallet_name)) {
+ if (!request.params[0].isNull()) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot unload the requested wallet");
+ }
+ } else {
+ wallet_name = request.params[0].get_str();
+ }
+
+ std::shared_ptr<CWallet> wallet = GetWallet(wallet_name);
+ if (!wallet) {
+ throw JSONRPCError(RPC_WALLET_NOT_FOUND, "Requested wallet does not exist or is not loaded");
+ }
+
+ // Release the "main" shared pointer and prevent further notifications.
+ // Note that any attempt to load the same wallet would fail until the wallet
+ // is destroyed (see CheckUniqueFileid).
+ if (!RemoveWallet(wallet)) {
+ throw JSONRPCError(RPC_MISC_ERROR, "Requested wallet already unloaded");
+ }
+ UnregisterValidationInterface(wallet.get());
+
+ // The wallet can be in use so it's not possible to explicitly unload here.
+ // Just notify the unload intent so that all shared pointers are released.
+ // The wallet will be destroyed once the last shared pointer is released.
+ wallet->NotifyUnload();
+
+ // There's no point in waiting for the wallet to unload.
+ // At this point this method should never fail. The unloading could only
+ // fail due to an unexpected error which would cause a process termination.
+
+ return NullUniValue;
+}
+
static UniValue resendwallettransactions(const JSONRPCRequest& request)
{
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
@@ -4187,7 +4240,7 @@ static UniValue getaddressesbylabel(const JSONRPCRequest& request)
// Find all addresses that have the given label
UniValue ret(UniValue::VOBJ);
- for (const std::pair<CTxDestination, CAddressBookData>& item : pwallet->mapAddressBook) {
+ for (const std::pair<const CTxDestination, CAddressBookData>& item : pwallet->mapAddressBook) {
if (item.second.name == label) {
ret.pushKV(EncodeDestination(item.first), AddressBookDataToJSON(item.second, false));
}
@@ -4240,7 +4293,7 @@ static UniValue listlabels(const JSONRPCRequest& request)
// Add to a set to sort by label name, then insert into Univalue array
std::set<std::string> label_set;
- for (const std::pair<CTxDestination, CAddressBookData>& entry : pwallet->mapAddressBook) {
+ for (const std::pair<const CTxDestination, CAddressBookData>& entry : pwallet->mapAddressBook) {
if (purpose.empty() || entry.second.purpose == purpose) {
label_set.insert(entry.second.name);
}
@@ -4382,6 +4435,7 @@ static const CRPCCommand commands[] =
{ "wallet", "settxfee", &settxfee, {"amount"} },
{ "wallet", "signmessage", &signmessage, {"address","message"} },
{ "wallet", "signrawtransactionwithwallet", &signrawtransactionwithwallet, {"hexstring","prevtxs","sighashtype"} },
+ { "wallet", "unloadwallet", &unloadwallet, {"wallet_name"} },
{ "wallet", "walletlock", &walletlock, {} },
{ "wallet", "walletpassphrasechange", &walletpassphrasechange, {"oldpassphrase","newpassphrase"} },
{ "wallet", "walletpassphrase", &walletpassphrase, {"passphrase","timeout"} },