Bitcoin Core  31.0.0
P2P Digital Currency
util.cpp
Go to the documentation of this file.
1 // Copyright (c) 2011-present 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 <common/url.h>
8 #include <rpc/util.h>
9 #include <util/any.h>
10 #include <util/translation.h>
11 #include <wallet/context.h>
12 #include <wallet/wallet.h>
13 
14 #include <optional>
15 #include <string_view>
16 #include <univalue.h>
17 
18 namespace wallet {
19 static const std::string WALLET_ENDPOINT_BASE = "/wallet/";
20 const std::string HELP_REQUIRING_PASSPHRASE{"\nRequires wallet passphrase to be set with walletpassphrase call if wallet is encrypted.\n"};
21 
22 bool GetAvoidReuseFlag(const CWallet& wallet, const UniValue& param) {
23  bool can_avoid_reuse = wallet.IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE);
24  bool avoid_reuse = param.isNull() ? can_avoid_reuse : param.get_bool();
25 
26  if (avoid_reuse && !can_avoid_reuse) {
27  throw JSONRPCError(RPC_WALLET_ERROR, "wallet does not have the \"avoid reuse\" feature enabled");
28  }
29 
30  return avoid_reuse;
31 }
32 
33 std::string EnsureUniqueWalletName(const JSONRPCRequest& request, std::optional<std::string_view> wallet_name)
34 {
35  std::string endpoint_wallet;
36  if (GetWalletNameFromJSONRPCRequest(request, endpoint_wallet)) {
37  // wallet endpoint was used
38  if (wallet_name && *wallet_name != endpoint_wallet) {
40  "The RPC endpoint wallet and the wallet name parameter specify different wallets");
41  }
42  return endpoint_wallet;
43  }
44 
45  // Not a wallet endpoint; parameter must be provided
46  if (!wallet_name) {
48  "Either the RPC endpoint wallet or the wallet name parameter must be provided");
49  }
50 
51  return std::string{*wallet_name};
52 }
53 
54 bool GetWalletNameFromJSONRPCRequest(const JSONRPCRequest& request, std::string& wallet_name)
55 {
56  if (request.URI.starts_with(WALLET_ENDPOINT_BASE)) {
57  // wallet endpoint was used
58  wallet_name = UrlDecode(std::string_view{request.URI}.substr(WALLET_ENDPOINT_BASE.size()));
59  return true;
60  }
61  return false;
62 }
63 
64 std::shared_ptr<CWallet> GetWalletForJSONRPCRequest(const JSONRPCRequest& request)
65 {
67  WalletContext& context = EnsureWalletContext(request.context);
68 
69  std::string wallet_name;
70  if (GetWalletNameFromJSONRPCRequest(request, wallet_name)) {
71  std::shared_ptr<CWallet> pwallet = GetWallet(context, wallet_name);
72  if (!pwallet) throw JSONRPCError(RPC_WALLET_NOT_FOUND, "Requested wallet does not exist or is not loaded");
73  return pwallet;
74  }
75 
76  size_t count{0};
77  auto wallet = GetDefaultWallet(context, count);
78  if (wallet) return wallet;
79 
80  if (count == 0) {
81  throw JSONRPCError(
82  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)");
83  }
85  "Multiple wallets are loaded. Please select which wallet to use by requesting the RPC through the /wallet/<walletname> URI path.");
86 }
87 
89 {
90  if (wallet.IsLocked()) {
91  throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first.");
92  }
93 }
94 
95 WalletContext& EnsureWalletContext(const std::any& context)
96 {
97  auto wallet_context = util::AnyPtr<WalletContext>(context);
98  if (!wallet_context) {
99  throw JSONRPCError(RPC_INTERNAL_ERROR, "Wallet context not found");
100  }
101  return *wallet_context;
102 }
103 
104 std::string LabelFromValue(const UniValue& value)
105 {
106  static const std::string empty_string;
107  if (value.isNull()) return empty_string;
108 
109  const std::string& label{value.get_str()};
110  if (label == "*")
111  throw JSONRPCError(RPC_WALLET_INVALID_LABEL_NAME, "Invalid label name");
112  return label;
113 }
114 
115 void PushParentDescriptors(const CWallet& wallet, const CScript& script_pubkey, UniValue& entry)
116 {
117  UniValue parent_descs(UniValue::VARR);
118  for (const auto& desc: wallet.GetWalletDescriptors(script_pubkey)) {
119  std::string desc_str;
120  FlatSigningProvider dummy_provider;
121  if (!CHECK_NONFATAL(desc.descriptor->ToNormalizedString(dummy_provider, desc_str, &desc.cache))) continue;
122  parent_descs.push_back(desc_str);
123  }
124  entry.pushKV("parent_descs", std::move(parent_descs));
125 }
126 
127 void HandleWalletError(const std::shared_ptr<CWallet>& wallet, DatabaseStatus& status, bilingual_str& error)
128 {
129  if (!wallet) {
130  // Map bad format to not found, since bad format is returned when the
131  // wallet directory exists, but doesn't contain a data file.
133  switch (status) {
137  code = RPC_WALLET_NOT_FOUND;
138  break;
141  break;
144  break;
147  code = RPC_INVALID_PARAMETER;
148  break;
151  break;
152  default: // RPC_WALLET_ERROR is returned for all other cases.
153  break;
154  }
155  throw JSONRPCError(code, error.original);
156  }
157 }
158 
160 {
161  AssertLockHeld(wallet.cs_wallet);
162  UniValue lastprocessedblock{UniValue::VOBJ};
163  lastprocessedblock.pushKV("hash", wallet.GetLastBlockHash().GetHex());
164  lastprocessedblock.pushKV("height", wallet.GetLastBlockHeight());
165  entry.pushKV("lastprocessedblock", std::move(lastprocessedblock));
166 }
167 
168 } // namespace wallet
No wallet specified (error when there are multiple wallets loaded)
Definition: protocol.h:81
void push_back(UniValue val)
Definition: univalue.cpp:103
std::any context
Definition: request.h:62
AssertLockHeld(pool.cs)
Enter the wallet passphrase with walletpassphrase first.
Definition: protocol.h:75
bool get_bool() const
Bilingual messages:
Definition: translation.h:24
#define CHECK_NONFATAL(condition)
Identity function.
Definition: check.h:109
const std::string & get_str() const
std::string UrlDecode(std::string_view url_encoded)
Definition: url.cpp:12
This same wallet is already loaded.
Definition: protocol.h:82
Invalid, missing or duplicate parameter.
Definition: protocol.h:44
void HandleWalletError(const std::shared_ptr< CWallet > &wallet, DatabaseStatus &status, bilingual_str &error)
Definition: util.cpp:127
UniValue JSONRPCError(int code, const std::string &message)
Definition: request.cpp:70
std::string LabelFromValue(const UniValue &value)
Definition: util.cpp:104
enum JSONRPCRequest::Mode mode
std::string EnsureUniqueWalletName(const JSONRPCRequest &request, std::optional< std::string_view > wallet_name)
Ensures that a wallet name is specified across the endpoint and wallet_name.
Definition: util.cpp:33
WalletContext & EnsureWalletContext(const std::any &context)
Definition: util.cpp:95
A CWallet maintains a set of transactions and balances, and provides the ability to create new transa...
Definition: wallet.h:309
Invalid wallet specified.
Definition: protocol.h:80
const std::string HELP_REQUIRING_PASSPHRASE
Definition: util.cpp:20
bool isNull() const
Definition: univalue.h:81
std::shared_ptr< CWallet > GetWallet(WalletContext &context, const std::string &name)
Definition: wallet.cpp:207
Failed to encrypt the wallet.
Definition: protocol.h:78
DatabaseStatus
Definition: db.h:186
std::string original
Definition: translation.h:25
void pushKV(std::string key, UniValue val)
Definition: univalue.cpp:125
Serialized script, used inside transaction inputs and outputs.
Definition: script.h:404
std::string URI
Definition: request.h:59
WalletContext struct containing references to state shared between CWallet instances, like the reference to the chain interface, and the list of opened wallets.
Definition: context.h:36
bool GetAvoidReuseFlag(const CWallet &wallet, const UniValue &param)
Definition: util.cpp:22
void EnsureWalletIsUnlocked(const CWallet &wallet)
Definition: util.cpp:88
static int count
Wallet errors.
Definition: protocol.h:71
There is already a wallet with the same name.
Definition: protocol.h:83
RPCErrorCode
Bitcoin RPC error codes.
Definition: protocol.h:24
void PushParentDescriptors(const CWallet &wallet, const CScript &script_pubkey, UniValue &entry)
Fetch parent descriptors of this scriptPubKey.
Definition: util.cpp:115
std::shared_ptr< CWallet > GetDefaultWallet(WalletContext &context, size_t &count)
Definition: wallet.cpp:200
Invalid label name.
Definition: protocol.h:73
static const std::string WALLET_ENDPOINT_BASE
Definition: util.cpp:19
void AppendLastProcessedBlock(UniValue &entry, const CWallet &wallet)
Definition: util.cpp:159
std::shared_ptr< CWallet > GetWalletForJSONRPCRequest(const JSONRPCRequest &request)
Figures out what wallet, if any, to use for a JSONRPCRequest.
Definition: util.cpp:64
bool GetWalletNameFromJSONRPCRequest(const JSONRPCRequest &request, std::string &wallet_name)
Definition: util.cpp:54