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