diff --git a/src/Makefile.am b/src/Makefile.am index 98f3ab4ea865b..29989b0e6928b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -401,6 +401,7 @@ BITCOIN_CORE_H = \ wallet/ismine.h \ wallet/load.h \ wallet/rpcwallet.h \ + wallet/rpc/util.h \ wallet/salvage.h \ wallet/scriptpubkeyman.h \ wallet/sqlite.h \ @@ -595,8 +596,8 @@ libbitcoin_wallet_a_SOURCES = \ wallet/hdchain.cpp \ wallet/interfaces.cpp \ wallet/load.cpp \ + wallet/rpc/util.cpp \ wallet/rpcdump.cpp \ - wallet/rpcwallet.cpp \ wallet/scriptpubkeyman.cpp \ wallet/wallet.cpp \ wallet/walletdb.cpp \ diff --git a/src/rpc/coinjoin.cpp b/src/rpc/coinjoin.cpp index 81f6c3793346b..0347294509feb 100644 --- a/src/rpc/coinjoin.cpp +++ b/src/rpc/coinjoin.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #endif // ENABLE_WALLET #include diff --git a/src/rpc/evo.cpp b/src/rpc/evo.cpp index a7d040a059baf..44ed79610b1fc 100644 --- a/src/rpc/evo.cpp +++ b/src/rpc/evo.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #endif//ENABLE_WALLET #ifdef ENABLE_WALLET diff --git a/src/rpc/masternode.cpp b/src/rpc/masternode.cpp index 4731ce204dec4..2e0b3f3c996b1 100644 --- a/src/rpc/masternode.cpp +++ b/src/rpc/masternode.cpp @@ -27,6 +27,7 @@ #include #ifdef ENABLE_WALLET #include +#include #endif // ENABLE_WALLET #include diff --git a/src/wallet/rpc/util.cpp b/src/wallet/rpc/util.cpp new file mode 100644 index 0000000000000..b926bfc75fd4d --- /dev/null +++ b/src/wallet/rpc/util.cpp @@ -0,0 +1,122 @@ +// Copyright (c) 2011-2021 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include + +#include +#include +#include +#include + +#include + +static const std::string WALLET_ENDPOINT_BASE = "/wallet/"; +const std::string HELP_REQUIRING_PASSPHRASE{"\nRequires wallet passphrase to be set with walletpassphrase call if wallet is encrypted.\n"}; + +bool GetAvoidReuseFlag(const CWallet& wallet, const UniValue& param) { + bool can_avoid_reuse = wallet.IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE); + bool avoid_reuse = param.isNull() ? can_avoid_reuse : param.get_bool(); + + if (avoid_reuse && !can_avoid_reuse) { + throw JSONRPCError(RPC_WALLET_ERROR, "wallet does not have the \"avoid reuse\" feature enabled"); + } + + return avoid_reuse; +} + +/** Used by RPC commands that have an include_watchonly parameter. + * We default to true for watchonly wallets if include_watchonly isn't + * explicitly set. + */ +bool ParseIncludeWatchonly(const UniValue& include_watchonly, const CWallet& wallet) +{ + if (include_watchonly.isNull()) { + // if include_watchonly isn't explicitly set, then check if we have a watchonly wallet + return wallet.IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS); + } + + // otherwise return whatever include_watchonly was set to + return include_watchonly.get_bool(); +} + +bool GetWalletNameFromJSONRPCRequest(const JSONRPCRequest& request, std::string& wallet_name) +{ + if (URL_DECODE && request.URI.substr(0, WALLET_ENDPOINT_BASE.size()) == WALLET_ENDPOINT_BASE) { + // wallet endpoint was used + wallet_name = URL_DECODE(request.URI.substr(WALLET_ENDPOINT_BASE.size())); + return true; + } + return false; +} + +std::shared_ptr GetWalletForJSONRPCRequest(const JSONRPCRequest& request) +{ + CHECK_NONFATAL(request.mode == JSONRPCRequest::EXECUTE); + WalletContext& context = EnsureWalletContext(request.context); + + std::string wallet_name; + if (GetWalletNameFromJSONRPCRequest(request, wallet_name)) { + const std::shared_ptr pwallet = GetWallet(context, wallet_name); + if (!pwallet) throw JSONRPCError(RPC_WALLET_NOT_FOUND, "Requested wallet does not exist or is not loaded"); + return pwallet; + } + + std::vector> wallets = GetWallets(context); + if (wallets.size() == 1) { + return wallets[0]; + } + + if (wallets.empty()) { + throw JSONRPCError( + RPC_WALLET_NOT_FOUND, "No wallet is loaded. Load a wallet using loadwallet or create a new one with createwallet. (Note: A default wallet is no longer automatically created)"); + } + throw JSONRPCError(RPC_WALLET_NOT_SPECIFIED, + "Wallet file not specified (must request wallet RPC through /wallet/ uri-path)."); +} + +void EnsureWalletIsUnlocked(const CWallet& wallet) +{ + if (wallet.IsLocked()) { + throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first."); + } +} + +WalletContext& EnsureWalletContext(const std::any& context) +{ + auto wallet_context = util::AnyPtr(context); + if (!wallet_context) { + throw JSONRPCError(RPC_INTERNAL_ERROR, "Wallet context not found"); + } + return *wallet_context; +} + +// also_create should only be set to true only when the RPC is expected to add things to a blank wallet and make it no longer blank +LegacyScriptPubKeyMan& EnsureLegacyScriptPubKeyMan(CWallet& wallet, bool also_create) +{ + LegacyScriptPubKeyMan* spk_man = wallet.GetLegacyScriptPubKeyMan(); + if (!spk_man && also_create) { + spk_man = wallet.GetOrCreateLegacyScriptPubKeyMan(); + } + if (!spk_man) { + throw JSONRPCError(RPC_WALLET_ERROR, "This type of wallet does not support this command"); + } + return *spk_man; +} + +const LegacyScriptPubKeyMan& EnsureConstLegacyScriptPubKeyMan(const CWallet& wallet) +{ + const LegacyScriptPubKeyMan* spk_man = wallet.GetLegacyScriptPubKeyMan(); + if (!spk_man) { + throw JSONRPCError(RPC_WALLET_ERROR, "This type of wallet does not support this command"); + } + return *spk_man; +} + +std::string LabelFromValue(const UniValue& value) +{ + std::string label = value.get_str(); + if (label == "*") + throw JSONRPCError(RPC_WALLET_INVALID_LABEL_NAME, "Invalid label name"); + return label; +} diff --git a/src/wallet/rpc/util.h b/src/wallet/rpc/util.h new file mode 100644 index 0000000000000..a493a80a74859 --- /dev/null +++ b/src/wallet/rpc/util.h @@ -0,0 +1,38 @@ +// Copyright (c) 2017-2021 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_WALLET_RPC_UTIL_H +#define BITCOIN_WALLET_RPC_UTIL_H + +#include +#include +#include + +class CWallet; +class JSONRPCRequest; +class LegacyScriptPubKeyMan; +class UniValue; +struct WalletContext; + +extern const std::string HELP_REQUIRING_PASSPHRASE; + +/** + * Figures out what wallet, if any, to use for a JSONRPCRequest. + * + * @param[in] request JSONRPCRequest that wishes to access a wallet + * @return nullptr if no wallet should be used, or a pointer to the CWallet + */ +std::shared_ptr GetWalletForJSONRPCRequest(const JSONRPCRequest& request); +bool GetWalletNameFromJSONRPCRequest(const JSONRPCRequest& request, std::string& wallet_name); + +void EnsureWalletIsUnlocked(const CWallet&); +WalletContext& EnsureWalletContext(const std::any& context); +LegacyScriptPubKeyMan& EnsureLegacyScriptPubKeyMan(CWallet& wallet, bool also_create = false); +const LegacyScriptPubKeyMan& EnsureConstLegacyScriptPubKeyMan(const CWallet& wallet); + +bool GetAvoidReuseFlag(const CWallet& wallet, const UniValue& param); +bool ParseIncludeWatchonly(const UniValue& include_watchonly, const CWallet& wallet); +std::string LabelFromValue(const UniValue& value); + +#endif // BITCOIN_WALLET_RPC_UTIL_H diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index d829bbab2c4f3..5d6af5fb41c6c 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index b4ca6de160730..8deb51496fa9b 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -49,35 +50,6 @@ using interfaces::FoundBlock; -static const std::string WALLET_ENDPOINT_BASE = "/wallet/"; - -static inline bool GetAvoidReuseFlag(const CWallet& wallet, const UniValue& param) { - bool can_avoid_reuse = wallet.IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE); - bool avoid_reuse = param.isNull() ? can_avoid_reuse : param.get_bool(); - - if (avoid_reuse && !can_avoid_reuse) { - throw JSONRPCError(RPC_WALLET_ERROR, "wallet does not have the \"avoid reuse\" feature enabled"); - } - - return avoid_reuse; -} - - -/** Used by RPC commands that have an include_watchonly parameter. - * We default to true for watchonly wallets if include_watchonly isn't - * explicitly set. - */ -static bool ParseIncludeWatchonly(const UniValue& include_watchonly, const CWallet& wallet) -{ - if (include_watchonly.isNull()) { - // if include_watchonly isn't explicitly set, then check if we have a watchonly wallet - return wallet.IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS); - } - - // otherwise return whatever include_watchonly was set to - return include_watchonly.get_bool(); -} - /** Checks if a CKey is in the given CWallet compressed or otherwise*/ bool HaveKey(const SigningProvider& wallet, const CKey& key) @@ -87,69 +59,6 @@ bool HaveKey(const SigningProvider& wallet, const CKey& key) return wallet.HaveKey(key.GetPubKey().GetID()) || wallet.HaveKey(key2.GetPubKey().GetID()); } -bool GetWalletNameFromJSONRPCRequest(const JSONRPCRequest& request, std::string& wallet_name) -{ - if (URL_DECODE && request.URI.substr(0, WALLET_ENDPOINT_BASE.size()) == WALLET_ENDPOINT_BASE) { - // wallet endpoint was used - wallet_name = URL_DECODE(request.URI.substr(WALLET_ENDPOINT_BASE.size())); - return true; - } - return false; -} - -std::shared_ptr GetWalletForJSONRPCRequest(const JSONRPCRequest& request) -{ - CHECK_NONFATAL(request.mode == JSONRPCRequest::EXECUTE); - - std::string wallet_name; - if (GetWalletNameFromJSONRPCRequest(request, wallet_name)) { - std::shared_ptr pwallet = GetWallet(wallet_name); - if (!pwallet) throw JSONRPCError(RPC_WALLET_NOT_FOUND, "Requested wallet does not exist or is not loaded"); - return pwallet; - } - - std::vector> wallets = GetWallets(); - if (wallets.size() == 1) { - return wallets[0]; - } - - if (wallets.empty()) { - throw JSONRPCError( - RPC_WALLET_NOT_FOUND, "No wallet is loaded. Load a wallet using loadwallet or create a new one with createwallet. (Note: A default wallet is no longer automatically created)"); - } - throw JSONRPCError(RPC_WALLET_NOT_SPECIFIED, - "Wallet file not specified (must request wallet RPC through /wallet/ uri-path)."); -} - -void EnsureWalletIsUnlocked(const CWallet& wallet) -{ - if (wallet.IsLocked()) { - throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first."); - } -} - -// also_create should only be set to true only when the RPC is expected to add things to a blank wallet and make it no longer blank -LegacyScriptPubKeyMan& EnsureLegacyScriptPubKeyMan(CWallet& wallet, bool also_create) -{ - LegacyScriptPubKeyMan* spk_man = wallet.GetLegacyScriptPubKeyMan(); - if (!spk_man && also_create) { - spk_man = wallet.GetOrCreateLegacyScriptPubKeyMan(); - } - if (!spk_man) { - throw JSONRPCError(RPC_WALLET_ERROR, "This type of wallet does not support this command"); - } - return *spk_man; -} - -WalletContext& EnsureWalletContext(const CoreContext& context) -{ - auto* wallet_context = GetContext(context); - if (!wallet_context) { - throw JSONRPCError(RPC_INTERNAL_ERROR, "Wallet context not found"); - } - return *wallet_context; -} - static void WalletTxToJSON(interfaces::Chain& chain, const CWalletTx& wtx, UniValue& entry) { int confirms = wtx.GetDepthInMainChain(); @@ -191,14 +100,6 @@ static void WalletTxToJSON(interfaces::Chain& chain, const CWalletTx& wtx, UniVa } -static std::string LabelFromValue(const UniValue& value) -{ - std::string label = value.get_str(); - if (label == "*") - throw JSONRPCError(RPC_WALLET_INVALID_LABEL_NAME, "Invalid label name"); - return label; -} - /** * Update coin control with fee estimation based on the given parameters * diff --git a/src/wallet/rpcwallet.h b/src/wallet/rpcwallet.h index ce3d5a659f6e7..2867801ae2c05 100644 --- a/src/wallet/rpcwallet.h +++ b/src/wallet/rpcwallet.h @@ -8,35 +8,10 @@ #include #include -#include -#include -#include - class CRPCCommand; -class CWallet; -class JSONRPCRequest; -class LegacyScriptPubKeyMan; -class UniValue; -class CTransaction; -struct PartiallySignedTransaction; -struct WalletContext; - -static const std::string HELP_REQUIRING_PASSPHRASE{"\nRequires wallet passphrase to be set with walletpassphrase call if wallet is encrypted.\n"}; Span GetWalletRPCCommands(); -/** - * Figures out what wallet, if any, to use for a JSONRPCRequest. - * - * @param[in] request JSONRPCRequest that wishes to access a wallet - * @return nullptr if no wallet should be used, or a pointer to the CWallet - */ -std::shared_ptr GetWalletForJSONRPCRequest(const JSONRPCRequest& request); - -void EnsureWalletIsUnlocked(const CWallet&); -WalletContext& EnsureWalletContext(const CoreContext& context); -LegacyScriptPubKeyMan& EnsureLegacyScriptPubKeyMan(CWallet& wallet, bool also_create = false); - RPCHelpMan getaddressinfo(); RPCHelpMan getrawchangeaddress(); RPCHelpMan addmultisigaddress();