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