Bitcoin Core  29.1.0
P2P Digital Currency
bitcoin-cli.cpp
Go to the documentation of this file.
1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2022 The Bitcoin Core developers
3 // Distributed under the MIT software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5 
6 #include <bitcoin-build-config.h> // IWYU pragma: keep
7 
8 #include <chainparamsbase.h>
9 #include <clientversion.h>
10 #include <common/args.h>
11 #include <common/system.h>
12 #include <compat/compat.h>
13 #include <compat/stdin.h>
14 #include <policy/feerate.h>
15 #include <rpc/client.h>
16 #include <rpc/mining.h>
17 #include <rpc/protocol.h>
18 #include <rpc/request.h>
19 #include <tinyformat.h>
20 #include <univalue.h>
21 #include <util/chaintype.h>
22 #include <util/exception.h>
23 #include <util/strencodings.h>
24 #include <util/time.h>
25 #include <util/translation.h>
26 
27 #include <algorithm>
28 #include <chrono>
29 #include <cmath>
30 #include <cstdio>
31 #include <functional>
32 #include <memory>
33 #include <optional>
34 #include <string>
35 #include <tuple>
36 
37 #ifndef WIN32
38 #include <unistd.h>
39 #endif
40 
41 #include <event2/buffer.h>
42 #include <event2/keyvalq_struct.h>
43 #include <support/events.h>
44 
45 using util::Join;
46 using util::ToString;
47 
48 // The server returns time values from a mockable system clock, but it is not
49 // trivial to get the mocked time from the server, nor is it needed for now, so
50 // just use a plain system_clock.
51 using CliClock = std::chrono::system_clock;
52 
54 
55 static const char DEFAULT_RPCCONNECT[] = "127.0.0.1";
56 static const int DEFAULT_HTTP_CLIENT_TIMEOUT=900;
57 static constexpr int DEFAULT_WAIT_CLIENT_TIMEOUT = 0;
58 static const bool DEFAULT_NAMED=false;
59 static const int CONTINUE_EXECUTION=-1;
60 static constexpr uint8_t NETINFO_MAX_LEVEL{4};
61 static constexpr int8_t UNKNOWN_NETWORK{-1};
62 // See GetNetworkName() in netbase.cpp
63 static constexpr std::array NETWORKS{"not_publicly_routable", "ipv4", "ipv6", "onion", "i2p", "cjdns", "internal"};
64 static constexpr std::array NETWORK_SHORT_NAMES{"npr", "ipv4", "ipv6", "onion", "i2p", "cjdns", "int"};
65 static constexpr std::array UNREACHABLE_NETWORK_IDS{/*not_publicly_routable*/0, /*internal*/6};
66 
68 static const std::string DEFAULT_NBLOCKS = "1";
69 
71 static const std::string DEFAULT_COLOR_SETTING{"auto"};
72 
73 static void SetupCliArgs(ArgsManager& argsman)
74 {
75  SetupHelpOptions(argsman);
76 
77  const auto defaultBaseParams = CreateBaseChainParams(ChainType::MAIN);
78  const auto testnetBaseParams = CreateBaseChainParams(ChainType::TESTNET);
79  const auto testnet4BaseParams = CreateBaseChainParams(ChainType::TESTNET4);
80  const auto signetBaseParams = CreateBaseChainParams(ChainType::SIGNET);
81  const auto regtestBaseParams = CreateBaseChainParams(ChainType::REGTEST);
82 
83  argsman.AddArg("-version", "Print version and exit", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
84  argsman.AddArg("-conf=<file>", strprintf("Specify configuration file. Relative paths will be prefixed by datadir location. (default: %s)", BITCOIN_CONF_FILENAME), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
85  argsman.AddArg("-datadir=<dir>", "Specify data directory", ArgsManager::ALLOW_ANY | ArgsManager::DISALLOW_NEGATION, OptionsCategory::OPTIONS);
86  argsman.AddArg("-generate",
87  strprintf("Generate blocks, equivalent to RPC getnewaddress followed by RPC generatetoaddress. Optional positional integer "
88  "arguments are number of blocks to generate (default: %s) and maximum iterations to try (default: %s), equivalent to "
89  "RPC generatetoaddress nblocks and maxtries arguments. Example: bitcoin-cli -generate 4 1000",
92  argsman.AddArg("-addrinfo", "Get the number of addresses known to the node, per network and total, after filtering for quality and recency. The total number of addresses known to the node may be higher.", ArgsManager::ALLOW_ANY, OptionsCategory::CLI_COMMANDS);
93  argsman.AddArg("-getinfo", "Get general information from the remote server. Note that unlike server-side RPC calls, the output of -getinfo is the result of multiple non-atomic requests. Some entries in the output may represent results from different states (e.g. wallet balance may be as of a different block from the chain state reported)", ArgsManager::ALLOW_ANY, OptionsCategory::CLI_COMMANDS);
94  argsman.AddArg("-netinfo", strprintf("Get network peer connection information from the remote server. An optional argument from 0 to %d can be passed for different peers listings (default: 0). If a non-zero value is passed, an additional \"outonly\" (or \"o\") argument can be passed to see outbound peers only. Pass \"help\" (or \"h\") for detailed help documentation.", NETINFO_MAX_LEVEL), ArgsManager::ALLOW_ANY, OptionsCategory::CLI_COMMANDS);
95 
97  argsman.AddArg("-color=<when>", strprintf("Color setting for CLI output (default: %s). Valid values: always, auto (add color codes when standard output is connected to a terminal and OS is not WIN32), never. Only applies to the output of -getinfo.", DEFAULT_COLOR_SETTING), ArgsManager::ALLOW_ANY | ArgsManager::DISALLOW_NEGATION, OptionsCategory::OPTIONS);
98  argsman.AddArg("-named", strprintf("Pass named instead of positional arguments (default: %s)", DEFAULT_NAMED), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
99  argsman.AddArg("-rpcclienttimeout=<n>", strprintf("Timeout in seconds during HTTP requests, or 0 for no timeout. (default: %d)", DEFAULT_HTTP_CLIENT_TIMEOUT), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
100  argsman.AddArg("-rpcconnect=<ip>", strprintf("Send commands to node running on <ip> (default: %s)", DEFAULT_RPCCONNECT), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
101  argsman.AddArg("-rpccookiefile=<loc>", "Location of the auth cookie. Relative paths will be prefixed by a net-specific datadir location. (default: data dir)", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
102  argsman.AddArg("-rpcpassword=<pw>", "Password for JSON-RPC connections", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
103  argsman.AddArg("-rpcport=<port>", strprintf("Connect to JSON-RPC on <port> (default: %u, testnet: %u, testnet4: %u, signet: %u, regtest: %u)", defaultBaseParams->RPCPort(), testnetBaseParams->RPCPort(), testnet4BaseParams->RPCPort(), signetBaseParams->RPCPort(), regtestBaseParams->RPCPort()), ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::OPTIONS);
104  argsman.AddArg("-rpcuser=<user>", "Username for JSON-RPC connections", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
105  argsman.AddArg("-rpcwait", "Wait for RPC server to start", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
106  argsman.AddArg("-rpcwaittimeout=<n>", strprintf("Timeout in seconds to wait for the RPC server to start, or 0 for no timeout. (default: %d)", DEFAULT_WAIT_CLIENT_TIMEOUT), ArgsManager::ALLOW_ANY | ArgsManager::DISALLOW_NEGATION, OptionsCategory::OPTIONS);
107  argsman.AddArg("-rpcwallet=<walletname>", "Send RPC for non-default wallet on RPC server (needs to exactly match corresponding -wallet option passed to bitcoind). This changes the RPC endpoint used, e.g. http://127.0.0.1:8332/wallet/<walletname>", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
108  argsman.AddArg("-stdin", "Read extra arguments from standard input, one per line until EOF/Ctrl-D (recommended for sensitive information such as passphrases). When combined with -stdinrpcpass, the first line from standard input is used for the RPC password.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
109  argsman.AddArg("-stdinrpcpass", "Read RPC password from standard input as a single line. When combined with -stdin, the first line from standard input is used for the RPC password. When combined with -stdinwalletpassphrase, -stdinrpcpass consumes the first line, and -stdinwalletpassphrase consumes the second.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
110  argsman.AddArg("-stdinwalletpassphrase", "Read wallet passphrase from standard input as a single line. When combined with -stdin, the first line from standard input is used for the wallet passphrase.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
111 }
112 
113 std::optional<std::string> RpcWalletName(const ArgsManager& args)
114 {
115  // Check IsArgNegated to return nullopt instead of "0" if -norpcwallet is specified
116  if (args.IsArgNegated("-rpcwallet")) return std::nullopt;
117  return args.GetArg("-rpcwallet");
118 }
119 
121 static void libevent_log_cb(int severity, const char *msg)
122 {
123  // Ignore everything other than errors
124  if (severity >= EVENT_LOG_ERR) {
125  throw std::runtime_error(strprintf("libevent error: %s", msg));
126  }
127 }
128 
129 //
130 // Exception thrown on connection error. This error is used to determine
131 // when to wait if -rpcwait is given.
132 //
133 class CConnectionFailed : public std::runtime_error
134 {
135 public:
136 
137  explicit inline CConnectionFailed(const std::string& msg) :
138  std::runtime_error(msg)
139  {}
140 
141 };
142 
143 //
144 // This function returns either one of EXIT_ codes when it's expected to stop the process or
145 // CONTINUE_EXECUTION when it's expected to continue further.
146 //
147 static int AppInitRPC(int argc, char* argv[])
148 {
150  std::string error;
151  if (!gArgs.ParseParameters(argc, argv, error)) {
152  tfm::format(std::cerr, "Error parsing command line arguments: %s\n", error);
153  return EXIT_FAILURE;
154  }
155  if (argc < 2 || HelpRequested(gArgs) || gArgs.GetBoolArg("-version", false)) {
156  std::string strUsage = CLIENT_NAME " RPC client version " + FormatFullVersion() + "\n";
157 
158  if (gArgs.GetBoolArg("-version", false)) {
159  strUsage += FormatParagraph(LicenseInfo());
160  } else {
161  strUsage += "\n"
162  "The bitcoin-cli utility provides a command line interface to interact with a " CLIENT_NAME " RPC server.\n"
163  "\nIt can be used to query network information, manage wallets, create or broadcast transactions, and control the " CLIENT_NAME " server.\n"
164  "\nUse the \"help\" command to list all commands. Use \"help <command>\" to show help for that command.\n"
165  "The -named option allows you to specify parameters using the key=value format, eliminating the need to pass unused positional parameters.\n"
166  "\n"
167  "Usage: bitcoin-cli [options] <command> [params]\n"
168  "or: bitcoin-cli [options] -named <command> [name=value]...\n"
169  "or: bitcoin-cli [options] help\n"
170  "or: bitcoin-cli [options] help <command>\n"
171  "\n";
172  strUsage += "\n" + gArgs.GetHelpMessage();
173  }
174 
175  tfm::format(std::cout, "%s", strUsage);
176  if (argc < 2) {
177  tfm::format(std::cerr, "Error: too few parameters\n");
178  return EXIT_FAILURE;
179  }
180  return EXIT_SUCCESS;
181  }
182  if (!CheckDataDirOption(gArgs)) {
183  tfm::format(std::cerr, "Error: Specified data directory \"%s\" does not exist.\n", gArgs.GetArg("-datadir", ""));
184  return EXIT_FAILURE;
185  }
186  if (!gArgs.ReadConfigFiles(error, true)) {
187  tfm::format(std::cerr, "Error reading configuration file: %s\n", error);
188  return EXIT_FAILURE;
189  }
190  // Check for chain settings (BaseParams() calls are only valid after this clause)
191  try {
193  } catch (const std::exception& e) {
194  tfm::format(std::cerr, "Error: %s\n", e.what());
195  return EXIT_FAILURE;
196  }
197  return CONTINUE_EXECUTION;
198 }
199 
200 
202 struct HTTPReply
203 {
204  HTTPReply() = default;
205 
206  int status{0};
207  int error{-1};
208  std::string body;
209 };
210 
211 static std::string http_errorstring(int code)
212 {
213  switch(code) {
214  case EVREQ_HTTP_TIMEOUT:
215  return "timeout reached";
216  case EVREQ_HTTP_EOF:
217  return "EOF reached";
218  case EVREQ_HTTP_INVALID_HEADER:
219  return "error while reading header, or invalid header";
220  case EVREQ_HTTP_BUFFER_ERROR:
221  return "error encountered while reading or writing";
222  case EVREQ_HTTP_REQUEST_CANCEL:
223  return "request was canceled";
224  case EVREQ_HTTP_DATA_TOO_LONG:
225  return "response body is larger than allowed";
226  default:
227  return "unknown";
228  }
229 }
230 
231 static void http_request_done(struct evhttp_request *req, void *ctx)
232 {
233  HTTPReply *reply = static_cast<HTTPReply*>(ctx);
234 
235  if (req == nullptr) {
236  /* If req is nullptr, it means an error occurred while connecting: the
237  * error code will have been passed to http_error_cb.
238  */
239  reply->status = 0;
240  return;
241  }
242 
243  reply->status = evhttp_request_get_response_code(req);
244 
245  struct evbuffer *buf = evhttp_request_get_input_buffer(req);
246  if (buf)
247  {
248  size_t size = evbuffer_get_length(buf);
249  const char *data = (const char*)evbuffer_pullup(buf, size);
250  if (data)
251  reply->body = std::string(data, size);
252  evbuffer_drain(buf, size);
253  }
254 }
255 
256 static void http_error_cb(enum evhttp_request_error err, void *ctx)
257 {
258  HTTPReply *reply = static_cast<HTTPReply*>(ctx);
259  reply->error = err;
260 }
261 
266 {
267 public:
268  virtual ~BaseRequestHandler() = default;
269  virtual UniValue PrepareRequest(const std::string& method, const std::vector<std::string>& args) = 0;
270  virtual UniValue ProcessReply(const UniValue &batch_in) = 0;
271 };
272 
275 {
276 private:
277  int8_t NetworkStringToId(const std::string& str) const
278  {
279  for (size_t i = 0; i < NETWORKS.size(); ++i) {
280  if (str == NETWORKS[i]) return i;
281  }
282  return UNKNOWN_NETWORK;
283  }
284 
285 public:
286  UniValue PrepareRequest(const std::string& method, const std::vector<std::string>& args) override
287  {
288  if (!args.empty()) {
289  throw std::runtime_error("-addrinfo takes no arguments");
290  }
291  UniValue params{RPCConvertValues("getnodeaddresses", std::vector<std::string>{{"0"}})};
292  return JSONRPCRequestObj("getnodeaddresses", params, 1);
293  }
294 
295  UniValue ProcessReply(const UniValue& reply) override
296  {
297  if (!reply["error"].isNull()) return reply;
298  const std::vector<UniValue>& nodes{reply["result"].getValues()};
299  if (!nodes.empty() && nodes.at(0)["network"].isNull()) {
300  throw std::runtime_error("-addrinfo requires bitcoind server to be running v22.0 and up");
301  }
302  // Count the number of peers known to our node, by network.
303  std::array<uint64_t, NETWORKS.size()> counts{{}};
304  for (const UniValue& node : nodes) {
305  std::string network_name{node["network"].get_str()};
306  const int8_t network_id{NetworkStringToId(network_name)};
307  if (network_id == UNKNOWN_NETWORK) continue;
308  ++counts.at(network_id);
309  }
310  // Prepare result to return to user.
312  uint64_t total{0}; // Total address count
313  for (size_t i = 1; i < NETWORKS.size() - 1; ++i) {
314  addresses.pushKV(NETWORKS[i], counts.at(i));
315  total += counts.at(i);
316  }
317  addresses.pushKV("total", total);
318  result.pushKV("addresses_known", std::move(addresses));
319  return JSONRPCReplyObj(std::move(result), NullUniValue, /*id=*/1, JSONRPCVersion::V2);
320  }
321 };
322 
325 {
326 public:
327  const int ID_NETWORKINFO = 0;
328  const int ID_BLOCKCHAININFO = 1;
329  const int ID_WALLETINFO = 2;
330  const int ID_BALANCES = 3;
331 
333  UniValue PrepareRequest(const std::string& method, const std::vector<std::string>& args) override
334  {
335  if (!args.empty()) {
336  throw std::runtime_error("-getinfo takes no arguments");
337  }
339  result.push_back(JSONRPCRequestObj("getnetworkinfo", NullUniValue, ID_NETWORKINFO));
340  result.push_back(JSONRPCRequestObj("getblockchaininfo", NullUniValue, ID_BLOCKCHAININFO));
341  result.push_back(JSONRPCRequestObj("getwalletinfo", NullUniValue, ID_WALLETINFO));
342  result.push_back(JSONRPCRequestObj("getbalances", NullUniValue, ID_BALANCES));
343  return result;
344  }
345 
347  UniValue ProcessReply(const UniValue &batch_in) override
348  {
350  const std::vector<UniValue> batch = JSONRPCProcessBatchReply(batch_in);
351  // Errors in getnetworkinfo() and getblockchaininfo() are fatal, pass them on;
352  // getwalletinfo() and getbalances() are allowed to fail if there is no wallet.
353  if (!batch[ID_NETWORKINFO]["error"].isNull()) {
354  return batch[ID_NETWORKINFO];
355  }
356  if (!batch[ID_BLOCKCHAININFO]["error"].isNull()) {
357  return batch[ID_BLOCKCHAININFO];
358  }
359  result.pushKV("version", batch[ID_NETWORKINFO]["result"]["version"]);
360  result.pushKV("blocks", batch[ID_BLOCKCHAININFO]["result"]["blocks"]);
361  result.pushKV("headers", batch[ID_BLOCKCHAININFO]["result"]["headers"]);
362  result.pushKV("verificationprogress", batch[ID_BLOCKCHAININFO]["result"]["verificationprogress"]);
363  result.pushKV("timeoffset", batch[ID_NETWORKINFO]["result"]["timeoffset"]);
364 
365  UniValue connections(UniValue::VOBJ);
366  connections.pushKV("in", batch[ID_NETWORKINFO]["result"]["connections_in"]);
367  connections.pushKV("out", batch[ID_NETWORKINFO]["result"]["connections_out"]);
368  connections.pushKV("total", batch[ID_NETWORKINFO]["result"]["connections"]);
369  result.pushKV("connections", std::move(connections));
370 
371  result.pushKV("networks", batch[ID_NETWORKINFO]["result"]["networks"]);
372  result.pushKV("difficulty", batch[ID_BLOCKCHAININFO]["result"]["difficulty"]);
373  result.pushKV("chain", UniValue(batch[ID_BLOCKCHAININFO]["result"]["chain"]));
374  if (!batch[ID_WALLETINFO]["result"].isNull()) {
375  result.pushKV("has_wallet", true);
376  result.pushKV("keypoolsize", batch[ID_WALLETINFO]["result"]["keypoolsize"]);
377  result.pushKV("walletname", batch[ID_WALLETINFO]["result"]["walletname"]);
378  if (!batch[ID_WALLETINFO]["result"]["unlocked_until"].isNull()) {
379  result.pushKV("unlocked_until", batch[ID_WALLETINFO]["result"]["unlocked_until"]);
380  }
381  result.pushKV("paytxfee", batch[ID_WALLETINFO]["result"]["paytxfee"]);
382  }
383  if (!batch[ID_BALANCES]["result"].isNull()) {
384  result.pushKV("balance", batch[ID_BALANCES]["result"]["mine"]["trusted"]);
385  }
386  result.pushKV("relayfee", batch[ID_NETWORKINFO]["result"]["relayfee"]);
387  result.pushKV("warnings", batch[ID_NETWORKINFO]["result"]["warnings"]);
388  return JSONRPCReplyObj(std::move(result), NullUniValue, /*id=*/1, JSONRPCVersion::V2);
389  }
390 };
391 
394 {
395 private:
396  std::array<std::array<uint16_t, NETWORKS.size() + 1>, 3> m_counts{{{}}};
399  int8_t NetworkStringToId(const std::string& str) const
400  {
401  for (size_t i = 0; i < NETWORKS.size(); ++i) {
402  if (str == NETWORKS[i]) return i;
403  }
404  return UNKNOWN_NETWORK;
405  }
406  uint8_t m_details_level{0};
407  bool DetailsRequested() const { return m_details_level > 0 && m_details_level < 5; }
408  bool IsAddressSelected() const { return m_details_level == 2 || m_details_level == 4; }
409  bool IsVersionSelected() const { return m_details_level == 3 || m_details_level == 4; }
411  bool m_is_asmap_on{false};
412  size_t m_max_addr_length{0};
415  size_t m_max_age_length{5};
416  size_t m_max_id_length{2};
418  struct Peer {
419  std::string addr;
420  std::string sub_version;
421  std::string conn_type;
422  std::string network;
423  std::string age;
424  std::string services;
426  double min_ping;
427  double ping;
428  int64_t addr_processed;
430  int64_t last_blck;
431  int64_t last_recv;
432  int64_t last_send;
433  int64_t last_trxn;
434  int id;
436  int version;
442  bool operator<(const Peer& rhs) const { return std::tie(is_outbound, min_ping) < std::tie(rhs.is_outbound, rhs.min_ping); }
443  };
444  std::vector<Peer> m_peers;
445  std::string ChainToString() const
446  {
447  switch (gArgs.GetChainType()) {
448  case ChainType::TESTNET4:
449  return " testnet4";
450  case ChainType::TESTNET:
451  return " testnet";
452  case ChainType::SIGNET:
453  return " signet";
454  case ChainType::REGTEST:
455  return " regtest";
456  case ChainType::MAIN:
457  return "";
458  }
459  assert(false);
460  }
461  std::string PingTimeToString(double seconds) const
462  {
463  if (seconds < 0) return "";
464  const double milliseconds{round(1000 * seconds)};
465  return milliseconds > 999999 ? "-" : ToString(milliseconds);
466  }
467  std::string ConnectionTypeForNetinfo(const std::string& conn_type) const
468  {
469  if (conn_type == "outbound-full-relay") return "full";
470  if (conn_type == "block-relay-only") return "block";
471  if (conn_type == "manual" || conn_type == "feeler") return conn_type;
472  if (conn_type == "addr-fetch") return "addr";
473  return "";
474  }
475  std::string FormatServices(const UniValue& services)
476  {
477  std::string str;
478  for (size_t i = 0; i < services.size(); ++i) {
479  const std::string s{services[i].get_str()};
480  str += s == "NETWORK_LIMITED" ? 'l' : s == "P2P_V2" ? '2' : ToLower(s[0]);
481  }
482  return str;
483  }
484 
485 public:
486  static constexpr int ID_PEERINFO = 0;
487  static constexpr int ID_NETWORKINFO = 1;
488 
489  UniValue PrepareRequest(const std::string& method, const std::vector<std::string>& args) override
490  {
491  if (!args.empty()) {
492  uint8_t n{0};
493  if (ParseUInt8(args.at(0), &n)) {
494  m_details_level = std::min(n, NETINFO_MAX_LEVEL);
495  } else {
496  throw std::runtime_error(strprintf("invalid -netinfo level argument: %s\nFor more information, run: bitcoin-cli -netinfo help", args.at(0)));
497  }
498  if (args.size() > 1) {
499  if (std::string_view s{args.at(1)}; n && (s == "o" || s == "outonly")) {
501  } else if (n) {
502  throw std::runtime_error(strprintf("invalid -netinfo outonly argument: %s\nFor more information, run: bitcoin-cli -netinfo help", s));
503  } else {
504  throw std::runtime_error(strprintf("invalid -netinfo outonly argument: %s\nThe outonly argument is only valid for a level greater than 0 (the first argument). For more information, run: bitcoin-cli -netinfo help", s));
505  }
506  }
507  }
509  result.push_back(JSONRPCRequestObj("getpeerinfo", NullUniValue, ID_PEERINFO));
510  result.push_back(JSONRPCRequestObj("getnetworkinfo", NullUniValue, ID_NETWORKINFO));
511  return result;
512  }
513 
514  UniValue ProcessReply(const UniValue& batch_in) override
515  {
516  const std::vector<UniValue> batch{JSONRPCProcessBatchReply(batch_in)};
517  if (!batch[ID_PEERINFO]["error"].isNull()) return batch[ID_PEERINFO];
518  if (!batch[ID_NETWORKINFO]["error"].isNull()) return batch[ID_NETWORKINFO];
519 
520  const UniValue& networkinfo{batch[ID_NETWORKINFO]["result"]};
521  if (networkinfo["version"].getInt<int>() < 209900) {
522  throw std::runtime_error("-netinfo requires bitcoind server to be running v0.21.0 and up");
523  }
524  const int64_t time_now{TicksSinceEpoch<std::chrono::seconds>(CliClock::now())};
525 
526  // Count peer connection totals, and if DetailsRequested(), store peer data in a vector of structs.
527  for (const UniValue& peer : batch[ID_PEERINFO]["result"].getValues()) {
528  const std::string network{peer["network"].get_str()};
529  const int8_t network_id{NetworkStringToId(network)};
530  if (network_id == UNKNOWN_NETWORK) continue;
531  const bool is_outbound{!peer["inbound"].get_bool()};
532  const bool is_tx_relay{peer["relaytxes"].isNull() ? true : peer["relaytxes"].get_bool()};
533  const std::string conn_type{peer["connection_type"].get_str()};
534  ++m_counts.at(is_outbound).at(network_id); // in/out by network
535  ++m_counts.at(is_outbound).at(NETWORKS.size()); // in/out overall
536  ++m_counts.at(2).at(network_id); // total by network
537  ++m_counts.at(2).at(NETWORKS.size()); // total overall
538  if (conn_type == "block-relay-only") ++m_block_relay_peers_count;
539  if (conn_type == "manual") ++m_manual_peers_count;
540  if (m_outbound_only_selected && !is_outbound) continue;
541  if (DetailsRequested()) {
542  // Push data for this peer to the peers vector.
543  const int peer_id{peer["id"].getInt<int>()};
544  const int mapped_as{peer["mapped_as"].isNull() ? 0 : peer["mapped_as"].getInt<int>()};
545  const int version{peer["version"].getInt<int>()};
546  const int64_t addr_processed{peer["addr_processed"].isNull() ? 0 : peer["addr_processed"].getInt<int64_t>()};
547  const int64_t addr_rate_limited{peer["addr_rate_limited"].isNull() ? 0 : peer["addr_rate_limited"].getInt<int64_t>()};
548  const int64_t conn_time{peer["conntime"].getInt<int64_t>()};
549  const int64_t last_blck{peer["last_block"].getInt<int64_t>()};
550  const int64_t last_recv{peer["lastrecv"].getInt<int64_t>()};
551  const int64_t last_send{peer["lastsend"].getInt<int64_t>()};
552  const int64_t last_trxn{peer["last_transaction"].getInt<int64_t>()};
553  const double min_ping{peer["minping"].isNull() ? -1 : peer["minping"].get_real()};
554  const double ping{peer["pingtime"].isNull() ? -1 : peer["pingtime"].get_real()};
555  const std::string addr{peer["addr"].get_str()};
556  const std::string age{conn_time == 0 ? "" : ToString((time_now - conn_time) / 60)};
557  const std::string services{FormatServices(peer["servicesnames"])};
558  const std::string sub_version{peer["subver"].get_str()};
559  const std::string transport{peer["transport_protocol_type"].isNull() ? "v1" : peer["transport_protocol_type"].get_str()};
560  const bool is_addr_relay_enabled{peer["addr_relay_enabled"].isNull() ? false : peer["addr_relay_enabled"].get_bool()};
561  const bool is_bip152_hb_from{peer["bip152_hb_from"].get_bool()};
562  const bool is_bip152_hb_to{peer["bip152_hb_to"].get_bool()};
563  m_peers.push_back({addr, sub_version, conn_type, NETWORK_SHORT_NAMES[network_id], age, services, transport, min_ping, ping, addr_processed, addr_rate_limited, last_blck, last_recv, last_send, last_trxn, peer_id, mapped_as, version, is_addr_relay_enabled, is_bip152_hb_from, is_bip152_hb_to, is_outbound, is_tx_relay});
564  m_max_addr_length = std::max(addr.length() + 1, m_max_addr_length);
565  m_max_addr_processed_length = std::max(ToString(addr_processed).length(), m_max_addr_processed_length);
566  m_max_addr_rate_limited_length = std::max(ToString(addr_rate_limited).length(), m_max_addr_rate_limited_length);
567  m_max_age_length = std::max(age.length(), m_max_age_length);
568  m_max_id_length = std::max(ToString(peer_id).length(), m_max_id_length);
569  m_max_services_length = std::max(services.length(), m_max_services_length);
570  m_is_asmap_on |= (mapped_as != 0);
571  }
572  }
573 
574  // Generate report header.
575  std::string result{strprintf("%s client %s%s - server %i%s\n\n", CLIENT_NAME, FormatFullVersion(), ChainToString(), networkinfo["protocolversion"].getInt<int>(), networkinfo["subversion"].get_str())};
576 
577  // Report detailed peer connections list sorted by direction and minimum ping time.
578  if (DetailsRequested() && !m_peers.empty()) {
579  std::sort(m_peers.begin(), m_peers.end());
580  result += strprintf("<-> type net %*s v mping ping send recv txn blk hb %*s%*s%*s ",
581  m_max_services_length, "serv",
584  m_max_age_length, "age");
585  if (m_is_asmap_on) result += " asmap ";
586  result += strprintf("%*s %-*s%s\n", m_max_id_length, "id", IsAddressSelected() ? m_max_addr_length : 0, IsAddressSelected() ? "address" : "", IsVersionSelected() ? "version" : "");
587  for (const Peer& peer : m_peers) {
588  std::string version{ToString(peer.version) + peer.sub_version};
589  result += strprintf(
590  "%3s %6s %5s %*s %2s%7s%7s%5s%5s%5s%5s %2s %*s%*s%*s%*i %*s %-*s%s\n",
591  peer.is_outbound ? "out" : "in",
592  ConnectionTypeForNetinfo(peer.conn_type),
593  peer.network,
594  m_max_services_length, // variable spacing
595  peer.services,
596  (peer.transport_protocol_type.size() == 2 && peer.transport_protocol_type[0] == 'v') ? peer.transport_protocol_type[1] : ' ',
597  PingTimeToString(peer.min_ping),
598  PingTimeToString(peer.ping),
599  peer.last_send ? ToString(time_now - peer.last_send) : "",
600  peer.last_recv ? ToString(time_now - peer.last_recv) : "",
601  peer.last_trxn ? ToString((time_now - peer.last_trxn) / 60) : peer.is_tx_relay ? "" : "*",
602  peer.last_blck ? ToString((time_now - peer.last_blck) / 60) : "",
603  strprintf("%s%s", peer.is_bip152_hb_to ? "." : " ", peer.is_bip152_hb_from ? "*" : " "),
604  m_max_addr_processed_length, // variable spacing
605  peer.addr_processed ? ToString(peer.addr_processed) : peer.is_addr_relay_enabled ? "" : ".",
606  m_max_addr_rate_limited_length, // variable spacing
607  peer.addr_rate_limited ? ToString(peer.addr_rate_limited) : "",
608  m_max_age_length, // variable spacing
609  peer.age,
610  m_is_asmap_on ? 7 : 0, // variable spacing
611  m_is_asmap_on && peer.mapped_as ? ToString(peer.mapped_as) : "",
612  m_max_id_length, // variable spacing
613  peer.id,
614  IsAddressSelected() ? m_max_addr_length : 0, // variable spacing
615  IsAddressSelected() ? peer.addr : "",
616  IsVersionSelected() && version != "0" ? version : "");
617  }
618  result += strprintf(" %*s ms ms sec sec min min %*s\n\n", m_max_services_length, "", m_max_age_length, "min");
619  }
620 
621  // Report peer connection totals by type.
622  result += " ";
623  std::vector<int8_t> reachable_networks;
624  for (const UniValue& network : networkinfo["networks"].getValues()) {
625  if (network["reachable"].get_bool()) {
626  const std::string& network_name{network["name"].get_str()};
627  const int8_t network_id{NetworkStringToId(network_name)};
628  if (network_id == UNKNOWN_NETWORK) continue;
629  result += strprintf("%8s", network_name); // column header
630  reachable_networks.push_back(network_id);
631  }
632  };
633 
634  for (const size_t network_id : UNREACHABLE_NETWORK_IDS) {
635  if (m_counts.at(2).at(network_id) == 0) continue;
636  result += strprintf("%8s", NETWORK_SHORT_NAMES.at(network_id)); // column header
637  reachable_networks.push_back(network_id);
638  }
639 
640  result += " total block";
641  if (m_manual_peers_count) result += " manual";
642 
643  const std::array rows{"in", "out", "total"};
644  for (size_t i = 0; i < rows.size(); ++i) {
645  result += strprintf("\n%-5s", rows[i]); // row header
646  for (int8_t n : reachable_networks) {
647  result += strprintf("%8i", m_counts.at(i).at(n)); // network peers count
648  }
649  result += strprintf(" %5i", m_counts.at(i).at(NETWORKS.size())); // total peers count
650  if (i == 1) { // the outbound row has two extra columns for block relay and manual peer counts
653  }
654  }
655 
656  // Report local addresses, ports, and scores.
657  result += "\n\nLocal addresses";
658  const std::vector<UniValue>& local_addrs{networkinfo["localaddresses"].getValues()};
659  if (local_addrs.empty()) {
660  result += ": n/a\n";
661  } else {
662  size_t max_addr_size{0};
663  for (const UniValue& addr : local_addrs) {
664  max_addr_size = std::max(addr["address"].get_str().length() + 1, max_addr_size);
665  }
666  for (const UniValue& addr : local_addrs) {
667  result += strprintf("\n%-*s port %6i score %6i", max_addr_size, addr["address"].get_str(), addr["port"].getInt<int>(), addr["score"].getInt<int>());
668  }
669  }
670 
672  }
673 
674  const std::string m_help_doc{
675  "-netinfo (level [outonly]) | help\n\n"
676  "Returns a network peer connections dashboard with information from the remote server.\n"
677  "This human-readable interface will change regularly and is not intended to be a stable API.\n"
678  "Under the hood, -netinfo fetches the data by calling getpeerinfo and getnetworkinfo.\n"
679  + strprintf("An optional argument from 0 to %d can be passed for different peers listings; values above %d up to 255 are parsed as %d.\n", NETINFO_MAX_LEVEL, NETINFO_MAX_LEVEL, NETINFO_MAX_LEVEL) +
680  "If that argument is passed, an optional additional \"outonly\" argument may be passed to obtain the listing with outbound peers only.\n"
681  "Pass \"help\" or \"h\" to see this detailed help documentation.\n"
682  "If more than two arguments are passed, only the first two are read and parsed.\n"
683  "Suggestion: use -netinfo with the Linux watch(1) command for a live dashboard; see example below.\n\n"
684  "Arguments:\n"
685  + strprintf("1. level (integer 0-%d, optional) Specify the info level of the peers dashboard (default 0):\n", NETINFO_MAX_LEVEL) +
686  " 0 - Peer counts for each reachable network as well as for block relay peers\n"
687  " and manual peers, and the list of local addresses and ports\n"
688  " 1 - Like 0 but preceded by a peers listing (without address and version columns)\n"
689  " 2 - Like 1 but with an address column\n"
690  " 3 - Like 1 but with a version column\n"
691  " 4 - Like 1 but with both address and version columns\n"
692  "2. outonly (\"outonly\" or \"o\", optional) Return the peers listing with outbound peers only, i.e. to save screen space\n"
693  " when a node has many inbound peers. Only valid if a level is passed.\n\n"
694  "help (\"help\" or \"h\", optional) Print this help documentation instead of the dashboard.\n\n"
695  "Result:\n\n"
696  + strprintf("* The peers listing in levels 1-%d displays all of the peers sorted by direction and minimum ping time:\n\n", NETINFO_MAX_LEVEL) +
697  " Column Description\n"
698  " ------ -----------\n"
699  " <-> Direction\n"
700  " \"in\" - inbound connections are those initiated by the peer\n"
701  " \"out\" - outbound connections are those initiated by us\n"
702  " type Type of peer connection\n"
703  " \"full\" - full relay, the default\n"
704  " \"block\" - block relay; like full relay but does not relay transactions or addresses\n"
705  " \"manual\" - peer we manually added using RPC addnode or the -addnode/-connect config options\n"
706  " \"feeler\" - short-lived connection for testing addresses\n"
707  " \"addr\" - address fetch; short-lived connection for requesting addresses\n"
708  " net Network the peer connected through (\"ipv4\", \"ipv6\", \"onion\", \"i2p\", \"cjdns\", or \"npr\" (not publicly routable))\n"
709  " serv Services offered by the peer\n"
710  " \"n\" - NETWORK: peer can serve the full block chain\n"
711  " \"b\" - BLOOM: peer can handle bloom-filtered connections (see BIP 111)\n"
712  " \"w\" - WITNESS: peer can be asked for blocks and transactions with witness data (SegWit)\n"
713  " \"c\" - COMPACT_FILTERS: peer can handle basic block filter requests (see BIPs 157 and 158)\n"
714  " \"l\" - NETWORK_LIMITED: peer limited to serving only the last 288 blocks (~2 days)\n"
715  " \"2\" - P2P_V2: peer supports version 2 P2P transport protocol, as defined in BIP 324\n"
716  " \"u\" - UNKNOWN: unrecognized bit flag\n"
717  " v Version of transport protocol used for the connection\n"
718  " mping Minimum observed ping time, in milliseconds (ms)\n"
719  " ping Last observed ping time, in milliseconds (ms)\n"
720  " send Time since last message sent to the peer, in seconds\n"
721  " recv Time since last message received from the peer, in seconds\n"
722  " txn Time since last novel transaction received from the peer and accepted into our mempool, in minutes\n"
723  " \"*\" - we do not relay transactions to this peer (getpeerinfo \"relaytxes\" is false)\n"
724  " blk Time since last novel block passing initial validity checks received from the peer, in minutes\n"
725  " hb High-bandwidth BIP152 compact block relay\n"
726  " \".\" (to) - we selected the peer as a high-bandwidth peer\n"
727  " \"*\" (from) - the peer selected us as a high-bandwidth peer\n"
728  " addrp Total number of addresses processed, excluding those dropped due to rate limiting\n"
729  " \".\" - we do not relay addresses to this peer (getpeerinfo \"addr_relay_enabled\" is false)\n"
730  " addrl Total number of addresses dropped due to rate limiting\n"
731  " age Duration of connection to the peer, in minutes\n"
732  " asmap Mapped AS (Autonomous System) number at the end of the BGP route to the peer, used for diversifying\n"
733  " peer selection (only displayed if the -asmap config option is set)\n"
734  " id Peer index, in increasing order of peer connections since node startup\n"
735  " address IP address and port of the peer\n"
736  " version Peer version and subversion concatenated, e.g. \"70016/Satoshi:21.0.0/\"\n\n"
737  "* The peer counts table displays the number of peers for each reachable network as well as\n"
738  " the number of block relay peers and manual peers.\n\n"
739  "* The local addresses table lists each local address broadcast by the node, the port, and the score.\n\n"
740  "Examples:\n\n"
741  "Peer counts table of reachable networks and list of local addresses\n"
742  "> bitcoin-cli -netinfo\n\n"
743  "The same, preceded by a peers listing without address and version columns\n"
744  "> bitcoin-cli -netinfo 1\n\n"
745  "Full dashboard\n"
746  + strprintf("> bitcoin-cli -netinfo %d\n\n", NETINFO_MAX_LEVEL) +
747  "Full dashboard, but with outbound peers only\n"
748  + strprintf("> bitcoin-cli -netinfo %d outonly\n\n", NETINFO_MAX_LEVEL) +
749  "Full live dashboard, adjust --interval or --no-title as needed (Linux)\n"
750  + strprintf("> watch --interval 1 --no-title bitcoin-cli -netinfo %d\n\n", NETINFO_MAX_LEVEL) +
751  "See this help\n"
752  "> bitcoin-cli -netinfo help\n"};
753 };
754 
757 {
758 public:
759  UniValue PrepareRequest(const std::string& method, const std::vector<std::string>& args) override
760  {
761  address_str = args.at(1);
762  UniValue params{RPCConvertValues("generatetoaddress", args)};
763  return JSONRPCRequestObj("generatetoaddress", params, 1);
764  }
765 
766  UniValue ProcessReply(const UniValue &reply) override
767  {
769  result.pushKV("address", address_str);
770  result.pushKV("blocks", reply.get_obj()["result"]);
771  return JSONRPCReplyObj(std::move(result), NullUniValue, /*id=*/1, JSONRPCVersion::V2);
772  }
773 protected:
774  std::string address_str;
775 };
776 
779 public:
780  UniValue PrepareRequest(const std::string& method, const std::vector<std::string>& args) override
781  {
782  UniValue params;
783  if(gArgs.GetBoolArg("-named", DEFAULT_NAMED)) {
784  params = RPCConvertNamedValues(method, args);
785  } else {
786  params = RPCConvertValues(method, args);
787  }
788  return JSONRPCRequestObj(method, params, 1);
789  }
790 
791  UniValue ProcessReply(const UniValue &reply) override
792  {
793  return reply.get_obj();
794  }
795 };
796 
797 static UniValue CallRPC(BaseRequestHandler* rh, const std::string& strMethod, const std::vector<std::string>& args, const std::optional<std::string>& rpcwallet = {})
798 {
799  std::string host;
800  // In preference order, we choose the following for the port:
801  // 1. -rpcport
802  // 2. port in -rpcconnect (ie following : in ipv4 or ]: in ipv6)
803  // 3. default port for chain
804  uint16_t port{BaseParams().RPCPort()};
805  {
806  uint16_t rpcconnect_port{0};
807  const std::string rpcconnect_str = gArgs.GetArg("-rpcconnect", DEFAULT_RPCCONNECT);
808  if (!SplitHostPort(rpcconnect_str, rpcconnect_port, host)) {
809  // Uses argument provided as-is
810  // (rather than value parsed)
811  // to aid the user in troubleshooting
812  throw std::runtime_error(strprintf("Invalid port provided in -rpcconnect: %s", rpcconnect_str));
813  } else {
814  if (rpcconnect_port != 0) {
815  // Use the valid port provided in rpcconnect
816  port = rpcconnect_port;
817  } // else, no port was provided in rpcconnect (continue using default one)
818  }
819 
820  if (std::optional<std::string> rpcport_arg = gArgs.GetArg("-rpcport")) {
821  // -rpcport was specified
822  const uint16_t rpcport_int{ToIntegral<uint16_t>(rpcport_arg.value()).value_or(0)};
823  if (rpcport_int == 0) {
824  // Uses argument provided as-is
825  // (rather than value parsed)
826  // to aid the user in troubleshooting
827  throw std::runtime_error(strprintf("Invalid port provided in -rpcport: %s", rpcport_arg.value()));
828  }
829 
830  // Use the valid port provided
831  port = rpcport_int;
832 
833  // If there was a valid port provided in rpcconnect,
834  // rpcconnect_port is non-zero.
835  if (rpcconnect_port != 0) {
836  tfm::format(std::cerr, "Warning: Port specified in both -rpcconnect and -rpcport. Using -rpcport %u\n", port);
837  }
838  }
839  }
840 
841  // Obtain event base
842  raii_event_base base = obtain_event_base();
843 
844  // Synchronously look up hostname
845  raii_evhttp_connection evcon = obtain_evhttp_connection_base(base.get(), host, port);
846 
847  // Set connection timeout
848  {
849  const int timeout = gArgs.GetIntArg("-rpcclienttimeout", DEFAULT_HTTP_CLIENT_TIMEOUT);
850  if (timeout > 0) {
851  evhttp_connection_set_timeout(evcon.get(), timeout);
852  } else {
853  // Indefinite request timeouts are not possible in libevent-http, so we
854  // set the timeout to a very long time period instead.
855 
856  constexpr int YEAR_IN_SECONDS = 31556952; // Average length of year in Gregorian calendar
857  evhttp_connection_set_timeout(evcon.get(), 5 * YEAR_IN_SECONDS);
858  }
859  }
860 
861  HTTPReply response;
862  raii_evhttp_request req = obtain_evhttp_request(http_request_done, (void*)&response);
863  if (req == nullptr) {
864  throw std::runtime_error("create http request failed");
865  }
866 
867  evhttp_request_set_error_cb(req.get(), http_error_cb);
868 
869  // Get credentials
870  std::string strRPCUserColonPass;
871  bool failedToGetAuthCookie = false;
872  if (gArgs.GetArg("-rpcpassword", "") == "") {
873  // Try fall back to cookie-based authentication if no password is provided
875  failedToGetAuthCookie = true;
876  }
877  } else {
878  strRPCUserColonPass = gArgs.GetArg("-rpcuser", "") + ":" + gArgs.GetArg("-rpcpassword", "");
879  }
880 
881  struct evkeyvalq* output_headers = evhttp_request_get_output_headers(req.get());
882  assert(output_headers);
883  evhttp_add_header(output_headers, "Host", host.c_str());
884  evhttp_add_header(output_headers, "Connection", "close");
885  evhttp_add_header(output_headers, "Content-Type", "application/json");
886  evhttp_add_header(output_headers, "Authorization", (std::string("Basic ") + EncodeBase64(strRPCUserColonPass)).c_str());
887 
888  // Attach request data
889  std::string strRequest = rh->PrepareRequest(strMethod, args).write() + "\n";
890  struct evbuffer* output_buffer = evhttp_request_get_output_buffer(req.get());
891  assert(output_buffer);
892  evbuffer_add(output_buffer, strRequest.data(), strRequest.size());
893 
894  // check if we should use a special wallet endpoint
895  std::string endpoint = "/";
896  if (rpcwallet) {
897  char* encodedURI = evhttp_uriencode(rpcwallet->data(), rpcwallet->size(), false);
898  if (encodedURI) {
899  endpoint = "/wallet/" + std::string(encodedURI);
900  free(encodedURI);
901  } else {
902  throw CConnectionFailed("uri-encode failed");
903  }
904  }
905  int r = evhttp_make_request(evcon.get(), req.get(), EVHTTP_REQ_POST, endpoint.c_str());
906  req.release(); // ownership moved to evcon in above call
907  if (r != 0) {
908  throw CConnectionFailed("send http request failed");
909  }
910 
911  event_base_dispatch(base.get());
912 
913  if (response.status == 0) {
914  std::string responseErrorMessage;
915  if (response.error != -1) {
916  responseErrorMessage = strprintf(" (error code %d - \"%s\")", response.error, http_errorstring(response.error));
917  }
918  throw CConnectionFailed(strprintf("Could not connect to the server %s:%d%s\n\n"
919  "Make sure the bitcoind server is running and that you are connecting to the correct RPC port.\n"
920  "Use \"bitcoin-cli -help\" for more info.",
921  host, port, responseErrorMessage));
922  } else if (response.status == HTTP_UNAUTHORIZED) {
923  if (failedToGetAuthCookie) {
924  throw std::runtime_error(strprintf(
925  "Could not locate RPC credentials. No authentication cookie could be found, and RPC password is not set. See -rpcpassword and -stdinrpcpass. Configuration file: (%s)",
927  } else {
928  throw std::runtime_error("Authorization failed: Incorrect rpcuser or rpcpassword");
929  }
930  } else if (response.status == HTTP_SERVICE_UNAVAILABLE) {
931  throw std::runtime_error(strprintf("Server response: %s", response.body));
932  } else if (response.status >= 400 && response.status != HTTP_BAD_REQUEST && response.status != HTTP_NOT_FOUND && response.status != HTTP_INTERNAL_SERVER_ERROR)
933  throw std::runtime_error(strprintf("server returned HTTP error %d", response.status));
934  else if (response.body.empty())
935  throw std::runtime_error("no response from server");
936 
937  // Parse reply
938  UniValue valReply(UniValue::VSTR);
939  if (!valReply.read(response.body))
940  throw std::runtime_error("couldn't parse reply from server");
941  UniValue reply = rh->ProcessReply(valReply);
942  if (reply.empty())
943  throw std::runtime_error("expected reply to have result, error and id properties");
944 
945  return reply;
946 }
947 
957 static UniValue ConnectAndCallRPC(BaseRequestHandler* rh, const std::string& strMethod, const std::vector<std::string>& args, const std::optional<std::string>& rpcwallet = {})
958 {
959  UniValue response(UniValue::VOBJ);
960  // Execute and handle connection failures with -rpcwait.
961  const bool fWait = gArgs.GetBoolArg("-rpcwait", false);
962  const int timeout = gArgs.GetIntArg("-rpcwaittimeout", DEFAULT_WAIT_CLIENT_TIMEOUT);
963  const auto deadline{std::chrono::steady_clock::now() + 1s * timeout};
964 
965  do {
966  try {
967  response = CallRPC(rh, strMethod, args, rpcwallet);
968  if (fWait) {
969  const UniValue& error = response.find_value("error");
970  if (!error.isNull() && error["code"].getInt<int>() == RPC_IN_WARMUP) {
971  throw CConnectionFailed("server in warmup");
972  }
973  }
974  break; // Connection succeeded, no need to retry.
975  } catch (const CConnectionFailed& e) {
976  if (fWait && (timeout <= 0 || std::chrono::steady_clock::now() < deadline)) {
978  } else {
979  throw CConnectionFailed(strprintf("timeout on transient error: %s", e.what()));
980  }
981  }
982  } while (fWait);
983  return response;
984 }
985 
987 static void ParseResult(const UniValue& result, std::string& strPrint)
988 {
989  if (result.isNull()) return;
990  strPrint = result.isStr() ? result.get_str() : result.write(2);
991 }
992 
994 static void ParseError(const UniValue& error, std::string& strPrint, int& nRet)
995 {
996  if (error.isObject()) {
997  const UniValue& err_code = error.find_value("code");
998  const UniValue& err_msg = error.find_value("message");
999  if (!err_code.isNull()) {
1000  strPrint = "error code: " + err_code.getValStr() + "\n";
1001  }
1002  if (err_msg.isStr()) {
1003  strPrint += ("error message:\n" + err_msg.get_str());
1004  }
1005  if (err_code.isNum() && err_code.getInt<int>() == RPC_WALLET_NOT_SPECIFIED) {
1006  strPrint += " Or for the CLI, specify the \"-rpcwallet=<walletname>\" option before the command";
1007  strPrint += " (run \"bitcoin-cli -h\" for help or \"bitcoin-cli listwallets\" to see which wallets are currently loaded).";
1008  }
1009  } else {
1010  strPrint = "error: " + error.write();
1011  }
1012  nRet = abs(error["code"].getInt<int>());
1013 }
1014 
1022 {
1024  const UniValue listwallets = ConnectAndCallRPC(&rh, "listwallets", /* args=*/{});
1025  if (!listwallets.find_value("error").isNull()) return;
1026  const UniValue& wallets = listwallets.find_value("result");
1027  if (wallets.size() <= 1) return;
1028 
1029  UniValue balances(UniValue::VOBJ);
1030  for (const UniValue& wallet : wallets.getValues()) {
1031  const std::string& wallet_name = wallet.get_str();
1032  const UniValue getbalances = ConnectAndCallRPC(&rh, "getbalances", /* args=*/{}, wallet_name);
1033  const UniValue& balance = getbalances.find_value("result")["mine"]["trusted"];
1034  balances.pushKV(wallet_name, balance);
1035  }
1036  result.pushKV("balances", std::move(balances));
1037 }
1038 
1045 static void GetProgressBar(double progress, std::string& progress_bar)
1046 {
1047  if (progress < 0 || progress > 1) return;
1048 
1049  static constexpr double INCREMENT{0.05};
1050  static const std::string COMPLETE_BAR{"\u2592"};
1051  static const std::string INCOMPLETE_BAR{"\u2591"};
1052 
1053  for (int i = 0; i < progress / INCREMENT; ++i) {
1054  progress_bar += COMPLETE_BAR;
1055  }
1056 
1057  for (int i = 0; i < (1 - progress) / INCREMENT; ++i) {
1058  progress_bar += INCOMPLETE_BAR;
1059  }
1060 }
1061 
1068 {
1069  if (!result.find_value("error").isNull()) return;
1070 
1071  std::string RESET, GREEN, BLUE, YELLOW, MAGENTA, CYAN;
1072  bool should_colorize = false;
1073 
1074 #ifndef WIN32
1075  if (isatty(fileno(stdout))) {
1076  // By default, only print colored text if OS is not WIN32 and stdout is connected to a terminal.
1077  should_colorize = true;
1078  }
1079 #endif
1080 
1081  if (gArgs.IsArgSet("-color")) {
1082  const std::string color{gArgs.GetArg("-color", DEFAULT_COLOR_SETTING)};
1083  if (color == "always") {
1084  should_colorize = true;
1085  } else if (color == "never") {
1086  should_colorize = false;
1087  } else if (color != "auto") {
1088  throw std::runtime_error("Invalid value for -color option. Valid values: always, auto, never.");
1089  }
1090  }
1091 
1092  if (should_colorize) {
1093  RESET = "\x1B[0m";
1094  GREEN = "\x1B[32m";
1095  BLUE = "\x1B[34m";
1096  YELLOW = "\x1B[33m";
1097  MAGENTA = "\x1B[35m";
1098  CYAN = "\x1B[36m";
1099  }
1100 
1101  std::string result_string = strprintf("%sChain: %s%s\n", BLUE, result["chain"].getValStr(), RESET);
1102  result_string += strprintf("Blocks: %s\n", result["blocks"].getValStr());
1103  result_string += strprintf("Headers: %s\n", result["headers"].getValStr());
1104 
1105  const double ibd_progress{result["verificationprogress"].get_real()};
1106  std::string ibd_progress_bar;
1107  // Display the progress bar only if IBD progress is less than 99%
1108  if (ibd_progress < 0.99) {
1109  GetProgressBar(ibd_progress, ibd_progress_bar);
1110  // Add padding between progress bar and IBD progress
1111  ibd_progress_bar += " ";
1112  }
1113 
1114  result_string += strprintf("Verification progress: %s%.4f%%\n", ibd_progress_bar, ibd_progress * 100);
1115  result_string += strprintf("Difficulty: %s\n\n", result["difficulty"].getValStr());
1116 
1117  result_string += strprintf(
1118  "%sNetwork: in %s, out %s, total %s%s\n",
1119  GREEN,
1120  result["connections"]["in"].getValStr(),
1121  result["connections"]["out"].getValStr(),
1122  result["connections"]["total"].getValStr(),
1123  RESET);
1124  result_string += strprintf("Version: %s\n", result["version"].getValStr());
1125  result_string += strprintf("Time offset (s): %s\n", result["timeoffset"].getValStr());
1126 
1127  // proxies
1128  std::map<std::string, std::vector<std::string>> proxy_networks;
1129  std::vector<std::string> ordered_proxies;
1130 
1131  for (const UniValue& network : result["networks"].getValues()) {
1132  const std::string proxy = network["proxy"].getValStr();
1133  if (proxy.empty()) continue;
1134  // Add proxy to ordered_proxy if has not been processed
1135  if (proxy_networks.find(proxy) == proxy_networks.end()) ordered_proxies.push_back(proxy);
1136 
1137  proxy_networks[proxy].push_back(network["name"].getValStr());
1138  }
1139 
1140  std::vector<std::string> formatted_proxies;
1141  formatted_proxies.reserve(ordered_proxies.size());
1142  for (const std::string& proxy : ordered_proxies) {
1143  formatted_proxies.emplace_back(strprintf("%s (%s)", proxy, Join(proxy_networks.find(proxy)->second, ", ")));
1144  }
1145  result_string += strprintf("Proxies: %s\n", formatted_proxies.empty() ? "n/a" : Join(formatted_proxies, ", "));
1146 
1147  result_string += strprintf("Min tx relay fee rate (%s/kvB): %s\n\n", CURRENCY_UNIT, result["relayfee"].getValStr());
1148 
1149  if (!result["has_wallet"].isNull()) {
1150  const std::string walletname = result["walletname"].getValStr();
1151  result_string += strprintf("%sWallet: %s%s\n", MAGENTA, walletname.empty() ? "\"\"" : walletname, RESET);
1152 
1153  result_string += strprintf("Keypool size: %s\n", result["keypoolsize"].getValStr());
1154  if (!result["unlocked_until"].isNull()) {
1155  result_string += strprintf("Unlocked until: %s\n", result["unlocked_until"].getValStr());
1156  }
1157  result_string += strprintf("Transaction fee rate (-paytxfee) (%s/kvB): %s\n\n", CURRENCY_UNIT, result["paytxfee"].getValStr());
1158  }
1159  if (!result["balance"].isNull()) {
1160  result_string += strprintf("%sBalance:%s %s\n\n", CYAN, RESET, result["balance"].getValStr());
1161  }
1162 
1163  if (!result["balances"].isNull()) {
1164  result_string += strprintf("%sBalances%s\n", CYAN, RESET);
1165 
1166  size_t max_balance_length{10};
1167 
1168  for (const std::string& wallet : result["balances"].getKeys()) {
1169  max_balance_length = std::max(result["balances"][wallet].getValStr().length(), max_balance_length);
1170  }
1171 
1172  for (const std::string& wallet : result["balances"].getKeys()) {
1173  result_string += strprintf("%*s %s\n",
1174  max_balance_length,
1175  result["balances"][wallet].getValStr(),
1176  wallet.empty() ? "\"\"" : wallet);
1177  }
1178  result_string += "\n";
1179  }
1180 
1181  const std::string warnings{result["warnings"].getValStr()};
1182  result_string += strprintf("%sWarnings:%s %s", YELLOW, RESET, warnings.empty() ? "(none)" : warnings);
1183 
1184  result.setStr(result_string);
1185 }
1186 
1192 {
1194  return ConnectAndCallRPC(&rh, "getnewaddress", /* args=*/{}, RpcWalletName(gArgs));
1195 }
1196 
1202 static void SetGenerateToAddressArgs(const std::string& address, std::vector<std::string>& args)
1203 {
1204  if (args.size() > 2) throw std::runtime_error("too many arguments (maximum 2 for nblocks and maxtries)");
1205  if (args.size() == 0) {
1206  args.emplace_back(DEFAULT_NBLOCKS);
1207  } else if (args.at(0) == "0") {
1208  throw std::runtime_error("the first argument (number of blocks to generate, default: " + DEFAULT_NBLOCKS + ") must be an integer value greater than zero");
1209  }
1210  args.emplace(args.begin() + 1, address);
1211 }
1212 
1213 static int CommandLineRPC(int argc, char *argv[])
1214 {
1215  std::string strPrint;
1216  int nRet = 0;
1217  try {
1218  // Skip switches
1219  while (argc > 1 && IsSwitchChar(argv[1][0])) {
1220  argc--;
1221  argv++;
1222  }
1223  std::string rpcPass;
1224  if (gArgs.GetBoolArg("-stdinrpcpass", false)) {
1225  NO_STDIN_ECHO();
1226  if (!StdinReady()) {
1227  fputs("RPC password> ", stderr);
1228  fflush(stderr);
1229  }
1230  if (!std::getline(std::cin, rpcPass)) {
1231  throw std::runtime_error("-stdinrpcpass specified but failed to read from standard input");
1232  }
1233  if (StdinTerminal()) {
1234  fputc('\n', stdout);
1235  }
1236  gArgs.ForceSetArg("-rpcpassword", rpcPass);
1237  }
1238  std::vector<std::string> args = std::vector<std::string>(&argv[1], &argv[argc]);
1239  if (gArgs.GetBoolArg("-stdinwalletpassphrase", false)) {
1240  NO_STDIN_ECHO();
1241  std::string walletPass;
1242  if (args.size() < 1 || args[0].substr(0, 16) != "walletpassphrase") {
1243  throw std::runtime_error("-stdinwalletpassphrase is only applicable for walletpassphrase(change)");
1244  }
1245  if (!StdinReady()) {
1246  fputs("Wallet passphrase> ", stderr);
1247  fflush(stderr);
1248  }
1249  if (!std::getline(std::cin, walletPass)) {
1250  throw std::runtime_error("-stdinwalletpassphrase specified but failed to read from standard input");
1251  }
1252  if (StdinTerminal()) {
1253  fputc('\n', stdout);
1254  }
1255  args.insert(args.begin() + 1, walletPass);
1256  }
1257  if (gArgs.GetBoolArg("-stdin", false)) {
1258  // Read one arg per line from stdin and append
1259  std::string line;
1260  while (std::getline(std::cin, line)) {
1261  args.push_back(line);
1262  }
1263  if (StdinTerminal()) {
1264  fputc('\n', stdout);
1265  }
1266  }
1268  std::unique_ptr<BaseRequestHandler> rh;
1269  std::string method;
1270  if (gArgs.IsArgSet("-getinfo")) {
1271  rh.reset(new GetinfoRequestHandler());
1272  } else if (gArgs.GetBoolArg("-netinfo", false)) {
1273  if (!args.empty() && (args.at(0) == "h" || args.at(0) == "help")) {
1274  tfm::format(std::cout, "%s\n", NetinfoRequestHandler().m_help_doc);
1275  return 0;
1276  }
1277  rh.reset(new NetinfoRequestHandler());
1278  } else if (gArgs.GetBoolArg("-generate", false)) {
1280  const UniValue& error{getnewaddress.find_value("error")};
1281  if (error.isNull()) {
1282  SetGenerateToAddressArgs(getnewaddress.find_value("result").get_str(), args);
1283  rh.reset(new GenerateToAddressRequestHandler());
1284  } else {
1285  ParseError(error, strPrint, nRet);
1286  }
1287  } else if (gArgs.GetBoolArg("-addrinfo", false)) {
1288  rh.reset(new AddrinfoRequestHandler());
1289  } else {
1290  rh.reset(new DefaultRequestHandler());
1291  if (args.size() < 1) {
1292  throw std::runtime_error("too few parameters (need at least command)");
1293  }
1294  method = args[0];
1295  args.erase(args.begin()); // Remove trailing method name from arguments vector
1296  }
1297  if (nRet == 0) {
1298  // Perform RPC call
1299  const std::optional<std::string> wallet_name{RpcWalletName(gArgs)};
1300  const UniValue reply = ConnectAndCallRPC(rh.get(), method, args, wallet_name);
1301 
1302  // Parse reply
1303  UniValue result = reply.find_value("result");
1304  const UniValue& error = reply.find_value("error");
1305  if (error.isNull()) {
1306  if (gArgs.GetBoolArg("-getinfo", false)) {
1307  if (!wallet_name) {
1308  GetWalletBalances(result); // fetch multiwallet balances and append to result
1309  }
1311  }
1312 
1314  } else {
1315  ParseError(error, strPrint, nRet);
1316  }
1317  }
1318  } catch (const std::exception& e) {
1319  strPrint = std::string("error: ") + e.what();
1320  nRet = EXIT_FAILURE;
1321  } catch (...) {
1322  PrintExceptionContinue(nullptr, "CommandLineRPC()");
1323  throw;
1324  }
1325 
1326  if (strPrint != "") {
1327  tfm::format(nRet == 0 ? std::cout : std::cerr, "%s\n", strPrint);
1328  }
1329  return nRet;
1330 }
1331 
1334 #ifdef WIN32
1335  common::WinCmdLineArgs winArgs;
1336  std::tie(argc, argv) = winArgs.get();
1337 #endif
1338  SetupEnvironment();
1340  tfm::format(std::cerr, "Error: Initializing networking failed\n");
1341  return EXIT_FAILURE;
1342  }
1343  event_set_log_callback(&libevent_log_cb);
1344 
1345  try {
1346  int ret = AppInitRPC(argc, argv);
1347  if (ret != CONTINUE_EXECUTION)
1348  return ret;
1349  }
1350  catch (const std::exception& e) {
1351  PrintExceptionContinue(&e, "AppInitRPC()");
1352  return EXIT_FAILURE;
1353  } catch (...) {
1354  PrintExceptionContinue(nullptr, "AppInitRPC()");
1355  return EXIT_FAILURE;
1356  }
1357 
1358  int ret = EXIT_FAILURE;
1359  try {
1360  ret = CommandLineRPC(argc, argv);
1361  }
1362  catch (const std::exception& e) {
1363  PrintExceptionContinue(&e, "CommandLineRPC()");
1364  } catch (...) {
1365  PrintExceptionContinue(nullptr, "CommandLineRPC()");
1366  }
1367  return ret;
1368 }
bool ReadConfigFiles(std::string &error, bool ignore_invalid_keys=false)
Definition: config.cpp:122
No wallet specified (error when there are multiple wallets loaded)
Definition: protocol.h:81
std::string ChainToString() const
MAIN_FUNCTION
static const std::string DEFAULT_NBLOCKS
Default number of blocks to generate for RPC generatetoaddress.
Definition: bitcoin-cli.cpp:68
bool DetailsRequested() const
static RPCHelpMan ping()
Definition: net.cpp:79
bool isObject() const
Definition: univalue.h:86
bool StdinTerminal()
Definition: stdin.cpp:43
bool StdinReady()
Definition: stdin.cpp:52
int ret
uint8_t m_block_relay_peers_count
bool IsArgSet(const std::string &strArg) const
Return true if the given argument has been manually set.
Definition: args.cpp:371
static int CommandLineRPC(int argc, char *argv[])
raii_event_base obtain_event_base()
Definition: events.h:30
void SetupChainParamsBaseOptions(ArgsManager &argsman)
Set the arguments for chainparams.
const std::vector< UniValue > & getValues() const
return EXIT_SUCCESS
fs::path GetConfigFilePath() const
Return config file path (read-only)
Definition: args.cpp:761
static constexpr std::array UNREACHABLE_NETWORK_IDS
Definition: bitcoin-cli.cpp:65
assert(!tx.IsCoinBase())
UniValue PrepareRequest(const std::string &method, const std::vector< std::string > &args) override
static int AppInitRPC(int argc, char *argv[])
bool SplitHostPort(std::string_view in, uint16_t &portOut, std::string &hostOut)
Splits socket address string into host string and port value.
std::chrono::system_clock CliClock
Definition: bitcoin-cli.cpp:51
static std::string strRPCUserColonPass
Definition: httprpc.cpp:73
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
Definition: tinyformat.h:1172
static constexpr int ID_NETWORKINFO
static const std::string DEFAULT_COLOR_SETTING
Default -color setting.
Definition: bitcoin-cli.cpp:71
UniValue ProcessReply(const UniValue &reply) override
int8_t NetworkStringToId(const std::string &str) const
std::string strPrint
static const int DEFAULT_HTTP_CLIENT_TIMEOUT
Definition: bitcoin-cli.cpp:56
disallow -nofoo syntax
Definition: args.h:111
static void http_error_cb(enum evhttp_request_error err, void *ctx)
static constexpr int ID_PEERINFO
const CBaseChainParams & BaseParams()
Return the currently selected parameters.
std::string EncodeBase64(Span< const unsigned char > input)
int8_t NetworkStringToId(const std::string &str) const
const std::string & get_str() const
SetupEnvironment()
Definition: system.cpp:59
size_t m_max_addr_rate_limited_length
bool isNum() const
Definition: univalue.h:84
raii_evhttp_request obtain_evhttp_request(void(*cb)(struct evhttp_request *, void *), void *arg)
Definition: events.h:45
bool ParseParameters(int argc, const char *const argv[], std::string &error)
Definition: args.cpp:179
std::vector< Peer > m_peers
bool isStr() const
Definition: univalue.h:83
static std::string http_errorstring(int code)
uint8_t m_details_level
Optional user-supplied arg to set dashboard details level.
bool GetBoolArg(const std::string &strArg, bool fDefault) const
Return boolean argument or default value.
Definition: args.cpp:507
std::string LicenseInfo()
Returns licensing information (for -version)
Int getInt() const
Definition: univalue.h:138
void ForceSetArg(const std::string &strArg, const std::string &strValue)
Definition: args.cpp:546
static constexpr int8_t UNKNOWN_NETWORK
Definition: bitcoin-cli.cpp:61
void format(std::ostream &out, FormatStringCheck< sizeof...(Args)> fmt, const Args &... args)
Format list of arguments to the stream according to given format string.
Definition: tinyformat.h:1079
void PrintExceptionContinue(const std::exception *pex, std::string_view thread_name)
Definition: exception.cpp:36
ChainType GetChainType() const
Returns the appropriate chain type from the program arguments.
Definition: args.cpp:774
const std::string & getValStr() const
Definition: univalue.h:68
Client still warming up.
Definition: protocol.h:50
bool operator<(const Peer &rhs) const
#define NO_STDIN_ECHO()
Definition: stdin.h:13
disable validation
Definition: args.h:106
virtual UniValue ProcessReply(const UniValue &batch_in)=0
UniValue PrepareRequest(const std::string &method, const std::vector< std::string > &args) override
Create a simulated getinfo request.
std::string GetHelpMessage() const
Get the help string.
Definition: args.cpp:609
UniValue RPCConvertValues(const std::string &strMethod, const std::vector< std::string > &strParams)
Convert positional arguments to command-specific RPC representation.
Definition: client.cpp:366
event_set_log_callback & libevent_log_cb
const UniValue & find_value(std::string_view key) const
Definition: univalue.cpp:233
std::vector< UniValue > JSONRPCProcessBatchReply(const UniValue &in)
Parse JSON-RPC batch reply into a vector.
Definition: request.cpp:177
static void ParseGetInfoResult(UniValue &result)
ParseGetInfoResult takes in -getinfo result in UniValue object and parses it into a user friendly Uni...
uint16_t RPCPort() const
static const char DEFAULT_RPCCONNECT[]
Definition: bitcoin-cli.cpp:55
bool IsArgNegated(const std::string &strArg) const
Return true if the argument was originally passed as a negated option, i.e.
Definition: args.cpp:452
UniValue ProcessReply(const UniValue &reply) override
static std::string PathToString(const path &path)
Convert path object to a byte string.
Definition: fs.h:151
ArgsManager & args
Definition: bitcoind.cpp:277
static void GetProgressBar(double progress, std::string &progress_bar)
GetProgressBar constructs a progress bar with 5% intervals.
static constexpr uint8_t NETINFO_MAX_LEVEL
Definition: bitcoin-cli.cpp:60
size_t m_max_addr_processed_length
static const uint64_t DEFAULT_MAX_TRIES
Default max iterations to try in RPC generatetodescriptor, generatetoaddress, and generateblock...
Definition: mining.h:9
static UniValue CallRPC(BaseRequestHandler *rh, const std::string &strMethod, const std::vector< std::string > &args, const std::optional< std::string > &rpcwallet={})
static void ParseError(const UniValue &error, std::string &strPrint, int &nRet)
Parse UniValue error to update the message to print to std::cerr and the code to return.
static constexpr int DEFAULT_WAIT_CLIENT_TIMEOUT
Definition: bitcoin-cli.cpp:57
std::function< std::string(const char *)> TranslateFn
Translate a message to the native language of the user.
Definition: translation.h:16
Process netinfo requests.
Process addrinfo requests.
void AddArg(const std::string &name, const std::string &help, unsigned int flags, const OptionsCategory &cat)
Add argument.
Definition: args.cpp:564
std::unique_ptr< CBaseChainParams > CreateBaseChainParams(const ChainType chain)
Port numbers for incoming Tor connections (8334, 18334, 38334, 48334, 18445) have been chosen arbitra...
static const int CONTINUE_EXECUTION
Definition: bitcoin-cli.cpp:59
bool ParseUInt8(std::string_view str, uint8_t *out)
Convert decimal string to unsigned 8-bit integer with strict parse error feedback.
bool empty() const
Definition: univalue.h:69
virtual UniValue PrepareRequest(const std::string &method, const std::vector< std::string > &args)=0
raii_evhttp_connection obtain_evhttp_connection_base(struct event_base *base, std::string host, uint16_t port)
Definition: events.h:49
std::string write(unsigned int prettyIndent=0, unsigned int indentLevel=0) const
const std::string CURRENCY_UNIT
Definition: feerate.h:17
static void GetWalletBalances(UniValue &result)
GetWalletBalances calls listwallets; if more than one wallet is loaded, it then fetches mine...
void CheckMultipleCLIArgs() const
Check CLI command args.
Definition: args.cpp:592
std::string ConnectionTypeForNetinfo(const std::string &conn_type) const
std::string FormatParagraph(std::string_view in, size_t width, size_t indent)
Format a paragraph of text to a fixed width, adding spaces for indentation to any added line...
UniValue ProcessReply(const UniValue &batch_in) override
Collect values from the batch and form a simulated getinfo reply.
std::optional< std::string > RpcWalletName(const ArgsManager &args)
bool isNull() const
Definition: univalue.h:79
UniValue JSONRPCReplyObj(UniValue result, UniValue error, std::optional< UniValue > id, JSONRPCVersion jsonrpc_version)
Definition: request.cpp:51
Class that handles the conversion from a command-line to a JSON-RPC request, as well as converting ba...
std::string FormatFullVersion()
static void SetupCliArgs(ArgsManager &argsman)
Definition: bitcoin-cli.cpp:73
Definition: messages.h:20
ArgsManager gArgs
Definition: args.cpp:42
std::string ToLower(std::string_view str)
Returns the lowercase equivalent of the given string.
bool IsVersionSelected() const
static constexpr std::array NETWORKS
Definition: bitcoin-cli.cpp:63
void SetupHelpOptions(ArgsManager &args)
Add help options to the args manager.
Definition: args.cpp:689
static void ParseResult(const UniValue &result, std::string &strPrint)
Parse UniValue result to update the message to print to std::cout.
CConnectionFailed(const std::string &msg)
bool SetupNetworking()
Definition: system.cpp:91
HTTPReply()=default
auto result
Definition: common-types.h:74
std::array< std::array< uint16_t, NETWORKS.size()+1 >, 3 > m_counts
Peer counts by (in/out/total, networks/total)
void UninterruptibleSleep(const std::chrono::microseconds &n)
Definition: time.cpp:20
void SelectBaseParams(const ChainType chain)
Sets the params returned by Params() to those for the given chain.
void pushKV(std::string key, UniValue val)
Definition: univalue.cpp:126
virtual ~BaseRequestHandler()=default
int64_t GetIntArg(const std::string &strArg, int64_t nDefault) const
Return integer argument or default value.
Definition: args.cpp:482
const UniValue & get_obj() const
std::string GetArg(const std::string &strArg, const std::string &strDefault) const
Return string argument or default value.
Definition: args.cpp:457
Process RPC generatetoaddress request.
std::string FormatServices(const UniValue &services)
static constexpr std::array NETWORK_SHORT_NAMES
Definition: bitcoin-cli.cpp:64
const std::string m_help_doc
bool HelpRequested(const ArgsManager &args)
Definition: args.cpp:684
Process default single requests.
UniValue PrepareRequest(const std::string &method, const std::vector< std::string > &args) override
UniValue JSONRPCRequestObj(const std::string &strMethod, const UniValue &params, const UniValue &id)
JSON-RPC protocol.
Definition: request.cpp:41
std::string body
const UniValue NullUniValue
Definition: univalue.cpp:16
UniValue PrepareRequest(const std::string &method, const std::vector< std::string > &args) override
const char *const BITCOIN_CONF_FILENAME
Definition: args.cpp:39
UniValue RPCConvertNamedValues(const std::string &strMethod, const std::vector< std::string > &strParams)
Convert named arguments to command-specific RPC representation.
Definition: client.cpp:378
static const bool DEFAULT_NAMED
Definition: bitcoin-cli.cpp:58
static UniValue GetNewAddress()
Call RPC getnewaddress.
static UniValue ConnectAndCallRPC(BaseRequestHandler *rh, const std::string &strMethod, const std::vector< std::string > &args, const std::optional< std::string > &rpcwallet={})
ConnectAndCallRPC wraps CallRPC with -rpcwait and an exception handler.
UniValue PrepareRequest(const std::string &method, const std::vector< std::string > &args) override
size_t size() const
Definition: univalue.h:71
UniValue ProcessReply(const UniValue &batch_in) override
RPCHelpMan getnewaddress()
Definition: addresses.cpp:21
bool IsAddressSelected() const
RPCHelpMan getbalances()
Definition: coins.cpp:427
static RPCHelpMan listwallets()
Definition: wallet.cpp:185
std::string PingTimeToString(double seconds) const
Process getinfo requests.
auto Join(const C &container, const S &separator, UnaryOp unary_op)
Join all container items.
Definition: string.h:192
bool GetAuthCookie(std::string *cookie_out)
Read the RPC authentication cookie from disk.
Definition: request.cpp:146
static void SetGenerateToAddressArgs(const std::string &address, std::vector< std::string > &args)
Check bounds and set up args for RPC generatetoaddress params: nblocks, address, maxtries.
static void http_request_done(struct evhttp_request *req, void *ctx)
bool IsSwitchChar(char c)
Definition: args.h:43
std::string ToString(const T &t)
Locale-independent version of std::to_string.
Definition: string.h:233
Reply structure for request_done to fill in.
UniValue ProcessReply(const UniValue &reply) override
bool CheckDataDirOption(const ArgsManager &args)
Definition: args.cpp:755
const TranslateFn G_TRANSLATION_FUN
Translate string to current locale using Qt.
Definition: bitcoin-cli.cpp:53