// 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 #include namespace wallet { 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; } size_t count{0}; auto wallet = GetDefaultWallet(context, count); if (wallet) return wallet; if (count == 0) { 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, "Only legacy wallets are supported by 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, "Only legacy wallets are supported by 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; } void PushParentDescriptors(const CWallet& wallet, const CScript& script_pubkey, UniValue& entry) { UniValue parent_descs(UniValue::VARR); for (const auto& desc: wallet.GetWalletDescriptors(script_pubkey)) { parent_descs.push_back(desc.descriptor->ToString()); } entry.pushKV("parent_descs", parent_descs); } void HandleWalletError(const std::shared_ptr wallet, DatabaseStatus& status, bilingual_str& error) { if (!wallet) { // Map bad format to not found, since bad format is returned when the // wallet directory exists, but doesn't contain a data file. RPCErrorCode code = RPC_WALLET_ERROR; switch (status) { case DatabaseStatus::FAILED_NOT_FOUND: case DatabaseStatus::FAILED_BAD_FORMAT: code = RPC_WALLET_NOT_FOUND; break; case DatabaseStatus::FAILED_ALREADY_LOADED: code = RPC_WALLET_ALREADY_LOADED; break; case DatabaseStatus::FAILED_ALREADY_EXISTS: code = RPC_WALLET_ALREADY_EXISTS; break; case DatabaseStatus::FAILED_INVALID_BACKUP_FILE: code = RPC_INVALID_PARAMETER; break; default: // RPC_WALLET_ERROR is returned for all other cases. break; } throw JSONRPCError(code, error.original); } } } // namespace wallet