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