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