Bitcoin Core  27.99.0
P2P Digital Currency
util.cpp
Go to the documentation of this file.
1 // Copyright (c) 2011-2022 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 <univalue.h>
15 
16 #include <boost/date_time/posix_time/posix_time.hpp>
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 int64_t ParseISO8601DateTime(const std::string& str)
23 {
24  static const boost::posix_time::ptime epoch = boost::posix_time::from_time_t(0);
25  static const std::locale loc(std::locale::classic(),
26  new boost::posix_time::time_input_facet("%Y-%m-%dT%H:%M:%SZ"));
27  std::istringstream iss(str);
28  iss.imbue(loc);
29  boost::posix_time::ptime ptime(boost::date_time::not_a_date_time);
30  iss >> ptime;
31  if (ptime.is_not_a_date_time() || epoch > ptime)
32  return 0;
33  return (ptime - epoch).total_seconds();
34 }
35 
36 bool GetAvoidReuseFlag(const CWallet& wallet, const UniValue& param) {
37  bool can_avoid_reuse = wallet.IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE);
38  bool avoid_reuse = param.isNull() ? can_avoid_reuse : param.get_bool();
39 
40  if (avoid_reuse && !can_avoid_reuse) {
41  throw JSONRPCError(RPC_WALLET_ERROR, "wallet does not have the \"avoid reuse\" feature enabled");
42  }
43 
44  return avoid_reuse;
45 }
46 
51 bool ParseIncludeWatchonly(const UniValue& include_watchonly, const CWallet& wallet)
52 {
53  if (include_watchonly.isNull()) {
54  // if include_watchonly isn't explicitly set, then check if we have a watchonly wallet
55  return wallet.IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS);
56  }
57 
58  // otherwise return whatever include_watchonly was set to
59  return include_watchonly.get_bool();
60 }
61 
62 bool GetWalletNameFromJSONRPCRequest(const JSONRPCRequest& request, std::string& wallet_name)
63 {
64  if (URL_DECODE && request.URI.substr(0, WALLET_ENDPOINT_BASE.size()) == WALLET_ENDPOINT_BASE) {
65  // wallet endpoint was used
66  wallet_name = URL_DECODE(request.URI.substr(WALLET_ENDPOINT_BASE.size()));
67  return true;
68  }
69  return false;
70 }
71 
72 std::shared_ptr<CWallet> GetWalletForJSONRPCRequest(const JSONRPCRequest& request)
73 {
75  WalletContext& context = EnsureWalletContext(request.context);
76 
77  std::string wallet_name;
78  if (GetWalletNameFromJSONRPCRequest(request, wallet_name)) {
79  std::shared_ptr<CWallet> pwallet = GetWallet(context, wallet_name);
80  if (!pwallet) throw JSONRPCError(RPC_WALLET_NOT_FOUND, "Requested wallet does not exist or is not loaded");
81  return pwallet;
82  }
83 
84  size_t count{0};
85  auto wallet = GetDefaultWallet(context, count);
86  if (wallet) return wallet;
87 
88  if (count == 0) {
89  throw JSONRPCError(
90  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)");
91  }
93  "Wallet file not specified (must request wallet RPC through /wallet/<filename> uri-path).");
94 }
95 
97 {
98  if (wallet.IsLocked()) {
99  throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first.");
100  }
101 }
102 
103 WalletContext& EnsureWalletContext(const std::any& context)
104 {
105  auto wallet_context = util::AnyPtr<WalletContext>(context);
106  if (!wallet_context) {
107  throw JSONRPCError(RPC_INTERNAL_ERROR, "Wallet context not found");
108  }
109  return *wallet_context;
110 }
111 
112 // 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
114 {
115  LegacyScriptPubKeyMan* spk_man = wallet.GetLegacyScriptPubKeyMan();
116  if (!spk_man && also_create) {
117  spk_man = wallet.GetOrCreateLegacyScriptPubKeyMan();
118  }
119  if (!spk_man) {
120  throw JSONRPCError(RPC_WALLET_ERROR, "Only legacy wallets are supported by this command");
121  }
122  return *spk_man;
123 }
124 
126 {
127  const LegacyScriptPubKeyMan* spk_man = wallet.GetLegacyScriptPubKeyMan();
128  if (!spk_man) {
129  throw JSONRPCError(RPC_WALLET_ERROR, "Only legacy wallets are supported by this command");
130  }
131  return *spk_man;
132 }
133 
134 std::string LabelFromValue(const UniValue& value)
135 {
136  static const std::string empty_string;
137  if (value.isNull()) return empty_string;
138 
139  const std::string& label{value.get_str()};
140  if (label == "*")
141  throw JSONRPCError(RPC_WALLET_INVALID_LABEL_NAME, "Invalid label name");
142  return label;
143 }
144 
145 void PushParentDescriptors(const CWallet& wallet, const CScript& script_pubkey, UniValue& entry)
146 {
147  UniValue parent_descs(UniValue::VARR);
148  for (const auto& desc: wallet.GetWalletDescriptors(script_pubkey)) {
149  parent_descs.push_back(desc.descriptor->ToString());
150  }
151  entry.pushKV("parent_descs", parent_descs);
152 }
153 
154 void HandleWalletError(const std::shared_ptr<CWallet> wallet, DatabaseStatus& status, bilingual_str& error)
155 {
156  if (!wallet) {
157  // Map bad format to not found, since bad format is returned when the
158  // wallet directory exists, but doesn't contain a data file.
160  switch (status) {
163  code = RPC_WALLET_NOT_FOUND;
164  break;
167  break;
170  break;
172  code = RPC_INVALID_PARAMETER;
173  break;
174  default: // RPC_WALLET_ERROR is returned for all other cases.
175  break;
176  }
177  throw JSONRPCError(code, error.original);
178  }
179 }
180 
182 {
183  AssertLockHeld(wallet.cs_wallet);
184  UniValue lastprocessedblock{UniValue::VOBJ};
185  lastprocessedblock.pushKV("hash", wallet.GetLastBlockHash().GetHex());
186  lastprocessedblock.pushKV("height", wallet.GetLastBlockHeight());
187  entry.pushKV("lastprocessedblock", lastprocessedblock);
188 }
189 
190 } // namespace wallet
UrlDecodeFn *const URL_DECODE
Definition: bitcoin-cli.cpp:54
#define CHECK_NONFATAL(condition)
Identity function.
Definition: check.h:73
Serialized script, used inside transaction inputs and outputs.
Definition: script.h:414
enum JSONRPCRequest::Mode mode
std::string URI
Definition: request.h:35
std::any context
Definition: request.h:38
void push_back(UniValue val)
Definition: univalue.cpp:104
const std::string & get_str() const
@ VOBJ
Definition: univalue.h:24
@ VARR
Definition: univalue.h:24
bool isNull() const
Definition: univalue.h:79
void pushKV(std::string key, UniValue val)
Definition: univalue.cpp:126
bool get_bool() const
A CWallet maintains a set of transactions and balances, and provides the ability to create new transa...
Definition: wallet.h:301
void AppendLastProcessedBlock(UniValue &entry, const CWallet &wallet) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet)
Definition: util.cpp:181
std::shared_ptr< CWallet > GetWalletForJSONRPCRequest(const JSONRPCRequest &request)
Figures out what wallet, if any, to use for a JSONRPCRequest.
Definition: util.cpp:72
bool GetWalletNameFromJSONRPCRequest(const JSONRPCRequest &request, std::string &wallet_name)
Definition: util.cpp:62
void HandleWalletError(const std::shared_ptr< CWallet > wallet, DatabaseStatus &status, bilingual_str &error)
Definition: util.cpp:154
void EnsureWalletIsUnlocked(const CWallet &wallet)
Definition: util.cpp:96
const LegacyScriptPubKeyMan & EnsureConstLegacyScriptPubKeyMan(const CWallet &wallet)
Definition: util.cpp:125
const std::string HELP_REQUIRING_PASSPHRASE
Definition: util.cpp:20
void PushParentDescriptors(const CWallet &wallet, const CScript &script_pubkey, UniValue &entry)
Fetch parent descriptors of this scriptPubKey.
Definition: util.cpp:145
LegacyScriptPubKeyMan & EnsureLegacyScriptPubKeyMan(CWallet &wallet, bool also_create)
Definition: util.cpp:113
WalletContext & EnsureWalletContext(const std::any &context)
Definition: util.cpp:103
std::string LabelFromValue(const UniValue &value)
Definition: util.cpp:134
bool ParseIncludeWatchonly(const UniValue &include_watchonly, const CWallet &wallet)
Used by RPC commands that have an include_watchonly parameter.
Definition: util.cpp:51
int64_t ParseISO8601DateTime(const std::string &str)
Definition: util.cpp:22
bool GetAvoidReuseFlag(const CWallet &wallet, const UniValue &param)
Definition: util.cpp:36
@ WALLET_FLAG_AVOID_REUSE
Definition: walletutil.h:42
@ WALLET_FLAG_DISABLE_PRIVATE_KEYS
Definition: walletutil.h:51
std::shared_ptr< CWallet > GetWallet(WalletContext &context, const std::string &name)
Definition: wallet.cpp:191
static const std::string WALLET_ENDPOINT_BASE
Definition: util.cpp:19
DatabaseStatus
Definition: db.h:196
std::shared_ptr< CWallet > GetDefaultWallet(WalletContext &context, size_t &count)
Definition: wallet.cpp:184
std::shared_ptr< CWallet > wallet
UniValue JSONRPCError(int code, const std::string &message)
Definition: request.cpp:58
RPCErrorCode
Bitcoin RPC error codes.
Definition: protocol.h:24
@ RPC_WALLET_NOT_SPECIFIED
No wallet specified (error when there are multiple wallets loaded)
Definition: protocol.h:81
@ RPC_WALLET_INVALID_LABEL_NAME
Invalid label name.
Definition: protocol.h:73
@ RPC_WALLET_UNLOCK_NEEDED
Enter the wallet passphrase with walletpassphrase first.
Definition: protocol.h:75
@ RPC_WALLET_ALREADY_EXISTS
There is already a wallet with the same name.
Definition: protocol.h:83
@ RPC_INVALID_PARAMETER
Invalid, missing or duplicate parameter.
Definition: protocol.h:43
@ RPC_WALLET_ERROR
Wallet errors.
Definition: protocol.h:71
@ RPC_WALLET_ALREADY_LOADED
This same wallet is already loaded.
Definition: protocol.h:82
@ RPC_WALLET_NOT_FOUND
Invalid wallet specified.
Definition: protocol.h:80
@ RPC_INTERNAL_ERROR
Definition: protocol.h:35
Bilingual messages:
Definition: translation.h:18
std::string original
Definition: translation.h:19
WalletContext struct containing references to state shared between CWallet instances,...
Definition: context.h:36
static int count
static const std::string empty_string
Definition: threadnames.cpp:54
#define EXCLUSIVE_LOCKS_REQUIRED(...)
Definition: threadsafety.h:49
AssertLockHeld(pool.cs)