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