6#if defined(HAVE_CONFIG_H)
7#include <config/bitcoin-config.h>
27#include <event2/buffer.h>
28#include <event2/keyvalq_struct.h>
59 const auto defaultBaseParams =
61 const auto testnetBaseParams =
63 const auto regtestBaseParams =
71 strprintf(
"Specify configuration file. Relative paths will be "
72 "prefixed by datadir location. (default: %s)",
75 argsman.
AddArg(
"-datadir=<dir>",
"Specify data directory",
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",
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)",
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).",
105 strprintf(
"Pass named instead of positional arguments (default: %s)",
110 strprintf(
"Send commands to node running on <ip> (default: %s)",
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",
133 "-rpcclienttimeout=<n>",
134 strprintf(
"Timeout in seconds during HTTP requests, or 0 for "
135 "no timeout. (default: %d)",
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.",
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.",
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>",
171#define EVENT_LOG_ERR _EVENT_LOG_ERR
175 throw std::runtime_error(
strprintf(
"libevent error: %s", msg));
191 :
std::runtime_error(msg) {}
205 tfm::format(std::cerr,
"Error parsing command line arguments: %s\n",
210 std::string strUsage =
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 "
224 "or: bitcoin-cli [options] help <command> Get "
225 "help for a command\n";
232 tfm::format(std::cerr,
"Error: too few parameters\n");
239 "Error: Specified data directory \"%s\" does not exist.\n",
251 }
catch (
const std::exception &e) {
269#if LIBEVENT_VERSION_NUMBER >= 0x02010300
270 case EVREQ_HTTP_TIMEOUT:
271 return "timeout reached";
273 return "EOF reached";
274 case EVREQ_HTTP_INVALID_HEADER:
275 return "error while reading header, or invalid header";
276 case EVREQ_HTTP_BUFFER_ERROR:
277 return "error encountered while reading or writing";
278 case EVREQ_HTTP_REQUEST_CANCEL:
279 return "request was canceled";
280 case EVREQ_HTTP_DATA_TOO_LONG:
281 return "response body is larger than allowed";
291 if (req ==
nullptr) {
300 reply->
status = evhttp_request_get_response_code(req);
302 struct evbuffer *buf = evhttp_request_get_input_buffer(req);
304 size_t size = evbuffer_get_length(buf);
305 const char *data = (
const char *)evbuffer_pullup(buf, size);
307 reply->
body = std::string(data, size);
309 evbuffer_drain(buf, size);
313#if LIBEVENT_VERSION_NUMBER >= 0x02010300
314static void http_error_cb(
enum evhttp_request_error err,
void *
ctx) {
328 const std::vector<std::string> &args) = 0;
342 const std::vector<std::string> &args)
override {
344 throw std::runtime_error(
"-getinfo takes no arguments");
375 "verificationprogress",
377 result.
pushKV(
"timeoffset",
385 connections.
pushKV(
"total",
387 result.
pushKV(
"connections", connections);
391 result.
pushKV(
"difficulty",
396 result.
pushKV(
"keypoolsize",
399 result.
pushKV(
"unlocked_until",
421 {
"ipv4",
"ipv6",
"onion"}};
423 std::array<std::array<uint16_t, m_networks_size + 2>, 3>
m_counts{{{}}};
482 const double milliseconds{round(1000 * seconds)};
483 return milliseconds > 999999 ?
"-" :
ToString(milliseconds);
486 TicksSinceEpoch<std::chrono::seconds>(CliClock::now())};
493 const std::vector<std::string> &args)
override {
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");
526 const std::string network{peer[
"network"].get_str()};
531 const bool is_outbound{!peer[
"inbound"].get_bool()};
532 const bool is_block_relay{!peer[
"relaytxes"].get_bool()};
534 ++
m_counts.at(is_outbound).at(network_id);
541 if (is_block_relay) {
549 const int peer_id{peer[
"id"].getInt<
int>()};
550 const int mapped_as{peer[
"mapped_as"].isNull()
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()
564 : peer[
"pingtime"].get_real()};
565 const std::string addr{peer[
"addr"].get_str()};
566 const std::string age{
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});
586 ChainToString(), networkinfo[
"protocolversion"].getInt<int>(),
587 networkinfo[
"subversion"].get_str())};
594 "Peer connections sorted by direction and min ping\n<-> relay "
595 " net mping ping send recv txn blk %*s ",
605 std::string version{
ToString(peer.version) + peer.sub_version};
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,
612 peer.last_send == 0 ?
""
614 peer.last_recv == 0 ?
""
637 " ms ms sec sec min min %*s\n\n",
642 result +=
" ipv4 ipv6 onion total block-relay\n";
643 const std::array<std::string, 3> rows{{
"in",
"out",
"total"}};
645 result +=
strprintf(
"%-5s %5i %5i %5i %5i %5i\n",
653 result +=
"\nLocal addresses";
654 const std::vector<UniValue> &local_addrs{
655 networkinfo[
"localaddresses"].getValues()};
656 if (local_addrs.empty()) {
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,
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>());
680 const std::vector<std::string> &args)
override {
701 const std::vector<std::string> &args)
override {
717 const std::vector<std::string> &args,
718 const std::optional<std::string> &rpcwallet = {}) {
732 raii_evhttp_connection evcon =
740 evhttp_connection_set_timeout(evcon.get(), timeout);
746 constexpr int YEAR_IN_SECONDS = 31556952;
747 evhttp_connection_set_timeout(evcon.get(), 5 * YEAR_IN_SECONDS);
752 raii_evhttp_request req =
754 if (req ==
nullptr) {
755 throw std::runtime_error(
"create http request failed");
757#if LIBEVENT_VERSION_NUMBER >= 0x02010300
758 evhttp_request_set_error_cb(req.get(), http_error_cb);
763 bool failedToGetAuthCookie =
false;
768 failedToGetAuthCookie =
true;
775 struct evkeyvalq *output_headers =
776 evhttp_request_get_output_headers(req.get());
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",
787 struct evbuffer *output_buffer =
788 evhttp_request_get_output_buffer(req.get());
790 evbuffer_add(output_buffer, strRequest.data(), strRequest.size());
793 std::string endpoint =
"/";
796 evhttp_uriencode(rpcwallet->data(), rpcwallet->size(),
false);
798 endpoint =
"/wallet/" + std::string(encodedURI);
804 int r = evhttp_make_request(evcon.get(), req.get(), EVHTTP_REQ_POST,
812 event_base_dispatch(base.get());
815 std::string responseErrorMessage;
817 responseErrorMessage =
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));
827 if (failedToGetAuthCookie) {
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)",
834 throw std::runtime_error(
835 "Authorization failed: Incorrect rpcuser or rpcpassword");
838 throw std::runtime_error(
843 throw std::runtime_error(
846 throw std::runtime_error(
"no response from server");
851 if (!valReply.read(
response.body)) {
852 throw std::runtime_error(
"couldn't parse reply from server");
856 throw std::runtime_error(
857 "expected reply to have result, error and id properties");
876 const std::vector<std::string> &args,
877 const std::optional<std::string> &rpcwallet = {}) {
886 if (!
error.isNull() &&
917 if (
error.isObject()) {
921 strPrint =
"error code: " + err_code.
getValStr() +
"\n";
923 if (err_msg.
isStr()) {
924 strPrint += (
"error message:\n" + err_msg.
get_str());
926 if (err_code.
isNum() &&
928 strPrint +=
"\nTry adding \"-rpcwallet=<filename>\" option to "
929 "bitcoin-cli command line.";
932 strPrint =
"error: " +
error.write();
934 nRet = abs(
error[
"code"].getInt<int>());
953 if (wallets.
size() <= 1) {
959 const std::string wallet_name =
wallet.get_str();
963 getbalances.find_value(
"result")[
"mine"][
"trusted"];
966 result.
pushKV(
"balances", balances);
974 std::optional<std::string> wallet_name{};
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)");
995 if (args.size() == 0) {
997 }
else if (args.at(0) ==
"0") {
998 throw std::runtime_error(
999 "the first argument (number of blocks to generate, default: " +
1002 args.emplace(args.begin() + 1, address);
1006 std::string strPrint;
1014 std::string rpcPass;
1018 fputs(
"RPC password> ", stderr);
1021 if (!std::getline(std::cin, rpcPass)) {
1022 throw std::runtime_error(
"-stdinrpcpass specified but failed "
1023 "to read from standard input");
1026 fputc(
'\n', stdout);
1030 std::vector<std::string> args =
1031 std::vector<std::string>(&argv[1], &argv[argc]);
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)");
1042 fputs(
"Wallet passphrase> ", stderr);
1045 if (!std::getline(std::cin, walletPass)) {
1046 throw std::runtime_error(
"-stdinwalletpassphrase specified but "
1047 "failed to read from standard input");
1050 fputc(
'\n', stdout);
1052 args.insert(args.begin() + 1, walletPass);
1057 while (std::getline(std::cin, line)) {
1058 args.push_back(line);
1061 fputc(
'\n', stdout);
1064 std::unique_ptr<BaseRequestHandler> rh;
1071 if (
error.isNull()) {
1082 if (args.size() < 1) {
1083 throw std::runtime_error(
1084 "too few parameters (need at least command)");
1088 args.erase(args.begin());
1093 std::optional<std::string> wallet_name{};
1103 if (
error.isNull()) {
1114 }
catch (
const std::exception &e) {
1115 strPrint = std::string(
"error: ") + e.what();
1116 nRet = EXIT_FAILURE;
1122 if (strPrint !=
"") {
1123 tfm::format(nRet == 0 ? std::cout : std::cerr,
"%s\n", strPrint);
1134__declspec(dllexport)
int main(
int argc,
char *argv[]) {
1135 common::WinCmdLineArgs winArgs;
1136 std::tie(argc, argv) = winArgs.get();
1142 tfm::format(std::cerr,
"Error: Initializing networking failed\n");
1143 return EXIT_FAILURE;
1152 }
catch (
const std::exception &e) {
1154 return EXIT_FAILURE;
1157 return EXIT_FAILURE;
1160 int ret = EXIT_FAILURE;
1163 }
catch (
const std::exception &e) {
bool HelpRequested(const ArgsManager &args)
void SetupHelpOptions(ArgsManager &args)
Add help options to the args manager.
bool CheckDataDirOption(const ArgsManager &args)
const char *const BITCOIN_CONF_FILENAME
bool IsSwitchChar(char c)
static const char DEFAULT_RPCCONNECT[]
int main(int argc, char *argv[])
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
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.
void ForceSetArg(const std::string &strArg, const std::string &strValue)
bool ParseParameters(int argc, const char *const argv[], std::string &error)
std::string GetHelpMessage() const
Get the help string.
bool IsArgSet(const std::string &strArg) const
Return true if the given argument has been manually set.
int64_t GetIntArg(const std::string &strArg, int64_t nDefault) const
Return integer argument or default value.
fs::path GetConfigFilePath() const
Return config file path (read-only)
std::string GetArg(const std::string &strArg, const std::string &strDefault) const
Return string argument or default value.
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.
void AddArg(const std::string &name, const std::string &help, unsigned int flags, const OptionsCategory &cat)
Add argument.
std::string GetChainName() const
Looks for -regtest, -testnet and returns the appropriate BIP70 chain name.
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
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.
const int ID_BLOCKCHAININFO
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
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)
const std::string & get_str() const
const UniValue & find_value(std::string_view key) const
std::string write(unsigned int prettyIndent=0, unsigned int indentLevel=0) const
const std::string & getValStr() const
const UniValue & get_obj() const
const std::vector< UniValue > & getValues() const
void pushKV(std::string key, UniValue val)
UniValue RPCConvertValues(const std::string &strMethod, const std::vector< std::string > &strParams)
Convert positional arguments to command-specific RPC representation.
UniValue RPCConvertNamedValues(const std::string &strMethod, const std::vector< std::string > &strParams)
Convert named arguments to command-specific RPC representation.
std::string FormatFullVersion()
std::string LicenseInfo()
Returns licensing information (for -version)
void SetupCurrencyUnitOptions(ArgsManager &argsman)
raii_evhttp_request obtain_evhttp_request(void(*cb)(struct evhttp_request *, void *), void *arg)
raii_evhttp_connection obtain_evhttp_connection_base(struct event_base *base, std::string host, uint16_t port)
raii_event_base obtain_event_base()
void PrintExceptionContinue(const std::exception *pex, const char *pszThread)
static std::string strRPCUserColonPass
bool error(const char *fmt, const Args &...args)
static const uint64_t DEFAULT_MAX_TRIES
Default max iterations to try in RPC generatetodescriptor, generatetoaddress, and generateblock.
static bool isNull(const AnyVoteItem &item)
static std::string PathToString(const path &path)
Convert path object to byte string.
Implement std::hash so RCUPtr can be used as a key for maps or sets.
std::vector< UniValue > JSONRPCProcessBatchReply(const UniValue &in)
Parse JSON-RPC batch reply into a vector.
bool GetAuthCookie(std::string *cookie_out)
Read the RPC authentication cookie from disk.
UniValue JSONRPCRequestObj(const std::string &strMethod, const UniValue ¶ms, const UniValue &id)
JSON-RPC protocol.
UniValue JSONRPCReplyObj(const UniValue &result, const UniValue &error, const UniValue &id)
@ HTTP_SERVICE_UNAVAILABLE
@ HTTP_INTERNAL_SERVER_ERROR
@ RPC_WALLET_NOT_SPECIFIED
No wallet specified (error when there are multiple wallets loaded)
@ RPC_IN_WARMUP
Client still warming up.
static RPCHelpMan getnewaddress()
static RPCHelpMan listwallets()
static RPCHelpMan getbalances()
std::string ToString(const T &t)
Locale-independent version of std::to_string.
Reply structure for request_done to fill in.
bool operator<(const Peer &rhs) const
void UninterruptibleSleep(const std::chrono::microseconds &n)
const UniValue NullUniValue
std::string EncodeBase64(Span< const uint8_t > input)
bool ParseUInt8(std::string_view str, uint8_t *out)
Convert decimal string to unsigned 8-bit integer with strict parse error feedback.
std::string FormatParagraph(std::string_view in, size_t width, size_t indent)
Format a paragraph of text to a fixed width, adding spaces for indentation to any added line.
void SplitHostPort(std::string_view in, uint16_t &portOut, std::string &hostOut)