Bitcoin ABC 0.26.3
P2P Digital Currency
Loading...
Searching...
No Matches
bitcoin-cli.cpp
Go to the documentation of this file.
1// Copyright (c) 2009-2010 Satoshi Nakamoto
2// Copyright (c) 2009-2016 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)
7#include <config/bitcoin-config.h>
8#endif
9
10#include <chainparamsbase.h>
11#include <clientversion.h>
12#include <common/args.h>
13#include <common/system.h>
14#include <currencyunit.h>
15#include <rpc/client.h>
16#include <rpc/mining.h>
17#include <rpc/protocol.h>
18#include <rpc/request.h>
19#include <support/events.h>
20#include <tinyformat.h>
21#include <util/exception.h>
22#include <util/strencodings.h>
23#include <util/string.h>
24#include <util/time.h>
25#include <util/translation.h>
26
27#include <event2/buffer.h>
28#include <event2/keyvalq_struct.h>
29
30#include <compat/stdin.h>
31#include <univalue.h>
32
33#include <algorithm>
34#include <chrono>
35#include <cmath>
36#include <cstdio>
37#include <functional>
38#include <memory>
39#include <string>
40#include <tuple>
41
42// The server returns time values from a mockable system clock, but it is not
43// trivial to get the mocked time from the server, nor is it needed for now, so
44// just use a plain system_clock.
45using CliClock = std::chrono::system_clock;
46
47const std::function<std::string(const char *)> G_TRANSLATION_FUN = nullptr;
48
49static const char DEFAULT_RPCCONNECT[] = "127.0.0.1";
50static const int DEFAULT_HTTP_CLIENT_TIMEOUT = 900;
51static const bool DEFAULT_NAMED = false;
52static const int CONTINUE_EXECUTION = -1;
54static const std::string DEFAULT_NBLOCKS = "1";
55
58
59 const auto defaultBaseParams =
61 const auto testnetBaseParams =
63 const auto regtestBaseParams =
65
67 argsman.AddArg("-version", "Print version and exit", ArgsManager::ALLOW_ANY,
69 argsman.AddArg(
70 "-conf=<file>",
71 strprintf("Specify configuration file. Relative paths will be "
72 "prefixed by datadir location. (default: %s)",
75 argsman.AddArg("-datadir=<dir>", "Specify data directory",
77 argsman.AddArg(
78 "-generate",
80 "Generate blocks immediately, equivalent to RPC getnewaddress "
81 "followed by RPC generatetoaddress. Optional positional integer "
82 "arguments are number of blocks to generate (default: %s) and "
83 "maximum iterations to try (default: %s), equivalent to RPC "
84 "generatetoaddress nblocks and maxtries arguments. Example: "
85 "bitcoin-cli -generate 4 1000",
88 argsman.AddArg(
89 "-getinfo",
90 "Get general information from the remote server. Note that unlike "
91 "server-side RPC calls, the results of -getinfo is the result of "
92 "multiple non-atomic requests. Some entries in the result may "
93 "represent results from different states (e.g. wallet balance may be "
94 "as of a different block from the chain state reported)",
96 argsman.AddArg("-netinfo",
97 "Get network peer connection information from the remote "
98 "server. An optional integer argument from 0 to 4 can be "
99 "passed for different peers listings (default: 0).",
101
103 argsman.AddArg(
104 "-named",
105 strprintf("Pass named instead of positional arguments (default: %s)",
108 argsman.AddArg(
109 "-rpcconnect=<ip>",
110 strprintf("Send commands to node running on <ip> (default: %s)",
113 argsman.AddArg(
114 "-rpccookiefile=<loc>",
115 "Location of the auth cookie. Relative paths will be prefixed "
116 "by a net-specific datadir location. (default: data dir)",
118 argsman.AddArg("-rpcport=<port>",
119 strprintf("Connect to JSON-RPC on <port> (default: %u, "
120 "testnet: %u, regtest: %u)",
121 defaultBaseParams->RPCPort(),
122 testnetBaseParams->RPCPort(),
123 regtestBaseParams->RPCPort()),
126 argsman.AddArg("-rpcwait", "Wait for RPC server to start",
128 argsman.AddArg("-rpcuser=<user>", "Username for JSON-RPC connections",
130 argsman.AddArg("-rpcpassword=<pw>", "Password for JSON-RPC connections",
132 argsman.AddArg(
133 "-rpcclienttimeout=<n>",
134 strprintf("Timeout in seconds during HTTP requests, or 0 for "
135 "no timeout. (default: %d)",
138
139 argsman.AddArg("-stdinrpcpass",
140 "Read RPC password from standard input as a single "
141 "line. When combined with -stdin, the first line "
142 "from standard input is used for the RPC password. When "
143 "combined with -stdinwalletpassphrase, -stdinrpcpass "
144 "consumes the first line, and -stdinwalletpassphrase "
145 "consumes the second.",
147 argsman.AddArg("-stdinwalletpassphrase",
148 "Read wallet passphrase from standard input as a single "
149 "line. When combined with -stdin, the first line "
150 "from standard input is used for the wallet passphrase.",
152 argsman.AddArg(
153 "-stdin",
154 "Read extra arguments from standard input, one per line until "
155 "EOF/Ctrl-D (recommended for sensitive information such as "
156 "passphrases). When combined with -stdinrpcpass, the first "
157 "line from standard input is used for the RPC password.",
159 argsman.AddArg(
160 "-rpcwallet=<walletname>",
161 "Send RPC for non-default wallet on RPC server (needs to exactly match "
162 "corresponding -wallet option passed to bitcoind). This changes the "
163 "RPC endpoint used, e.g. http://127.0.0.1:8332/wallet/<walletname>",
165}
166
168static void libevent_log_cb(int severity, const char *msg) {
169#ifndef EVENT_LOG_ERR
170// EVENT_LOG_ERR was added in 2.0.19; but before then _EVENT_LOG_ERR existed.
171#define EVENT_LOG_ERR _EVENT_LOG_ERR
172#endif
173 // Ignore everything other than errors
174 if (severity >= EVENT_LOG_ERR) {
175 throw std::runtime_error(strprintf("libevent error: %s", msg));
176 }
177}
178
180//
181// Start
182//
183
184//
185// Exception thrown on connection error. This error is used to determine when
186// to wait if -rpcwait is given.
187//
188class CConnectionFailed : public std::runtime_error {
189public:
190 explicit inline CConnectionFailed(const std::string &msg)
191 : std::runtime_error(msg) {}
192};
193
194//
195// This function returns either one of EXIT_ codes when it's expected to stop
196// the process or CONTINUE_EXECUTION when it's expected to continue further.
197//
198static int AppInitRPC(int argc, char *argv[]) {
199 //
200 // Parameters
201 //
203 std::string error;
205 tfm::format(std::cerr, "Error parsing command line arguments: %s\n",
206 error);
207 return EXIT_FAILURE;
208 }
209 if (argc < 2 || HelpRequested(gArgs) || gArgs.IsArgSet("-version")) {
210 std::string strUsage =
211 PACKAGE_NAME " RPC client version " + FormatFullVersion() + "\n";
212
213 if (gArgs.IsArgSet("-version")) {
215 } else {
216 strUsage += "\n"
217 "Usage: bitcoin-cli [options] <command> [params] "
218 "Send command to " PACKAGE_NAME "\n"
219 "or: bitcoin-cli [options] -named <command> "
220 "[name=value]... Send command to " PACKAGE_NAME
221 " (with named arguments)\n"
222 "or: bitcoin-cli [options] help "
223 "List commands\n"
224 "or: bitcoin-cli [options] help <command> Get "
225 "help for a command\n";
226
227 strUsage += "\n" + gArgs.GetHelpMessage();
228 }
229
230 tfm::format(std::cout, "%s", strUsage);
231 if (argc < 2) {
232 tfm::format(std::cerr, "Error: too few parameters\n");
233 return EXIT_FAILURE;
234 }
235 return EXIT_SUCCESS;
236 }
238 tfm::format(std::cerr,
239 "Error: Specified data directory \"%s\" does not exist.\n",
240 gArgs.GetArg("-datadir", ""));
241 return EXIT_FAILURE;
242 }
243 if (!gArgs.ReadConfigFiles(error, true)) {
244 tfm::format(std::cerr, "Error reading configuration file: %s\n", error);
245 return EXIT_FAILURE;
246 }
247 // Check for -chain, -testnet or -regtest parameter (BaseParams() calls are
248 // only valid after this clause)
249 try {
251 } catch (const std::exception &e) {
252 tfm::format(std::cerr, "Error: %s\n", e.what());
253 return EXIT_FAILURE;
254 }
255 return CONTINUE_EXECUTION;
256}
257
259struct HTTPReply {
260 HTTPReply() : status(0), error(-1) {}
261
263 int error;
264 std::string body;
265};
266
267static std::string http_errorstring(int code) {
268 switch (code) {
269#if LIBEVENT_VERSION_NUMBER >= 0x02010300
271 return "timeout reached";
272 case EVREQ_HTTP_EOF:
273 return "EOF reached";
275 return "error while reading header, or invalid header";
277 return "error encountered while reading or writing";
279 return "request was canceled";
281 return "response body is larger than allowed";
282#endif
283 default:
284 return "unknown";
285 }
286}
287
288static void http_request_done(struct evhttp_request *req, void *ctx) {
289 HTTPReply *reply = static_cast<HTTPReply *>(ctx);
290
291 if (req == nullptr) {
296 reply->status = 0;
297 return;
298 }
299
301
302 struct evbuffer *buf = evhttp_request_get_input_buffer(req);
303 if (buf) {
304 size_t size = evbuffer_get_length(buf);
305 const char *data = (const char *)evbuffer_pullup(buf, size);
306 if (data) {
307 reply->body = std::string(data, size);
308 }
309 evbuffer_drain(buf, size);
310 }
311}
312
313#if LIBEVENT_VERSION_NUMBER >= 0x02010300
314static void http_error_cb(enum evhttp_request_error err, void *ctx) {
315 HTTPReply *reply = static_cast<HTTPReply *>(ctx);
316 reply->error = err;
317}
318#endif
319
325public:
327 virtual UniValue PrepareRequest(const std::string &method,
328 const std::vector<std::string> &args) = 0;
330};
331
334public:
335 const int ID_NETWORKINFO = 0;
336 const int ID_BLOCKCHAININFO = 1;
337 const int ID_WALLETINFO = 2;
338 const int ID_BALANCES = 3;
339
341 UniValue PrepareRequest(const std::string &method,
342 const std::vector<std::string> &args) override {
343 if (!args.empty()) {
344 throw std::runtime_error("-getinfo takes no arguments");
345 }
346 UniValue result(UniValue::VARR);
347 result.push_back(
348 JSONRPCRequestObj("getnetworkinfo", NullUniValue, ID_NETWORKINFO));
349 result.push_back(JSONRPCRequestObj("getblockchaininfo", NullUniValue,
351 result.push_back(
352 JSONRPCRequestObj("getwalletinfo", NullUniValue, ID_WALLETINFO));
353 result.push_back(
355 return result;
356 }
357
360 UniValue result(UniValue::VOBJ);
361 const std::vector<UniValue> batch = JSONRPCProcessBatchReply(batch_in);
362 // Errors in getnetworkinfo() and getblockchaininfo() are fatal, pass
363 // them on; getwalletinfo() and getbalances are allowed to fail if there
364 // is no wallet.
365 if (!batch[ID_NETWORKINFO]["error"].isNull()) {
366 return batch[ID_NETWORKINFO];
367 }
368 if (!batch[ID_BLOCKCHAININFO]["error"].isNull()) {
369 return batch[ID_BLOCKCHAININFO];
370 }
371 result.pushKV("version", batch[ID_NETWORKINFO]["result"]["version"]);
372 result.pushKV("blocks", batch[ID_BLOCKCHAININFO]["result"]["blocks"]);
373 result.pushKV("headers", batch[ID_BLOCKCHAININFO]["result"]["headers"]);
374 result.pushKV(
375 "verificationprogress",
376 batch[ID_BLOCKCHAININFO]["result"]["verificationprogress"]);
377 result.pushKV("timeoffset",
378 batch[ID_NETWORKINFO]["result"]["timeoffset"]);
379
381 connections.pushKV("in",
382 batch[ID_NETWORKINFO]["result"]["connections_in"]);
383 connections.pushKV("out",
384 batch[ID_NETWORKINFO]["result"]["connections_out"]);
385 connections.pushKV("total",
386 batch[ID_NETWORKINFO]["result"]["connections"]);
387 result.pushKV("connections", connections);
388
389 result.pushKV("proxy",
390 batch[ID_NETWORKINFO]["result"]["networks"][0]["proxy"]);
391 result.pushKV("difficulty",
392 batch[ID_BLOCKCHAININFO]["result"]["difficulty"]);
393 result.pushKV("chain",
394 UniValue(batch[ID_BLOCKCHAININFO]["result"]["chain"]));
395 if (!batch[ID_WALLETINFO]["result"].isNull()) {
396 result.pushKV("keypoolsize",
397 batch[ID_WALLETINFO]["result"]["keypoolsize"]);
398 if (!batch[ID_WALLETINFO]["result"]["unlocked_until"].isNull()) {
399 result.pushKV("unlocked_until",
400 batch[ID_WALLETINFO]["result"]["unlocked_until"]);
401 }
402 result.pushKV("paytxfee",
403 batch[ID_WALLETINFO]["result"]["paytxfee"]);
404 }
405 if (!batch[ID_BALANCES]["result"].isNull()) {
406 result.pushKV("balance",
407 batch[ID_BALANCES]["result"]["mine"]["trusted"]);
408 }
409 result.pushKV("relayfee", batch[ID_NETWORKINFO]["result"]["relayfee"]);
410 result.pushKV("warnings", batch[ID_NETWORKINFO]["result"]["warnings"]);
411 return JSONRPCReplyObj(result, NullUniValue, 1);
412 }
413};
414
417private:
418 static constexpr int8_t UNKNOWN_NETWORK{-1};
419 static constexpr uint8_t m_networks_size{3};
420 const std::array<std::string, m_networks_size> m_networks{
421 {"ipv4", "ipv6", "onion"}};
423 std::array<std::array<uint16_t, m_networks_size + 2>, 3> m_counts{{{}}};
424 int8_t NetworkStringToId(const std::string &str) const {
425 for (uint8_t i = 0; i < m_networks_size; ++i) {
426 if (str == m_networks.at(i)) {
427 return i;
428 }
429 }
430 return UNKNOWN_NETWORK;
431 }
434 bool DetailsRequested() const {
435 return m_details_level > 0 && m_details_level < 5;
436 }
437 bool IsAddressSelected() const {
438 return m_details_level == 2 || m_details_level == 4;
439 }
440 bool IsVersionSelected() const {
441 return m_details_level == 3 || m_details_level == 4;
442 }
443 bool m_is_asmap_on{false};
447 struct Peer {
448 std::string addr;
449 std::string sub_version;
450 std::string network;
451 std::string age;
452 double min_ping;
453 double ping;
458 int id;
463 bool operator<(const Peer &rhs) const {
464 return std::tie(is_outbound, min_ping) <
465 std::tie(rhs.is_outbound, rhs.min_ping);
466 }
467 };
468 std::vector<Peer> m_peers;
469 std::string ChainToString() const {
471 return " testnet";
472 }
474 return " regtest";
475 }
476 return "";
477 }
478 std::string PingTimeToString(double seconds) const {
479 if (seconds < 0) {
480 return "";
481 }
482 const double milliseconds{round(1000 * seconds)};
483 return milliseconds > 999999 ? "-" : ToString(milliseconds);
484 }
487
488public:
489 static constexpr int ID_PEERINFO = 0;
490 static constexpr int ID_NETWORKINFO = 1;
491
492 UniValue PrepareRequest(const std::string &method,
493 const std::vector<std::string> &args) override {
494 if (!args.empty()) {
495 uint8_t n{0};
496 if (ParseUInt8(args.at(0), &n)) {
497 m_details_level = n;
498 }
499 }
500 UniValue result(UniValue::VARR);
501 result.push_back(
503 result.push_back(
504 JSONRPCRequestObj("getnetworkinfo", NullUniValue, ID_NETWORKINFO));
505 return result;
506 }
507
509 const std::vector<UniValue> batch{JSONRPCProcessBatchReply(batch_in)};
510 if (!batch[ID_PEERINFO]["error"].isNull()) {
511 return batch[ID_PEERINFO];
512 }
513 if (!batch[ID_NETWORKINFO]["error"].isNull()) {
514 return batch[ID_NETWORKINFO];
515 }
516
517 const UniValue &networkinfo{batch[ID_NETWORKINFO]["result"]};
518 if (networkinfo["version"].getInt<int>() < 230000) {
519 throw std::runtime_error("-netinfo requires bitcoind server to be "
520 "running v0.23.0 and up");
521 }
522
523 // Count peer connection totals, and if DetailsRequested(), store peer
524 // data in a vector of structs.
525 for (const UniValue &peer : batch[ID_PEERINFO]["result"].getValues()) {
526 const std::string network{peer["network"].get_str()};
527 const int8_t network_id{NetworkStringToId(network)};
529 continue;
530 }
531 const bool is_outbound{!peer["inbound"].get_bool()};
532 const bool is_block_relay{!peer["relaytxes"].get_bool()};
533 // in/out by network
534 ++m_counts.at(is_outbound).at(network_id);
535 // in/out overall
536 ++m_counts.at(is_outbound).at(m_networks_size);
537 // total by network
538 ++m_counts.at(2).at(network_id);
539 // total overall
540 ++m_counts.at(2).at(m_networks_size);
541 if (is_block_relay) {
542 // in/out block-relay
543 ++m_counts.at(is_outbound).at(m_networks_size + 1);
544 // total block-relay
545 ++m_counts.at(2).at(m_networks_size + 1);
546 }
547 if (DetailsRequested()) {
548 // Push data for this peer to the peers vector.
549 const int peer_id{peer["id"].getInt<int>()};
550 const int mapped_as{peer["mapped_as"].isNull()
551 ? 0
552 : peer["mapped_as"].getInt<int>()};
553 const int version{peer["version"].getInt<int>()};
554 const int64_t conn_time{peer["conntime"].getInt<int64_t>()};
555 const int64_t last_blck{peer["last_block"].getInt<int64_t>()};
556 const int64_t last_recv{peer["lastrecv"].getInt<int64_t>()};
557 const int64_t last_send{peer["lastsend"].getInt<int64_t>()};
558 const int64_t last_trxn{
559 peer["last_transaction"].getInt<int64_t>()};
560 const double min_ping{
561 peer["minping"].isNull() ? -1 : peer["minping"].get_real()};
562 const double ping{peer["pingtime"].isNull()
563 ? -1
564 : peer["pingtime"].get_real()};
565 const std::string addr{peer["addr"].get_str()};
566 const std::string age{
567 conn_time == 0 ? ""
568 : ToString((m_time_now - conn_time) / 60)};
569 const std::string sub_version{peer["subver"].get_str()};
570 m_peers.push_back({addr, sub_version, network, age, min_ping,
571 ping, last_blck, last_recv, last_send,
572 last_trxn, peer_id, mapped_as, version,
573 is_block_relay, is_outbound});
575 std::max(addr.length() + 1, m_max_addr_length);
576 m_max_age_length = std::max(age.length(), m_max_age_length);
579 m_is_asmap_on |= (mapped_as != 0);
580 }
581 }
582
583 // Generate report header.
584 std::string result{strprintf(
585 "%s %s%s - %i%s\n\n", PACKAGE_NAME, FormatFullVersion(),
586 ChainToString(), networkinfo["protocolversion"].getInt<int>(),
587 networkinfo["subversion"].get_str())};
588
589 // Report detailed peer connections list sorted by direction and minimum
590 // ping time.
591 if (DetailsRequested() && !m_peers.empty()) {
592 std::sort(m_peers.begin(), m_peers.end());
593 result += strprintf(
594 "Peer connections sorted by direction and min ping\n<-> relay "
595 " net mping ping send recv txn blk %*s ",
596 m_max_age_length, "age");
597 if (m_is_asmap_on) {
598 result += " asmap ";
599 }
600 result += strprintf("%*s %-*s%s\n", m_max_id_length, "id",
602 IsAddressSelected() ? "address" : "",
603 IsVersionSelected() ? "version" : "");
604 for (const Peer &peer : m_peers) {
605 std::string version{ToString(peer.version) + peer.sub_version};
606 result += strprintf(
607 "%3s %5s %5s%7s%7s%5s%5s%5s%5s %*s%*i %*s %-*s%s\n",
608 peer.is_outbound ? "out" : "in",
609 peer.is_block_relay ? "block" : "full", peer.network,
610 PingTimeToString(peer.min_ping),
611 PingTimeToString(peer.ping),
612 peer.last_send == 0 ? ""
613 : ToString(m_time_now - peer.last_send),
614 peer.last_recv == 0 ? ""
615 : ToString(m_time_now - peer.last_recv),
616 peer.last_trxn == 0
617 ? ""
618 : ToString((m_time_now - peer.last_trxn) / 60),
619 peer.last_blck == 0
620 ? ""
621 : ToString((m_time_now - peer.last_blck) / 60),
622 // variable spacing
623 m_max_age_length, peer.age,
624 // variable spacing
625 m_is_asmap_on ? 7 : 0,
626 m_is_asmap_on && peer.mapped_as != 0
627 ? ToString(peer.mapped_as)
628 : "",
629 // variable spacing
630 m_max_id_length, peer.id,
631 // variable spacing
633 IsAddressSelected() ? peer.addr : "",
634 IsVersionSelected() && version != "0" ? version : "");
635 }
636 result += strprintf(
637 " ms ms sec sec min min %*s\n\n",
638 m_max_age_length, "min");
639 }
640
641 // Report peer connection totals by type.
642 result += " ipv4 ipv6 onion total block-relay\n";
643 const std::array<std::string, 3> rows{{"in", "out", "total"}};
644 for (uint8_t i = 0; i < m_networks_size; ++i) {
645 result += strprintf("%-5s %5i %5i %5i %5i %5i\n",
646 rows.at(i), m_counts.at(i).at(0),
647 m_counts.at(i).at(1), m_counts.at(i).at(2),
648 m_counts.at(i).at(m_networks_size),
649 m_counts.at(i).at(m_networks_size + 1));
650 }
651
652 // Report local addresses, ports, and scores.
653 result += "\nLocal addresses";
654 const std::vector<UniValue> &local_addrs{
655 networkinfo["localaddresses"].getValues()};
656 if (local_addrs.empty()) {
657 result += ": n/a\n";
658 } else {
659 size_t max_addr_size{0};
660 for (const UniValue &addr : local_addrs) {
661 max_addr_size = std::max(addr["address"].get_str().length() + 1,
663 }
664 for (const UniValue &addr : local_addrs) {
665 result += strprintf("\n%-*s port %6i score %6i",
666 max_addr_size, addr["address"].get_str(),
667 addr["port"].getInt<int>(),
668 addr["score"].getInt<int>());
669 }
670 }
671
672 return JSONRPCReplyObj(UniValue{result}, NullUniValue, 1);
673 }
674};
675
678public:
679 UniValue PrepareRequest(const std::string &method,
680 const std::vector<std::string> &args) override {
681 address_str = args.at(1);
682 UniValue params{RPCConvertValues("generatetoaddress", args)};
683 return JSONRPCRequestObj("generatetoaddress", params, 1);
684 }
685
686 UniValue ProcessReply(const UniValue &reply) override {
687 UniValue result(UniValue::VOBJ);
688 result.pushKV("address", address_str);
689 result.pushKV("blocks", reply.get_obj()["result"]);
690 return JSONRPCReplyObj(result, NullUniValue, 1);
691 }
692
693protected:
694 std::string address_str;
695};
696
699public:
700 UniValue PrepareRequest(const std::string &method,
701 const std::vector<std::string> &args) override {
702 UniValue params;
703 if (gArgs.GetBoolArg("-named", DEFAULT_NAMED)) {
704 params = RPCConvertNamedValues(method, args);
705 } else {
706 params = RPCConvertValues(method, args);
707 }
708 return JSONRPCRequestObj(method, params, 1);
709 }
710
711 UniValue ProcessReply(const UniValue &reply) override {
712 return reply.get_obj();
713 }
714};
715
716static UniValue CallRPC(BaseRequestHandler *rh, const std::string &strMethod,
717 const std::vector<std::string> &args,
718 const std::optional<std::string> &rpcwallet = {}) {
719 std::string host;
720 // In preference order, we choose the following for the port:
721 // 1. -rpcport
722 // 2. port in -rpcconnect (ie following : in ipv4 or ]: in ipv6)
723 // 3. default port for chain
724 uint16_t port{BaseParams().RPCPort()};
725 SplitHostPort(gArgs.GetArg("-rpcconnect", DEFAULT_RPCCONNECT), port, host);
726 port = static_cast<uint16_t>(gArgs.GetIntArg("-rpcport", port));
727
728 // Obtain event base
730
731 // Synchronously look up hostname
733 obtain_evhttp_connection_base(base.get(), host, port);
734
735 // Set connection timeout
736 {
737 const int timeout =
738 gArgs.GetIntArg("-rpcclienttimeout", DEFAULT_HTTP_CLIENT_TIMEOUT);
739 if (timeout > 0) {
740 evhttp_connection_set_timeout(evcon.get(), timeout);
741 } else {
742 // Indefinite request timeouts are not possible in libevent-http,
743 // so we set the timeout to a very long time period instead.
744
745 // Average length of year in Gregorian calendar
746 constexpr int YEAR_IN_SECONDS = 31556952;
748 }
749 }
750
754 if (req == nullptr) {
755 throw std::runtime_error("create http request failed");
756 }
757#if LIBEVENT_VERSION_NUMBER >= 0x02010300
759#endif
760
761 // Get credentials
762 std::string strRPCUserColonPass;
763 bool failedToGetAuthCookie = false;
764 if (gArgs.GetArg("-rpcpassword", "") == "") {
765 // Try fall back to cookie-based authentication if no password is
766 // provided
769 }
770 } else {
771 strRPCUserColonPass = gArgs.GetArg("-rpcuser", "") + ":" +
772 gArgs.GetArg("-rpcpassword", "");
773 }
774
775 struct evkeyvalq *output_headers =
778 evhttp_add_header(output_headers, "Host", host.c_str());
779 evhttp_add_header(output_headers, "Connection", "close");
780 evhttp_add_header(output_headers, "Content-Type", "application/json");
782 output_headers, "Authorization",
783 (std::string("Basic ") + EncodeBase64(strRPCUserColonPass)).c_str());
784
785 // Attach request data
786 std::string strRequest = rh->PrepareRequest(strMethod, args).write() + "\n";
787 struct evbuffer *output_buffer =
791
792 // check if we should use a special wallet endpoint
793 std::string endpoint = "/";
794 if (rpcwallet) {
795 char *encodedURI =
796 evhttp_uriencode(rpcwallet->data(), rpcwallet->size(), false);
797 if (encodedURI) {
798 endpoint = "/wallet/" + std::string(encodedURI);
799 free(encodedURI);
800 } else {
801 throw CConnectionFailed("uri-encode failed");
802 }
803 }
804 int r = evhttp_make_request(evcon.get(), req.get(), EVHTTP_REQ_POST,
805 endpoint.c_str());
806 // ownership moved to evcon in above call
807 req.release();
808 if (r != 0) {
809 throw CConnectionFailed("send http request failed");
810 }
811
812 event_base_dispatch(base.get());
813
814 if (response.status == 0) {
815 std::string responseErrorMessage;
816 if (response.error != -1) {
818 strprintf(" (error code %d - \"%s\")", response.error,
820 }
821 throw CConnectionFailed(
822 strprintf("Could not connect to the server %s:%d%s\n\nMake sure "
823 "the bitcoind server is running and that you are "
824 "connecting to the correct RPC port.",
825 host, port, responseErrorMessage));
826 } else if (response.status == HTTP_UNAUTHORIZED) {
828 throw std::runtime_error(strprintf(
829 "Could not locate RPC credentials. No authentication cookie "
830 "could be found, and RPC password is not set. See "
831 "-rpcpassword and -stdinrpcpass. Configuration file: (%s)",
833 } else {
834 throw std::runtime_error(
835 "Authorization failed: Incorrect rpcuser or rpcpassword");
836 }
837 } else if (response.status == HTTP_SERVICE_UNAVAILABLE) {
838 throw std::runtime_error(
839 strprintf("Server response: %s", response.body));
840 } else if (response.status >= 400 && response.status != HTTP_BAD_REQUEST &&
841 response.status != HTTP_NOT_FOUND &&
843 throw std::runtime_error(
844 strprintf("server returned HTTP error %d", response.status));
845 } else if (response.body.empty()) {
846 throw std::runtime_error("no response from server");
847 }
848
849 // Parse reply
851 if (!valReply.read(response.body)) {
852 throw std::runtime_error("couldn't parse reply from server");
853 }
854 const UniValue reply = rh->ProcessReply(valReply);
855 if (reply.empty()) {
856 throw std::runtime_error(
857 "expected reply to have result, error and id properties");
858 }
859
860 return reply;
861}
862
874static UniValue
875ConnectAndCallRPC(BaseRequestHandler *rh, const std::string &strMethod,
876 const std::vector<std::string> &args,
877 const std::optional<std::string> &rpcwallet = {}) {
879 // Execute and handle connection failures with -rpcwait.
880 const bool fWait = gArgs.GetBoolArg("-rpcwait", false);
881 do {
882 try {
883 response = CallRPC(rh, strMethod, args, rpcwallet);
884 if (fWait) {
885 const UniValue &error = response.find_value("error");
886 if (!error.isNull() &&
887 error["code"].getInt<int>() == RPC_IN_WARMUP) {
888 throw CConnectionFailed("server in warmup");
889 }
890 }
891 break; // Connection succeeded, no need to retry.
892 } catch (const CConnectionFailed &) {
893 if (fWait) {
894 UninterruptibleSleep(std::chrono::milliseconds{1000});
895 } else {
896 throw;
897 }
898 }
899 } while (fWait);
900 return response;
901}
902
904static void ParseResult(const UniValue &result, std::string &strPrint) {
905 if (result.isNull()) {
906 return;
907 }
908 strPrint = result.isStr() ? result.get_str() : result.write(2);
909}
910
915static void ParseError(const UniValue &error, std::string &strPrint,
916 int &nRet) {
917 if (error.isObject()) {
918 const UniValue &err_code = error.find_value("code");
919 const UniValue &err_msg = error.find_value("message");
920 if (!err_code.isNull()) {
921 strPrint = "error code: " + err_code.getValStr() + "\n";
922 }
923 if (err_msg.isStr()) {
924 strPrint += ("error message:\n" + err_msg.get_str());
925 }
926 if (err_code.isNum() &&
927 err_code.getInt<int>() == RPC_WALLET_NOT_SPECIFIED) {
928 strPrint += "\nTry adding \"-rpcwallet=<filename>\" option to "
929 "bitcoin-cli command line.";
930 }
931 } else {
932 strPrint = "error: " + error.write();
933 }
934 nRet = abs(error["code"].getInt<int>());
935}
936
945static void GetWalletBalances(UniValue &result) {
947 const UniValue listwallets =
948 ConnectAndCallRPC(&rh, "listwallets", /* args=*/{});
949 if (!listwallets.find_value("error").isNull()) {
950 return;
951 }
952 const UniValue &wallets = listwallets.find_value("result");
953 if (wallets.size() <= 1) {
954 return;
955 }
956
958 for (const UniValue &wallet : wallets.getValues()) {
959 const std::string wallet_name = wallet.get_str();
960 const UniValue getbalances =
961 ConnectAndCallRPC(&rh, "getbalances", /* args=*/{}, wallet_name);
962 const UniValue &balance =
963 getbalances.find_value("result")["mine"]["trusted"];
965 }
966 result.pushKV("balances", balances);
967}
968
974 std::optional<std::string> wallet_name{};
975 if (gArgs.IsArgSet("-rpcwallet")) {
976 wallet_name = gArgs.GetArg("-rpcwallet", "");
977 }
979 return ConnectAndCallRPC(&rh, "getnewaddress", /* args=*/{}, wallet_name);
980}
981
989static void SetGenerateToAddressArgs(const std::string &address,
990 std::vector<std::string> &args) {
991 if (args.size() > 2) {
992 throw std::runtime_error(
993 "too many arguments (maximum 2 for nblocks and maxtries)");
994 }
995 if (args.size() == 0) {
996 args.emplace_back(DEFAULT_NBLOCKS);
997 } else if (args.at(0) == "0") {
998 throw std::runtime_error(
999 "the first argument (number of blocks to generate, default: " +
1000 DEFAULT_NBLOCKS + ") must be an integer value greater than zero");
1001 }
1002 args.emplace(args.begin() + 1, address);
1003}
1004
1005static int CommandLineRPC(int argc, char *argv[]) {
1006 std::string strPrint;
1007 int nRet = 0;
1008 try {
1009 // Skip switches
1010 while (argc > 1 && IsSwitchChar(argv[1][0])) {
1011 argc--;
1012 argv++;
1013 }
1014 std::string rpcPass;
1015 if (gArgs.GetBoolArg("-stdinrpcpass", false)) {
1016 NO_STDIN_ECHO();
1017 if (!StdinReady()) {
1018 fputs("RPC password> ", stderr);
1019 fflush(stderr);
1020 }
1021 if (!std::getline(std::cin, rpcPass)) {
1022 throw std::runtime_error("-stdinrpcpass specified but failed "
1023 "to read from standard input");
1024 }
1025 if (StdinTerminal()) {
1026 fputc('\n', stdout);
1027 }
1028 gArgs.ForceSetArg("-rpcpassword", rpcPass);
1029 }
1030 std::vector<std::string> args =
1031 std::vector<std::string>(&argv[1], &argv[argc]);
1032 if (gArgs.GetBoolArg("-stdinwalletpassphrase", false)) {
1033 NO_STDIN_ECHO();
1034 std::string walletPass;
1035 if (args.size() < 1 ||
1036 args[0].substr(0, 16) != "walletpassphrase") {
1037 throw std::runtime_error(
1038 "-stdinwalletpassphrase is only applicable for "
1039 "walletpassphrase(change)");
1040 }
1041 if (!StdinReady()) {
1042 fputs("Wallet passphrase> ", stderr);
1043 fflush(stderr);
1044 }
1045 if (!std::getline(std::cin, walletPass)) {
1046 throw std::runtime_error("-stdinwalletpassphrase specified but "
1047 "failed to read from standard input");
1048 }
1049 if (StdinTerminal()) {
1050 fputc('\n', stdout);
1051 }
1052 args.insert(args.begin() + 1, walletPass);
1053 }
1054 if (gArgs.GetBoolArg("-stdin", false)) {
1055 // Read one arg per line from stdin and append
1056 std::string line;
1057 while (std::getline(std::cin, line)) {
1058 args.push_back(line);
1059 }
1060 if (StdinTerminal()) {
1061 fputc('\n', stdout);
1062 }
1063 }
1064 std::unique_ptr<BaseRequestHandler> rh;
1065 std::string method;
1066 if (gArgs.IsArgSet("-getinfo")) {
1067 rh.reset(new GetinfoRequestHandler());
1068 } else if (gArgs.GetBoolArg("-generate", false)) {
1070 const UniValue &error{getnewaddress.find_value("error")};
1071 if (error.isNull()) {
1073 getnewaddress.find_value("result").get_str(), args);
1075 } else {
1077 }
1078 } else if (gArgs.GetBoolArg("-netinfo", false)) {
1079 rh.reset(new NetinfoRequestHandler());
1080 } else {
1081 rh.reset(new DefaultRequestHandler());
1082 if (args.size() < 1) {
1083 throw std::runtime_error(
1084 "too few parameters (need at least command)");
1085 }
1086 method = args[0];
1087 // Remove trailing method name from arguments vector
1088 args.erase(args.begin());
1089 }
1090
1091 if (nRet == 0) {
1092 // Perform RPC call
1093 std::optional<std::string> wallet_name{};
1094 if (gArgs.IsArgSet("-rpcwallet")) {
1095 wallet_name = gArgs.GetArg("-rpcwallet", "");
1096 }
1097 const UniValue reply =
1098 ConnectAndCallRPC(rh.get(), method, args, wallet_name);
1099
1100 // Parse reply
1101 UniValue result = reply.find_value("result");
1102 const UniValue &error = reply.find_value("error");
1103 if (error.isNull()) {
1104 if (gArgs.IsArgSet("-getinfo") &&
1105 !gArgs.IsArgSet("-rpcwallet")) {
1106 // fetch multiwallet balances and append to result
1107 GetWalletBalances(result);
1108 }
1109 ParseResult(result, strPrint);
1110 } else {
1112 }
1113 }
1114 } catch (const std::exception &e) {
1115 strPrint = std::string("error: ") + e.what();
1117 } catch (...) {
1118 PrintExceptionContinue(nullptr, "CommandLineRPC()");
1119 throw;
1120 }
1121
1122 if (strPrint != "") {
1123 tfm::format(nRet == 0 ? std::cout : std::cerr, "%s\n", strPrint);
1124 }
1125 return nRet;
1126}
1127
1128#ifdef WIN32
1129// Export main() and ensure working ASLR on Windows.
1130// Exporting a symbol will prevent the linker from stripping
1131// the .reloc section from the binary, which is a requirement
1132// for ASLR. This is a temporary workaround until a fixed
1133// version of binutils is used for releases.
1134__declspec(dllexport) int main(int argc, char *argv[]) {
1135 common::WinCmdLineArgs winArgs;
1136 std::tie(argc, argv) = winArgs.get();
1137#else
1138int main(int argc, char *argv[]) {
1139#endif
1141 if (!SetupNetworking()) {
1142 tfm::format(std::cerr, "Error: Initializing networking failed\n");
1143 return EXIT_FAILURE;
1144 }
1146
1147 try {
1148 int ret = AppInitRPC(argc, argv);
1149 if (ret != CONTINUE_EXECUTION) {
1150 return ret;
1151 }
1152 } catch (const std::exception &e) {
1153 PrintExceptionContinue(&e, "AppInitRPC()");
1154 return EXIT_FAILURE;
1155 } catch (...) {
1156 PrintExceptionContinue(nullptr, "AppInitRPC()");
1157 return EXIT_FAILURE;
1158 }
1159
1160 int ret = EXIT_FAILURE;
1161 try {
1163 } catch (const std::exception &e) {
1164 PrintExceptionContinue(&e, "CommandLineRPC()");
1165 } catch (...) {
1166 PrintExceptionContinue(nullptr, "CommandLineRPC()");
1167 }
1168 return ret;
1169}
bool HelpRequested(const ArgsManager &args)
Definition args.cpp:732
void SetupHelpOptions(ArgsManager &args)
Add help options to the args manager.
Definition args.cpp:737
bool CheckDataDirOption(const ArgsManager &args)
Definition args.cpp:784
ArgsManager gArgs
Definition args.cpp:38
const char *const BITCOIN_CONF_FILENAME
Definition args.cpp:35
bool IsSwitchChar(char c)
Definition args.h:47
int main(void)
Definition bench.c:157
secp256k1_context * ctx
static const char DEFAULT_RPCCONNECT[]
static const int CONTINUE_EXECUTION
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
static void http_request_done(struct evhttp_request *req, void *ctx)
const std::function< std::string(const char *)> G_TRANSLATION_FUN
Translate string to current locale using Qt.
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.
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 void SetupCliArgs(ArgsManager &argsman)
std::chrono::system_clock CliClock
#define EVENT_LOG_ERR
static std::string http_errorstring(int code)
static void libevent_log_cb(int severity, const char *msg)
libevent event log callback
static const bool DEFAULT_NAMED
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.
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.
@ NETWORK_ONLY
Definition args.h:110
@ ALLOW_ANY
Definition args.h:103
@ ALLOW_INT
Definition args.h:101
void ForceSetArg(const std::string &strArg, const std::string &strValue)
Definition args.cpp:597
bool ParseParameters(int argc, const char *const argv[], std::string &error)
Definition args.cpp:201
std::string GetHelpMessage() const
Get the help string.
Definition args.cpp:653
bool IsArgSet(const std::string &strArg) const
Return true if the given argument has been manually set.
Definition args.cpp:381
int64_t GetIntArg(const std::string &strArg, int64_t nDefault) const
Return integer argument or default value.
Definition args.cpp:526
fs::path GetConfigFilePath() const
Return config file path (read-only)
Definition args.cpp:789
std::string GetArg(const std::string &strArg, const std::string &strDefault) const
Return string argument or default value.
Definition args.cpp:494
bool ReadConfigFiles(std::string &error, bool ignore_invalid_keys=false)
bool GetBoolArg(const std::string &strArg, bool fDefault) const
Return boolean argument or default value.
Definition args.cpp:556
std::string GetChainName() const
Looks for -regtest, -testnet and returns the appropriate BIP70 chain name.
Definition args.cpp:793
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 MAIN
BIP70 chain name strings (main, test or regtest)
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.
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.
std::array< std::array< uint16_t, m_networks_size+2 >, 3 > m_counts
Peer counts by (in/out/total, networks/total/block-relay)
bool IsAddressSelected() const
static constexpr int8_t UNKNOWN_NETWORK
bool IsVersionSelected() const
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
static constexpr int ID_NETWORKINFO
const std::array< std::string, m_networks_size > m_networks
std::string PingTimeToString(double seconds) const
static constexpr uint8_t m_networks_size
void push_back(UniValue val)
Definition univalue.cpp:96
const std::string & get_str() const
const UniValue & find_value(std::string_view key) const
Definition univalue.cpp:229
std::string write(unsigned int prettyIndent=0, unsigned int indentLevel=0) const
bool isNull() const
Definition univalue.h:104
const std::string & getValStr() const
Definition univalue.h:89
const UniValue & get_obj() const
bool empty() const
Definition univalue.h:90
bool isStr() const
Definition univalue.h:108
void pushKV(std::string key, UniValue val)
Definition univalue.cpp:115
UniValue RPCConvertValues(const std::string &strMethod, const std::vector< std::string > &strParams)
Convert positional arguments to command-specific RPC representation.
Definition client.cpp:272
UniValue RPCConvertNamedValues(const std::string &strMethod, const std::vector< std::string > &strParams)
Convert named arguments to command-specific RPC representation.
Definition client.cpp:284
std::string FormatFullVersion()
std::string LicenseInfo()
Returns licensing information (for -version)
static Amount balance
void SetupCurrencyUnitOptions(ArgsManager &argsman)
raii_evhttp_request obtain_evhttp_request(void(*cb)(struct evhttp_request *, void *), void *arg)
Definition events.h:46
raii_evhttp_connection obtain_evhttp_connection_base(struct event_base *base, std::string host, uint16_t port)
Definition events.h:51
raii_event_base obtain_event_base()
Definition events.h:28
void PrintExceptionContinue(const std::exception *pex, const char *pszThread)
Definition exception.cpp:38
static std::string strRPCUserColonPass
Definition httprpc.cpp:69
bool error(const char *fmt, const Args &...args)
Definition logging.h:226
static const uint64_t DEFAULT_MAX_TRIES
Default max iterations to try in RPC generatetodescriptor, generatetoaddress, and generateblock.
Definition mining.h:12
static std::string PathToString(const path &path)
Convert path object to byte string.
Definition fs.h:142
Implement std::hash so RCUPtr can be used as a key for maps or sets.
Definition rcu.h:257
void format(std::ostream &out, const char *fmt, const Args &...args)
Format list of arguments to the stream according to given format string.
Response response
T GetRand(T nMax=std::numeric_limits< T >::max()) noexcept
Generate a uniform random integer of type T in the range [0..nMax) nMax defaults to std::numeric_limi...
Definition random.h:85
std::vector< UniValue > JSONRPCProcessBatchReply(const UniValue &in)
Parse JSON-RPC batch reply into a vector.
Definition request.cpp:144
bool GetAuthCookie(std::string *cookie_out)
Read the RPC authentication cookie from disk.
Definition request.cpp:118
UniValue JSONRPCRequestObj(const std::string &strMethod, const UniValue &params, const UniValue &id)
JSON-RPC protocol.
Definition request.cpp:30
UniValue JSONRPCReplyObj(const UniValue &result, const UniValue &error, const UniValue &id)
Definition request.cpp:39
static RPCHelpMan ping()
Definition net.cpp:57
@ HTTP_BAD_REQUEST
Definition protocol.h:12
@ HTTP_SERVICE_UNAVAILABLE
Definition protocol.h:18
@ HTTP_UNAUTHORIZED
Definition protocol.h:13
@ HTTP_NOT_FOUND
Definition protocol.h:15
@ HTTP_INTERNAL_SERVER_ERROR
Definition protocol.h:17
@ RPC_WALLET_NOT_SPECIFIED
No wallet specified (error when there are multiple wallets loaded)
Definition protocol.h:111
@ RPC_IN_WARMUP
Client still warming up.
Definition protocol.h:58
static RPCHelpMan getnewaddress()
Definition rpcwallet.cpp:95
static RPCHelpMan listwallets()
static RPCHelpMan getbalances()
static std::string ToString(const CService &ip)
Definition db.h:32
bool StdinReady()
Definition stdin.cpp:54
bool StdinTerminal()
Definition stdin.cpp:46
#define NO_STDIN_ECHO()
Definition stdin.h:13
std::string EncodeBase64(Span< const uint8_t > input)
std::string FormatParagraph(const std::string &in, size_t width, size_t indent)
Format a paragraph of text to a fixed width, adding spaces for indentation to any added line.
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.
Reply structure for request_done to fill in.
std::string body
bool operator<(const Peer &rhs) const
bool SetupNetworking()
Definition system.cpp:98
void SetupEnvironment()
Definition system.cpp:70
void UninterruptibleSleep(const std::chrono::microseconds &n)
Definition time.cpp:23
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
const UniValue NullUniValue
Definition univalue.cpp:16
assert(!tx.IsCoinBase())