diff options
Diffstat (limited to 'src/wallet/rpcwallet.cpp')
-rw-r--r-- | src/wallet/rpcwallet.cpp | 101 |
1 files changed, 85 insertions, 16 deletions
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index fd9e23cb64..b1d2532d86 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2010 Satoshi Nakamoto -// Copyright (c) 2009-2017 The Bitcoin Core developers +// Copyright (c) 2009-2018 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -20,6 +20,7 @@ #include <rpc/server.h> #include <rpc/util.h> #include <script/sign.h> +#include <shutdown.h> #include <timedata.h> #include <util.h> #include <utilmoneystr.h> @@ -30,8 +31,6 @@ #include <wallet/walletdb.h> #include <wallet/walletutil.h> -#include <init.h> // For StartShutdown - #include <stdint.h> #include <univalue.h> @@ -40,12 +39,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 +74,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)"); } @@ -1017,6 +1020,14 @@ static UniValue sendfrom(const JSONRPCRequest& request) return NullUniValue; } + if (!IsDeprecatedRPCEnabled("accounts")) { + if (request.fHelp) { + throw std::runtime_error("sendfrom (Deprecated, will be removed in V0.18. To use this command, start bitcoind with -deprecatedrpc=accounts)"); + } + throw JSONRPCError(RPC_METHOD_DEPRECATED, "sendfrom is deprecated and will be removed in V0.18. To use this command, start bitcoind with -deprecatedrpc=accounts."); + } + + if (request.fHelp || request.params.size() < 3 || request.params.size() > 6) throw std::runtime_error( "sendfrom \"fromaccount\" \"toaddress\" amount ( minconf \"comment\" \"comment_to\" )\n" @@ -1255,9 +1266,11 @@ static UniValue sendmany(const JSONRPCRequest& request) EnsureWalletIsUnlocked(pwallet); // Check funds - CAmount nBalance = pwallet->GetLegacyBalance(ISMINE_SPENDABLE, nMinDepth, &strAccount); - if (totalAmount > nBalance) + if (IsDeprecatedRPCEnabled("accounts") && totalAmount > pwallet->GetLegacyBalance(ISMINE_SPENDABLE, nMinDepth, &strAccount)) { throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds"); + } else if (!IsDeprecatedRPCEnabled("accounts") && totalAmount > pwallet->GetLegacyBalance(ISMINE_SPENDABLE, nMinDepth, nullptr)) { + throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Wallet has insufficient funds"); + } // Shuffle recipient list std::shuffle(vecSend.begin(), vecSend.end(), FastRandomContext()); @@ -3053,7 +3066,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( @@ -3078,6 +3091,12 @@ UniValue loadwallet(const JSONRPCRequest& request) fs::path wallet_path = fs::absolute(wallet_file, GetWalletDir()); if (fs::symlink_status(wallet_path).type() == fs::file_not_found) { throw JSONRPCError(RPC_WALLET_NOT_FOUND, "Wallet " + wallet_file + " not found."); + } else if (fs::is_directory(wallet_path)) { + // The given filename is a directory. Check that there's a wallet.dat file. + fs::path wallet_dat_file = wallet_path / "wallet.dat"; + if (fs::symlink_status(wallet_dat_file).type() == fs::file_not_found) { + throw JSONRPCError(RPC_WALLET_NOT_FOUND, "Directory " + wallet_file + " does not contain a wallet.dat file."); + } } std::string warning; @@ -3100,7 +3119,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 +3166,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); @@ -4376,12 +4444,12 @@ static const CRPCCommand commands[] = { "wallet", "listwallets", &listwallets, {} }, { "wallet", "loadwallet", &loadwallet, {"filename"} }, { "wallet", "lockunspent", &lockunspent, {"unlock","transactions"} }, - { "wallet", "sendfrom", &sendfrom, {"fromaccount","toaddress","amount","minconf","comment","comment_to"} }, { "wallet", "sendmany", &sendmany, {"fromaccount|dummy","amounts","minconf","comment","subtractfeefrom","replaceable","conf_target","estimate_mode"} }, { "wallet", "sendtoaddress", &sendtoaddress, {"address","amount","comment","comment_to","subtractfeefromamount","replaceable","conf_target","estimate_mode"} }, { "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"} }, @@ -4397,6 +4465,7 @@ static const CRPCCommand commands[] = { "wallet", "listaccounts", &listaccounts, {"minconf","include_watchonly"} }, { "wallet", "listreceivedbyaccount", &listreceivedbylabel, {"minconf","include_empty","include_watchonly"} }, { "wallet", "setaccount", &setlabel, {"address","account"} }, + { "wallet", "sendfrom", &sendfrom, {"fromaccount","toaddress","amount","minconf","comment","comment_to"} }, { "wallet", "move", &movecmd, {"fromaccount","toaccount","amount","minconf","comment"} }, /** Label functions (to replace non-balance account functions) */ |