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