Bitcoin Core  0.20.99
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 <optional.h>
13 #include <rpc/client.h>
14 #include <rpc/protocol.h>
15 #include <rpc/request.h>
16 #include <util/strencodings.h>
17 #include <util/system.h>
18 #include <util/translation.h>
19 #include <util/url.h>
20 
21 #include <functional>
22 #include <memory>
23 #include <stdio.h>
24 #include <string>
25 #include <tuple>
26 
27 #include <event2/buffer.h>
28 #include <event2/keyvalq_struct.h>
29 #include <support/events.h>
30 
31 #include <univalue.h>
32 #include <compat/stdin.h>
33 
34 const std::function<std::string(const char*)> G_TRANSLATION_FUN = nullptr;
36 
37 static const char DEFAULT_RPCCONNECT[] = "127.0.0.1";
38 static const int DEFAULT_HTTP_CLIENT_TIMEOUT=900;
39 static const bool DEFAULT_NAMED=false;
40 static const int CONTINUE_EXECUTION=-1;
41 
42 static void SetupCliArgs()
43 {
45 
46  const auto defaultBaseParams = CreateBaseChainParams(CBaseChainParams::MAIN);
47  const auto testnetBaseParams = CreateBaseChainParams(CBaseChainParams::TESTNET);
48  const auto regtestBaseParams = CreateBaseChainParams(CBaseChainParams::REGTEST);
49 
50  gArgs.AddArg("-version", "Print version and exit", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
51  gArgs.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);
52  gArgs.AddArg("-datadir=<dir>", "Specify data directory", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
53  gArgs.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);
55  gArgs.AddArg("-named", strprintf("Pass named instead of positional arguments (default: %s)", DEFAULT_NAMED), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
56  gArgs.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);
57  gArgs.AddArg("-rpcconnect=<ip>", strprintf("Send commands to node running on <ip> (default: %s)", DEFAULT_RPCCONNECT), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
58  gArgs.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);
59  gArgs.AddArg("-rpcpassword=<pw>", "Password for JSON-RPC connections", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
60  gArgs.AddArg("-rpcport=<port>", strprintf("Connect to JSON-RPC on <port> (default: %u, testnet: %u, regtest: %u)", defaultBaseParams->RPCPort(), testnetBaseParams->RPCPort(), regtestBaseParams->RPCPort()), ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::OPTIONS);
61  gArgs.AddArg("-rpcuser=<user>", "Username for JSON-RPC connections", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
62  gArgs.AddArg("-rpcwait", "Wait for RPC server to start", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
63  gArgs.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);
64  gArgs.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);
65  gArgs.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);
66  gArgs.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);
67 }
68 
70 static void libevent_log_cb(int severity, const char *msg)
71 {
72 #ifndef EVENT_LOG_ERR // EVENT_LOG_ERR was added in 2.0.19; but before then _EVENT_LOG_ERR existed.
73 # define EVENT_LOG_ERR _EVENT_LOG_ERR
74 #endif
75  // Ignore everything other than errors
76  if (severity >= EVENT_LOG_ERR) {
77  throw std::runtime_error(strprintf("libevent error: %s", msg));
78  }
79 }
80 
82 //
83 // Start
84 //
85 
86 //
87 // Exception thrown on connection error. This error is used to determine
88 // when to wait if -rpcwait is given.
89 //
90 class CConnectionFailed : public std::runtime_error
91 {
92 public:
93 
94  explicit inline CConnectionFailed(const std::string& msg) :
95  std::runtime_error(msg)
96  {}
97 
98 };
99 
100 //
101 // This function returns either one of EXIT_ codes when it's expected to stop the process or
102 // CONTINUE_EXECUTION when it's expected to continue further.
103 //
104 static int AppInitRPC(int argc, char* argv[])
105 {
106  //
107  // Parameters
108  //
109  SetupCliArgs();
110  std::string error;
111  if (!gArgs.ParseParameters(argc, argv, error)) {
112  tfm::format(std::cerr, "Error parsing command line arguments: %s\n", error);
113  return EXIT_FAILURE;
114  }
115  if (argc < 2 || HelpRequested(gArgs) || gArgs.IsArgSet("-version")) {
116  std::string strUsage = PACKAGE_NAME " RPC client version " + FormatFullVersion() + "\n";
117  if (!gArgs.IsArgSet("-version")) {
118  strUsage += "\n"
119  "Usage: bitcoin-cli [options] <command> [params] Send command to " PACKAGE_NAME "\n"
120  "or: bitcoin-cli [options] -named <command> [name=value]... Send command to " PACKAGE_NAME " (with named arguments)\n"
121  "or: bitcoin-cli [options] help List commands\n"
122  "or: bitcoin-cli [options] help <command> Get help for a command\n";
123  strUsage += "\n" + gArgs.GetHelpMessage();
124  }
125 
126  tfm::format(std::cout, "%s", strUsage);
127  if (argc < 2) {
128  tfm::format(std::cerr, "Error: too few parameters\n");
129  return EXIT_FAILURE;
130  }
131  return EXIT_SUCCESS;
132  }
133  if (!CheckDataDirOption()) {
134  tfm::format(std::cerr, "Error: Specified data directory \"%s\" does not exist.\n", gArgs.GetArg("-datadir", ""));
135  return EXIT_FAILURE;
136  }
137  if (!gArgs.ReadConfigFiles(error, true)) {
138  tfm::format(std::cerr, "Error reading configuration file: %s\n", error);
139  return EXIT_FAILURE;
140  }
141  // Check for -chain, -testnet or -regtest parameter (BaseParams() calls are only valid after this clause)
142  try {
144  } catch (const std::exception& e) {
145  tfm::format(std::cerr, "Error: %s\n", e.what());
146  return EXIT_FAILURE;
147  }
148  return CONTINUE_EXECUTION;
149 }
150 
151 
153 struct HTTPReply
154 {
155  HTTPReply(): status(0), error(-1) {}
156 
157  int status;
158  int error;
159  std::string body;
160 };
161 
162 static std::string http_errorstring(int code)
163 {
164  switch(code) {
165 #if LIBEVENT_VERSION_NUMBER >= 0x02010300
166  case EVREQ_HTTP_TIMEOUT:
167  return "timeout reached";
168  case EVREQ_HTTP_EOF:
169  return "EOF reached";
170  case EVREQ_HTTP_INVALID_HEADER:
171  return "error while reading header, or invalid header";
172  case EVREQ_HTTP_BUFFER_ERROR:
173  return "error encountered while reading or writing";
174  case EVREQ_HTTP_REQUEST_CANCEL:
175  return "request was canceled";
176  case EVREQ_HTTP_DATA_TOO_LONG:
177  return "response body is larger than allowed";
178 #endif
179  default:
180  return "unknown";
181  }
182 }
183 
184 static void http_request_done(struct evhttp_request *req, void *ctx)
185 {
186  HTTPReply *reply = static_cast<HTTPReply*>(ctx);
187 
188  if (req == nullptr) {
189  /* If req is nullptr, it means an error occurred while connecting: the
190  * error code will have been passed to http_error_cb.
191  */
192  reply->status = 0;
193  return;
194  }
195 
196  reply->status = evhttp_request_get_response_code(req);
197 
198  struct evbuffer *buf = evhttp_request_get_input_buffer(req);
199  if (buf)
200  {
201  size_t size = evbuffer_get_length(buf);
202  const char *data = (const char*)evbuffer_pullup(buf, size);
203  if (data)
204  reply->body = std::string(data, size);
205  evbuffer_drain(buf, size);
206  }
207 }
208 
209 #if LIBEVENT_VERSION_NUMBER >= 0x02010300
210 static void http_error_cb(enum evhttp_request_error err, void *ctx)
211 {
212  HTTPReply *reply = static_cast<HTTPReply*>(ctx);
213  reply->error = err;
214 }
215 #endif
216 
221 {
222 public:
223  virtual ~BaseRequestHandler() {}
224  virtual UniValue PrepareRequest(const std::string& method, const std::vector<std::string>& args) = 0;
225  virtual UniValue ProcessReply(const UniValue &batch_in) = 0;
226 };
227 
230 {
231 public:
232  const int ID_NETWORKINFO = 0;
233  const int ID_BLOCKCHAININFO = 1;
234  const int ID_WALLETINFO = 2;
235  const int ID_BALANCES = 3;
236 
238  UniValue PrepareRequest(const std::string& method, const std::vector<std::string>& args) override
239  {
240  if (!args.empty()) {
241  throw std::runtime_error("-getinfo takes no arguments");
242  }
243  UniValue result(UniValue::VARR);
244  result.push_back(JSONRPCRequestObj("getnetworkinfo", NullUniValue, ID_NETWORKINFO));
245  result.push_back(JSONRPCRequestObj("getblockchaininfo", NullUniValue, ID_BLOCKCHAININFO));
246  result.push_back(JSONRPCRequestObj("getwalletinfo", NullUniValue, ID_WALLETINFO));
247  result.push_back(JSONRPCRequestObj("getbalances", NullUniValue, ID_BALANCES));
248  return result;
249  }
250 
252  UniValue ProcessReply(const UniValue &batch_in) override
253  {
254  UniValue result(UniValue::VOBJ);
255  const std::vector<UniValue> batch = JSONRPCProcessBatchReply(batch_in);
256  // Errors in getnetworkinfo() and getblockchaininfo() are fatal, pass them on;
257  // getwalletinfo() and getbalances() are allowed to fail if there is no wallet.
258  if (!batch[ID_NETWORKINFO]["error"].isNull()) {
259  return batch[ID_NETWORKINFO];
260  }
261  if (!batch[ID_BLOCKCHAININFO]["error"].isNull()) {
262  return batch[ID_BLOCKCHAININFO];
263  }
264  result.pushKV("version", batch[ID_NETWORKINFO]["result"]["version"]);
265  result.pushKV("blocks", batch[ID_BLOCKCHAININFO]["result"]["blocks"]);
266  result.pushKV("headers", batch[ID_BLOCKCHAININFO]["result"]["headers"]);
267  result.pushKV("verificationprogress", batch[ID_BLOCKCHAININFO]["result"]["verificationprogress"]);
268  result.pushKV("timeoffset", batch[ID_NETWORKINFO]["result"]["timeoffset"]);
269  result.pushKV("connections", batch[ID_NETWORKINFO]["result"]["connections"]);
270  result.pushKV("proxy", batch[ID_NETWORKINFO]["result"]["networks"][0]["proxy"]);
271  result.pushKV("difficulty", batch[ID_BLOCKCHAININFO]["result"]["difficulty"]);
272  result.pushKV("chain", UniValue(batch[ID_BLOCKCHAININFO]["result"]["chain"]));
273  if (!batch[ID_WALLETINFO]["result"].isNull()) {
274  result.pushKV("keypoolsize", batch[ID_WALLETINFO]["result"]["keypoolsize"]);
275  if (!batch[ID_WALLETINFO]["result"]["unlocked_until"].isNull()) {
276  result.pushKV("unlocked_until", batch[ID_WALLETINFO]["result"]["unlocked_until"]);
277  }
278  result.pushKV("paytxfee", batch[ID_WALLETINFO]["result"]["paytxfee"]);
279  }
280  if (!batch[ID_BALANCES]["result"].isNull()) {
281  result.pushKV("balance", batch[ID_BALANCES]["result"]["mine"]["trusted"]);
282  }
283  result.pushKV("relayfee", batch[ID_NETWORKINFO]["result"]["relayfee"]);
284  result.pushKV("warnings", batch[ID_NETWORKINFO]["result"]["warnings"]);
285  return JSONRPCReplyObj(result, NullUniValue, 1);
286  }
287 };
288 
291 public:
292  UniValue PrepareRequest(const std::string& method, const std::vector<std::string>& args) override
293  {
294  UniValue params;
295  if(gArgs.GetBoolArg("-named", DEFAULT_NAMED)) {
296  params = RPCConvertNamedValues(method, args);
297  } else {
298  params = RPCConvertValues(method, args);
299  }
300  return JSONRPCRequestObj(method, params, 1);
301  }
302 
303  UniValue ProcessReply(const UniValue &reply) override
304  {
305  return reply.get_obj();
306  }
307 };
308 
309 static UniValue CallRPC(BaseRequestHandler* rh, const std::string& strMethod, const std::vector<std::string>& args, const Optional<std::string>& rpcwallet = {})
310 {
311  std::string host;
312  // In preference order, we choose the following for the port:
313  // 1. -rpcport
314  // 2. port in -rpcconnect (ie following : in ipv4 or ]: in ipv6)
315  // 3. default port for chain
316  int port = BaseParams().RPCPort();
317  SplitHostPort(gArgs.GetArg("-rpcconnect", DEFAULT_RPCCONNECT), port, host);
318  port = gArgs.GetArg("-rpcport", port);
319 
320  // Obtain event base
321  raii_event_base base = obtain_event_base();
322 
323  // Synchronously look up hostname
324  raii_evhttp_connection evcon = obtain_evhttp_connection_base(base.get(), host, port);
325 
326  // Set connection timeout
327  {
328  const int timeout = gArgs.GetArg("-rpcclienttimeout", DEFAULT_HTTP_CLIENT_TIMEOUT);
329  if (timeout > 0) {
330  evhttp_connection_set_timeout(evcon.get(), timeout);
331  } else {
332  // Indefinite request timeouts are not possible in libevent-http, so we
333  // set the timeout to a very long time period instead.
334 
335  constexpr int YEAR_IN_SECONDS = 31556952; // Average length of year in Gregorian calendar
336  evhttp_connection_set_timeout(evcon.get(), 5 * YEAR_IN_SECONDS);
337  }
338  }
339 
340  HTTPReply response;
341  raii_evhttp_request req = obtain_evhttp_request(http_request_done, (void*)&response);
342  if (req == nullptr)
343  throw std::runtime_error("create http request failed");
344 #if LIBEVENT_VERSION_NUMBER >= 0x02010300
345  evhttp_request_set_error_cb(req.get(), http_error_cb);
346 #endif
347 
348  // Get credentials
349  std::string strRPCUserColonPass;
350  bool failedToGetAuthCookie = false;
351  if (gArgs.GetArg("-rpcpassword", "") == "") {
352  // Try fall back to cookie-based authentication if no password is provided
353  if (!GetAuthCookie(&strRPCUserColonPass)) {
354  failedToGetAuthCookie = true;
355  }
356  } else {
357  strRPCUserColonPass = gArgs.GetArg("-rpcuser", "") + ":" + gArgs.GetArg("-rpcpassword", "");
358  }
359 
360  struct evkeyvalq* output_headers = evhttp_request_get_output_headers(req.get());
361  assert(output_headers);
362  evhttp_add_header(output_headers, "Host", host.c_str());
363  evhttp_add_header(output_headers, "Connection", "close");
364  evhttp_add_header(output_headers, "Authorization", (std::string("Basic ") + EncodeBase64(strRPCUserColonPass)).c_str());
365 
366  // Attach request data
367  std::string strRequest = rh->PrepareRequest(strMethod, args).write() + "\n";
368  struct evbuffer* output_buffer = evhttp_request_get_output_buffer(req.get());
369  assert(output_buffer);
370  evbuffer_add(output_buffer, strRequest.data(), strRequest.size());
371 
372  // check if we should use a special wallet endpoint
373  std::string endpoint = "/";
374  if (rpcwallet) {
375  char* encodedURI = evhttp_uriencode(rpcwallet->data(), rpcwallet->size(), false);
376  if (encodedURI) {
377  endpoint = "/wallet/" + std::string(encodedURI);
378  free(encodedURI);
379  } else {
380  throw CConnectionFailed("uri-encode failed");
381  }
382  }
383  int r = evhttp_make_request(evcon.get(), req.get(), EVHTTP_REQ_POST, endpoint.c_str());
384  req.release(); // ownership moved to evcon in above call
385  if (r != 0) {
386  throw CConnectionFailed("send http request failed");
387  }
388 
389  event_base_dispatch(base.get());
390 
391  if (response.status == 0) {
392  std::string responseErrorMessage;
393  if (response.error != -1) {
394  responseErrorMessage = strprintf(" (error code %d - \"%s\")", response.error, http_errorstring(response.error));
395  }
396  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));
397  } else if (response.status == HTTP_UNAUTHORIZED) {
398  if (failedToGetAuthCookie) {
399  throw std::runtime_error(strprintf(
400  "Could not locate RPC credentials. No authentication cookie could be found, and RPC password is not set. See -rpcpassword and -stdinrpcpass. Configuration file: (%s)",
401  GetConfigFile(gArgs.GetArg("-conf", BITCOIN_CONF_FILENAME)).string()));
402  } else {
403  throw std::runtime_error("Authorization failed: Incorrect rpcuser or rpcpassword");
404  }
405  } else if (response.status >= 400 && response.status != HTTP_BAD_REQUEST && response.status != HTTP_NOT_FOUND && response.status != HTTP_INTERNAL_SERVER_ERROR)
406  throw std::runtime_error(strprintf("server returned HTTP error %d", response.status));
407  else if (response.body.empty())
408  throw std::runtime_error("no response from server");
409 
410  // Parse reply
411  UniValue valReply(UniValue::VSTR);
412  if (!valReply.read(response.body))
413  throw std::runtime_error("couldn't parse reply from server");
414  const UniValue reply = rh->ProcessReply(valReply);
415  if (reply.empty())
416  throw std::runtime_error("expected reply to have result, error and id properties");
417 
418  return reply;
419 }
420 
430 static UniValue ConnectAndCallRPC(BaseRequestHandler* rh, const std::string& strMethod, const std::vector<std::string>& args, const Optional<std::string>& rpcwallet = {})
431 {
432  UniValue response(UniValue::VOBJ);
433  // Execute and handle connection failures with -rpcwait.
434  const bool fWait = gArgs.GetBoolArg("-rpcwait", false);
435  do {
436  try {
437  response = CallRPC(rh, strMethod, args, rpcwallet);
438  if (fWait) {
439  const UniValue& error = find_value(response, "error");
440  if (!error.isNull() && error["code"].get_int() == RPC_IN_WARMUP) {
441  throw CConnectionFailed("server in warmup");
442  }
443  }
444  break; // Connection succeeded, no need to retry.
445  } catch (const CConnectionFailed&) {
446  if (fWait) {
447  UninterruptibleSleep(std::chrono::milliseconds{1000});
448  } else {
449  throw;
450  }
451  }
452  } while (fWait);
453  return response;
454 }
455 
462 static void GetWalletBalances(UniValue& result)
463 {
464  std::unique_ptr<BaseRequestHandler> rh{MakeUnique<DefaultRequestHandler>()};
465  const UniValue listwallets = ConnectAndCallRPC(rh.get(), "listwallets", /* args=*/{});
466  if (!find_value(listwallets, "error").isNull()) return;
467  const UniValue& wallets = find_value(listwallets, "result");
468  if (wallets.size() <= 1) return;
469 
470  UniValue balances(UniValue::VOBJ);
471  for (const UniValue& wallet : wallets.getValues()) {
472  const std::string wallet_name = wallet.get_str();
473  const UniValue getbalances = ConnectAndCallRPC(rh.get(), "getbalances", /* args=*/{}, wallet_name);
474  const UniValue& balance = find_value(getbalances, "result")["mine"]["trusted"];
475  balances.pushKV(wallet_name, balance);
476  }
477  result.pushKV("balances", balances);
478 }
479 
480 static int CommandLineRPC(int argc, char *argv[])
481 {
482  std::string strPrint;
483  int nRet = 0;
484  try {
485  // Skip switches
486  while (argc > 1 && IsSwitchChar(argv[1][0])) {
487  argc--;
488  argv++;
489  }
490  std::string rpcPass;
491  if (gArgs.GetBoolArg("-stdinrpcpass", false)) {
492  NO_STDIN_ECHO();
493  if (!StdinReady()) {
494  fputs("RPC password> ", stderr);
495  fflush(stderr);
496  }
497  if (!std::getline(std::cin, rpcPass)) {
498  throw std::runtime_error("-stdinrpcpass specified but failed to read from standard input");
499  }
500  if (StdinTerminal()) {
501  fputc('\n', stdout);
502  }
503  gArgs.ForceSetArg("-rpcpassword", rpcPass);
504  }
505  std::vector<std::string> args = std::vector<std::string>(&argv[1], &argv[argc]);
506  if (gArgs.GetBoolArg("-stdinwalletpassphrase", false)) {
507  NO_STDIN_ECHO();
508  std::string walletPass;
509  if (args.size() < 1 || args[0].substr(0, 16) != "walletpassphrase") {
510  throw std::runtime_error("-stdinwalletpassphrase is only applicable for walletpassphrase(change)");
511  }
512  if (!StdinReady()) {
513  fputs("Wallet passphrase> ", stderr);
514  fflush(stderr);
515  }
516  if (!std::getline(std::cin, walletPass)) {
517  throw std::runtime_error("-stdinwalletpassphrase specified but failed to read from standard input");
518  }
519  if (StdinTerminal()) {
520  fputc('\n', stdout);
521  }
522  args.insert(args.begin() + 1, walletPass);
523  }
524  if (gArgs.GetBoolArg("-stdin", false)) {
525  // Read one arg per line from stdin and append
526  std::string line;
527  while (std::getline(std::cin, line)) {
528  args.push_back(line);
529  }
530  if (StdinTerminal()) {
531  fputc('\n', stdout);
532  }
533  }
534  std::unique_ptr<BaseRequestHandler> rh;
535  std::string method;
536  if (gArgs.IsArgSet("-getinfo")) {
537  rh.reset(new GetinfoRequestHandler());
538  } else {
539  rh.reset(new DefaultRequestHandler());
540  if (args.size() < 1) {
541  throw std::runtime_error("too few parameters (need at least command)");
542  }
543  method = args[0];
544  args.erase(args.begin()); // Remove trailing method name from arguments vector
545  }
546  Optional<std::string> wallet_name{};
547  if (gArgs.IsArgSet("-rpcwallet")) wallet_name = gArgs.GetArg("-rpcwallet", "");
548  const UniValue reply = ConnectAndCallRPC(rh.get(), method, args, wallet_name);
549 
550  // Parse reply
551  UniValue result = find_value(reply, "result");
552  const UniValue& error = find_value(reply, "error");
553  if (!error.isNull()) {
554  // Error
555  strPrint = "error: " + error.write();
556  nRet = abs(error["code"].get_int());
557  if (error.isObject()) {
558  const UniValue& errCode = find_value(error, "code");
559  const UniValue& errMsg = find_value(error, "message");
560  strPrint = errCode.isNull() ? "" : ("error code: " + errCode.getValStr() + "\n");
561 
562  if (errMsg.isStr()) {
563  strPrint += ("error message:\n" + errMsg.get_str());
564  }
565  if (errCode.isNum() && errCode.get_int() == RPC_WALLET_NOT_SPECIFIED) {
566  strPrint += "\nTry adding \"-rpcwallet=<filename>\" option to bitcoin-cli command line.";
567  }
568  }
569  } else {
570  if (gArgs.IsArgSet("-getinfo") && !gArgs.IsArgSet("-rpcwallet")) {
571  GetWalletBalances(result); // fetch multiwallet balances and append to result
572  }
573  // Result
574  if (result.isNull()) {
575  strPrint = "";
576  } else if (result.isStr()) {
577  strPrint = result.get_str();
578  } else {
579  strPrint = result.write(2);
580  }
581  }
582  } catch (const std::exception& e) {
583  strPrint = std::string("error: ") + e.what();
584  nRet = EXIT_FAILURE;
585  } catch (...) {
586  PrintExceptionContinue(nullptr, "CommandLineRPC()");
587  throw;
588  }
589 
590  if (strPrint != "") {
591  tfm::format(nRet == 0 ? std::cout : std::cerr, "%s\n", strPrint);
592  }
593  return nRet;
594 }
595 
596 #ifdef WIN32
597 // Export main() and ensure working ASLR on Windows.
598 // Exporting a symbol will prevent the linker from stripping
599 // the .reloc section from the binary, which is a requirement
600 // for ASLR. This is a temporary workaround until a fixed
601 // version of binutils is used for releases.
602 __declspec(dllexport) int main(int argc, char* argv[])
603 {
604  util::WinCmdLineArgs winArgs;
605  std::tie(argc, argv) = winArgs.get();
606 #else
607 int main(int argc, char* argv[])
608 {
609 #endif
611  if (!SetupNetworking()) {
612  tfm::format(std::cerr, "Error: Initializing networking failed\n");
613  return EXIT_FAILURE;
614  }
615  event_set_log_callback(&libevent_log_cb);
616 
617  try {
618  int ret = AppInitRPC(argc, argv);
619  if (ret != CONTINUE_EXECUTION)
620  return ret;
621  }
622  catch (const std::exception& e) {
623  PrintExceptionContinue(&e, "AppInitRPC()");
624  return EXIT_FAILURE;
625  } catch (...) {
626  PrintExceptionContinue(nullptr, "AppInitRPC()");
627  return EXIT_FAILURE;
628  }
629 
630  int ret = EXIT_FAILURE;
631  try {
632  ret = CommandLineRPC(argc, argv);
633  }
634  catch (const std::exception& e) {
635  PrintExceptionContinue(&e, "CommandLineRPC()");
636  } catch (...) {
637  PrintExceptionContinue(nullptr, "CommandLineRPC()");
638  }
639  return ret;
640 }
NODISCARD bool ReadConfigFiles(std::string &error, bool ignore_invalid_keys=false)
Definition: system.cpp:744
No wallet specified (error when there are multiple wallets loaded)
Definition: protocol.h:80
bool isObject() const
Definition: univalue.h:84
bool StdinTerminal()
Definition: stdin.cpp:47
std::unique_ptr< CBaseChainParams > CreateBaseChainParams(const std::string &chain)
Creates and returns a std::unique_ptr<CBaseChainParams> of the chosen chain.
bool StdinReady()
Definition: stdin.cpp:56
bool IsArgSet(const std::string &strArg) const
Return true if the given argument has been manually set.
Definition: system.cpp:370
static int CommandLineRPC(int argc, char *argv[])
static UniValue ConnectAndCallRPC(BaseRequestHandler *rh, const std::string &strMethod, const std::vector< std::string > &args, const Optional< std::string > &rpcwallet={})
ConnectAndCallRPC wraps CallRPC with -rpcwait and an exception handler.
raii_event_base obtain_event_base()
Definition: events.h:30
const std::vector< UniValue > & getValues() const
static int AppInitRPC(int argc, char *argv[])
static void libevent_log_cb(int severity, const char *msg)
libevent event log callback
Definition: bitcoin-cli.cpp:70
static const std::string REGTEST
bool read(const char *raw, size_t len)
static std::string strRPCUserColonPass
Definition: httprpc.cpp:68
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
Definition: tinyformat.h:1164
UrlDecodeFn urlDecode
Definition: url.h:11
UniValue ProcessReply(const UniValue &reply) override
static UniValue CallRPC(BaseRequestHandler *rh, const std::string &strMethod, const std::vector< std::string > &args, const Optional< std::string > &rpcwallet={})
virtual ~BaseRequestHandler()
static const int DEFAULT_HTTP_CLIENT_TIMEOUT
Definition: bitcoin-cli.cpp:38
void SetupEnvironment()
Definition: system.cpp:1082
const CBaseChainParams & BaseParams()
Return the currently selected parameters.
#define PACKAGE_NAME
const std::string & get_str() const
bool isNum() const
Definition: univalue.h:82
raii_evhttp_request obtain_evhttp_request(void(*cb)(struct evhttp_request *, void *), void *arg)
Definition: events.h:45
NODISCARD bool ParseParameters(int argc, const char *const argv[], std::string &error)
Definition: system.cpp:283
bool isStr() const
Definition: univalue.h:81
static std::string http_errorstring(int code)
bool GetBoolArg(const std::string &strArg, bool fDefault) const
Return boolean argument or default value.
Definition: system.cpp:392
void ForceSetArg(const std::string &strArg, const std::string &strValue)
Definition: system.cpp:414
const char *const BITCOIN_CONF_FILENAME
Definition: system.cpp:75
bool SetupNetworking()
Definition: system.cpp:1119
const std::string & getValStr() const
Definition: univalue.h:65
Client still warming up.
Definition: protocol.h:49
#define NO_STDIN_ECHO()
Definition: stdin.h:13
virtual UniValue ProcessReply(const UniValue &batch_in)=0
UniValue PrepareRequest(const std::string &method, const std::vector< std::string > &args) override
Create a simulated getinfo request.
const UniValue & find_value(const UniValue &obj, const std::string &name)
Definition: univalue.cpp:234
std::string GetHelpMessage() const
Get the help string.
Definition: system.cpp:446
static const std::string MAIN
Chain name strings.
UniValue RPCConvertValues(const std::string &strMethod, const std::vector< std::string > &strParams)
Convert positional arguments to command-specific RPC representation.
Definition: client.cpp:224
bool CheckDataDirOption()
Definition: system.cpp:650
std::vector< UniValue > JSONRPCProcessBatchReply(const UniValue &in)
Parse JSON-RPC batch reply into a vector.
Definition: request.cpp:133
static const char DEFAULT_RPCCONNECT[]
Definition: bitcoin-cli.cpp:37
bool push_back(const UniValue &val)
Definition: univalue.cpp:108
static CAmount balance
static secp256k1_context * ctx
Definition: tests.c:46
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::string EncodeBase64(const unsigned char *pch, size_t len)
void AddArg(const std::string &name, const std::string &help, unsigned int flags, const OptionsCategory &cat)
Add argument.
Definition: system.cpp:420
bool HelpRequested(const ArgsManager &args)
Definition: system.cpp:515
#define EVENT_LOG_ERR
static const int CONTINUE_EXECUTION
Definition: bitcoin-cli.cpp:40
bool empty() const
Definition: univalue.h:66
virtual UniValue PrepareRequest(const std::string &method, const std::vector< std::string > &args)=0
raii_evhttp_connection obtain_evhttp_connection_base(struct event_base *base, std::string host, uint16_t port)
Definition: events.h:49
std::string write(unsigned int prettyIndent=0, unsigned int indentLevel=0) const
static void GetWalletBalances(UniValue &result)
GetWalletBalances calls listwallets; if more than one wallet is loaded, it then fetches mine...
bool pushKV(const std::string &key, const UniValue &val)
Definition: univalue.cpp:133
int get_int() const
void PrintExceptionContinue(const std::exception *pex, const char *pszThread)
Definition: system.cpp:557
int main(int argc, char *argv[])
UniValue ProcessReply(const UniValue &batch_in) override
Collect values from the batch and form a simulated getinfo reply.
bool isNull() const
Definition: univalue.h:77
Class that handles the conversion from a command-line to a JSON-RPC request, as well as converting ba...
std::string FormatFullVersion()
CConnectionFailed(const std::string &msg)
Definition: bitcoin-cli.cpp:94
int RPCPort() const
void SetupChainParamsBaseOptions()
Set the arguments for chainparams.
void UninterruptibleSleep(const std::chrono::microseconds &n)
Definition: time.cpp:19
fs::path GetConfigFile(const std::string &confPath)
Definition: system.cpp:665
const UniValue & get_obj() const
std::string GetArg(const std::string &strArg, const std::string &strDefault) const
Return string argument or default value.
Definition: system.cpp:380
UniValue JSONRPCReplyObj(const UniValue &result, const UniValue &error, const UniValue &id)
Definition: request.cpp:33
Process default single requests.
ArgsManager gArgs
Definition: system.cpp:77
const std::function< std::string(const char *)> G_TRANSLATION_FUN
Translate string to current locale using Qt.
Definition: bitcoin-cli.cpp:34
UniValue JSONRPCRequestObj(const std::string &strMethod, const UniValue &params, const UniValue &id)
JSON-RPC protocol.
Definition: request.cpp:24
void SetupHelpOptions(ArgsManager &args)
Add help options to the args manager.
Definition: system.cpp:520
static void SetupCliArgs()
Definition: bitcoin-cli.cpp:42
std::string body
const UniValue NullUniValue
Definition: univalue.cpp:13
UrlDecodeFn *const URL_DECODE
Definition: bitcoin-cli.cpp:35
UniValue RPCConvertNamedValues(const std::string &strMethod, const std::vector< std::string > &strParams)
Convert named arguments to command-specific RPC representation.
Definition: client.cpp:243
static const std::string TESTNET
static const bool DEFAULT_NAMED
Definition: bitcoin-cli.cpp:39
std::string GetChainName() const
Returns the appropriate chain name from the program arguments.
Definition: system.cpp:831
bool IsSwitchChar(char c)
Definition: system.h:109
UniValue PrepareRequest(const std::string &method, const std::vector< std::string > &args) override
size_t size() const
Definition: univalue.h:68
boost::optional< T > Optional
Substitute for C++17 std::optional.
Definition: optional.h:14
void SelectBaseParams(const std::string &chain)
Sets the params returned by Params() to those for the given network.
Process getinfo requests.
static UniValue listwallets(const JSONRPCRequest &request)
Definition: rpcwallet.cpp:2532
bool error(const char *fmt, const Args &... args)
Definition: system.h:49
bool GetAuthCookie(std::string *cookie_out)
Read the RPC authentication cookie from disk.
Definition: request.cpp:108
static void http_request_done(struct evhttp_request *req, void *ctx)
Reply structure for request_done to fill in.
std::string(const std::string &url_encoded) UrlDecodeFn
Definition: url.h:10
static UniValue getbalances(const JSONRPCRequest &request)
Definition: rpcwallet.cpp:2335
void SplitHostPort(std::string in, int &portOut, std::string &hostOut)