Branch data Line data Source code
# 1 : : // Copyright (c) 2011-2021 The Bitcoin Core developers # 2 : : // Distributed under the MIT software license, see the accompanying # 3 : : // file COPYING or http://www.opensource.org/licenses/mit-license.php. # 4 : : # 5 : : #include <wallet/rpc/util.h> # 6 : : # 7 : : #include <rpc/util.h> # 8 : : #include <util/translation.h> # 9 : : #include <util/url.h> # 10 : : #include <wallet/context.h> # 11 : : #include <wallet/wallet.h> # 12 : : # 13 : : #include <univalue.h> # 14 : : # 15 : : namespace wallet { # 16 : : static const std::string WALLET_ENDPOINT_BASE = "/wallet/"; # 17 : : const std::string HELP_REQUIRING_PASSPHRASE{"\nRequires wallet passphrase to be set with walletpassphrase call if wallet is encrypted.\n"}; # 18 : : # 19 : 2717 : bool GetAvoidReuseFlag(const CWallet& wallet, const UniValue& param) { # 20 : 2717 : bool can_avoid_reuse = wallet.IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE); # 21 [ + + ]: 2717 : bool avoid_reuse = param.isNull() ? can_avoid_reuse : param.get_bool(); # 22 : : # 23 [ + + ][ - + ]: 2717 : if (avoid_reuse && !can_avoid_reuse) { # 24 : 0 : throw JSONRPCError(RPC_WALLET_ERROR, "wallet does not have the \"avoid reuse\" feature enabled"); # 25 : 0 : } # 26 : : # 27 : 2717 : return avoid_reuse; # 28 : 2717 : } # 29 : : # 30 : : /** Used by RPC commands that have an include_watchonly parameter. # 31 : : * We default to true for watchonly wallets if include_watchonly isn't # 32 : : * explicitly set. # 33 : : */ # 34 : : bool ParseIncludeWatchonly(const UniValue& include_watchonly, const CWallet& wallet) # 35 : 2852 : { # 36 [ + + ]: 2852 : if (include_watchonly.isNull()) { # 37 : : // if include_watchonly isn't explicitly set, then check if we have a watchonly wallet # 38 : 2127 : return wallet.IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS); # 39 : 2127 : } # 40 : : # 41 : : // otherwise return whatever include_watchonly was set to # 42 : 725 : return include_watchonly.get_bool(); # 43 : 2852 : } # 44 : : # 45 : : bool GetWalletNameFromJSONRPCRequest(const JSONRPCRequest& request, std::string& wallet_name) # 46 : 26185 : { # 47 [ + + ][ + + ]: 26185 : if (URL_DECODE && request.URI.substr(0, WALLET_ENDPOINT_BASE.size()) == WALLET_ENDPOINT_BASE) { # [ + + ] # 48 : : // wallet endpoint was used # 49 : 8664 : wallet_name = URL_DECODE(request.URI.substr(WALLET_ENDPOINT_BASE.size())); # 50 : 8664 : return true; # 51 : 8664 : } # 52 : 17521 : return false; # 53 : 26185 : } # 54 : : # 55 : : std::shared_ptr<CWallet> GetWalletForJSONRPCRequest(const JSONRPCRequest& request) # 56 : 26006 : { # 57 [ - + ]: 26006 : CHECK_NONFATAL(request.mode == JSONRPCRequest::EXECUTE); # 58 : 26006 : WalletContext& context = EnsureWalletContext(request.context); # 59 : : # 60 : 26006 : std::string wallet_name; # 61 [ + + ]: 26006 : if (GetWalletNameFromJSONRPCRequest(request, wallet_name)) { # 62 : 8619 : const std::shared_ptr<CWallet> pwallet = GetWallet(context, wallet_name); # 63 [ + + ]: 8619 : if (!pwallet) throw JSONRPCError(RPC_WALLET_NOT_FOUND, "Requested wallet does not exist or is not loaded"); # 64 : 8600 : return pwallet; # 65 : 8619 : } # 66 : : # 67 : 17387 : std::vector<std::shared_ptr<CWallet>> wallets = GetWallets(context); # 68 [ + + ]: 17387 : if (wallets.size() == 1) { # 69 : 17358 : return wallets[0]; # 70 : 17358 : } # 71 : : # 72 [ + + ]: 29 : if (wallets.empty()) { # 73 : 7 : throw JSONRPCError( # 74 : 7 : 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)"); # 75 : 7 : } # 76 : 22 : throw JSONRPCError(RPC_WALLET_NOT_SPECIFIED, # 77 : 22 : "Wallet file not specified (must request wallet RPC through /wallet/<filename> uri-path)."); # 78 : 29 : } # 79 : : # 80 : : void EnsureWalletIsUnlocked(const CWallet& wallet) # 81 : 6753 : { # 82 [ + + ]: 6753 : if (wallet.IsLocked()) { # 83 : 21 : throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first."); # 84 : 21 : } # 85 : 6753 : } # 86 : : # 87 : : WalletContext& EnsureWalletContext(const std::any& context) # 88 : 26993 : { # 89 : 26993 : auto wallet_context = util::AnyPtr<WalletContext>(context); # 90 [ - + ]: 26993 : if (!wallet_context) { # 91 : 0 : throw JSONRPCError(RPC_INTERNAL_ERROR, "Wallet context not found"); # 92 : 0 : } # 93 : 26993 : return *wallet_context; # 94 : 26993 : } # 95 : : # 96 : : // 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 # 97 : : LegacyScriptPubKeyMan& EnsureLegacyScriptPubKeyMan(CWallet& wallet, bool also_create) # 98 : 645 : { # 99 : 645 : LegacyScriptPubKeyMan* spk_man = wallet.GetLegacyScriptPubKeyMan(); # 100 [ + + ][ + + ]: 645 : if (!spk_man && also_create) { # 101 : 7 : spk_man = wallet.GetOrCreateLegacyScriptPubKeyMan(); # 102 : 7 : } # 103 [ + + ]: 645 : if (!spk_man) { # 104 : 7 : throw JSONRPCError(RPC_WALLET_ERROR, "This type of wallet does not support this command"); # 105 : 7 : } # 106 : 638 : return *spk_man; # 107 : 645 : } # 108 : : # 109 : : const LegacyScriptPubKeyMan& EnsureConstLegacyScriptPubKeyMan(const CWallet& wallet) # 110 : 233 : { # 111 : 233 : const LegacyScriptPubKeyMan* spk_man = wallet.GetLegacyScriptPubKeyMan(); # 112 [ + + ]: 233 : if (!spk_man) { # 113 : 2 : throw JSONRPCError(RPC_WALLET_ERROR, "This type of wallet does not support this command"); # 114 : 2 : } # 115 : 231 : return *spk_man; # 116 : 233 : } # 117 : : # 118 : : std::string LabelFromValue(const UniValue& value) # 119 : 447 : { # 120 : 447 : std::string label = value.get_str(); # 121 [ - + ]: 447 : if (label == "*") # 122 : 0 : throw JSONRPCError(RPC_WALLET_INVALID_LABEL_NAME, "Invalid label name"); # 123 : 447 : return label; # 124 : 447 : } # 125 : : # 126 : : void HandleWalletError(const std::shared_ptr<CWallet> wallet, DatabaseStatus& status, bilingual_str& error) # 127 : 231 : { # 128 [ + + ]: 231 : if (!wallet) { # 129 : : // Map bad format to not found, since bad format is returned when the # 130 : : // wallet directory exists, but doesn't contain a data file. # 131 : 34 : RPCErrorCode code = RPC_WALLET_ERROR; # 132 : 34 : switch (status) { # 133 [ + + ]: 4 : case DatabaseStatus::FAILED_NOT_FOUND: # 134 [ + + ]: 9 : case DatabaseStatus::FAILED_BAD_FORMAT: # 135 : 9 : code = RPC_WALLET_NOT_FOUND; # 136 : 9 : break; # 137 [ + + ]: 4 : case DatabaseStatus::FAILED_ALREADY_LOADED: # 138 : 4 : code = RPC_WALLET_ALREADY_LOADED; # 139 : 4 : break; # 140 [ + + ]: 2 : case DatabaseStatus::FAILED_ALREADY_EXISTS: # 141 : 2 : code = RPC_WALLET_ALREADY_EXISTS; # 142 : 2 : break; # 143 [ + + ]: 2 : case DatabaseStatus::FAILED_INVALID_BACKUP_FILE: # 144 : 2 : code = RPC_INVALID_PARAMETER; # 145 : 2 : break; # 146 [ + + ]: 17 : default: // RPC_WALLET_ERROR is returned for all other cases. # 147 : 17 : break; # 148 : 34 : } # 149 : 34 : throw JSONRPCError(code, error.original); # 150 : 34 : } # 151 : 231 : } # 152 : : } // namespace wallet