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