1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2017 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.
6 #if defined(HAVE_CONFIG_H)
7 #include <config/bitcoin-config.h>
10 #include <chainparamsbase.h>
11 #include <clientversion.h>
13 #include <rpc/client.h>
14 #include <rpc/protocol.h>
16 #include <utilstrencodings.h>
20 #include <event2/buffer.h>
21 #include <event2/keyvalq_struct.h>
22 #include <support/events.h>
26 static const char DEFAULT_RPCCONNECT
[] = "127.0.0.1";
27 static const int DEFAULT_HTTP_CLIENT_TIMEOUT
=900;
28 static const bool DEFAULT_NAMED
=false;
29 static const int CONTINUE_EXECUTION
=-1;
31 std::string
HelpMessageCli()
33 const auto defaultBaseParams
= CreateBaseChainParams(CBaseChainParams::MAIN
);
34 const auto testnetBaseParams
= CreateBaseChainParams(CBaseChainParams::TESTNET
);
36 strUsage
+= HelpMessageGroup(_("Options:"));
37 strUsage
+= HelpMessageOpt("-?", _("This help message"));
38 strUsage
+= HelpMessageOpt("-conf=<file>", strprintf(_("Specify configuration file (default: %s)"), BITCOIN_CONF_FILENAME
));
39 strUsage
+= HelpMessageOpt("-datadir=<dir>", _("Specify data directory"));
40 strUsage
+= HelpMessageOpt("-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)"));
41 AppendParamsHelpMessages(strUsage
);
42 strUsage
+= HelpMessageOpt("-named", strprintf(_("Pass named instead of positional arguments (default: %s)"), DEFAULT_NAMED
));
43 strUsage
+= HelpMessageOpt("-rpcconnect=<ip>", strprintf(_("Send commands to node running on <ip> (default: %s)"), DEFAULT_RPCCONNECT
));
44 strUsage
+= HelpMessageOpt("-rpcport=<port>", strprintf(_("Connect to JSON-RPC on <port> (default: %u or testnet: %u)"), defaultBaseParams
->RPCPort(), testnetBaseParams
->RPCPort()));
45 strUsage
+= HelpMessageOpt("-rpcwait", _("Wait for RPC server to start"));
46 strUsage
+= HelpMessageOpt("-rpcuser=<user>", _("Username for JSON-RPC connections"));
47 strUsage
+= HelpMessageOpt("-rpcpassword=<pw>", _("Password for JSON-RPC connections"));
48 strUsage
+= HelpMessageOpt("-rpcclienttimeout=<n>", strprintf(_("Timeout in seconds during HTTP requests, or 0 for no timeout. (default: %d)"), DEFAULT_HTTP_CLIENT_TIMEOUT
));
49 strUsage
+= HelpMessageOpt("-stdinrpcpass", strprintf(_("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.")));
50 strUsage
+= HelpMessageOpt("-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."));
51 strUsage
+= HelpMessageOpt("-rpcwallet=<walletname>", _("Send RPC for non-default wallet on RPC server (argument is wallet filename in bitcoind directory, required if bitcoind/-Qt runs with multiple wallets)"));
56 //////////////////////////////////////////////////////////////////////////////
62 // Exception thrown on connection error. This error is used to determine
63 // when to wait if -rpcwait is given.
65 class CConnectionFailed
: public std::runtime_error
69 explicit inline CConnectionFailed(const std::string
& msg
) :
70 std::runtime_error(msg
)
76 // This function returns either one of EXIT_ codes when it's expected to stop the process or
77 // CONTINUE_EXECUTION when it's expected to continue further.
79 static int AppInitRPC(int argc
, char* argv
[])
84 gArgs
.ParseParameters(argc
, argv
);
85 if (argc
<2 || gArgs
.IsArgSet("-?") || gArgs
.IsArgSet("-h") || gArgs
.IsArgSet("-help") || gArgs
.IsArgSet("-version")) {
86 std::string strUsage
= strprintf(_("%s RPC client version"), _(PACKAGE_NAME
)) + " " + FormatFullVersion() + "\n";
87 if (!gArgs
.IsArgSet("-version")) {
88 strUsage
+= "\n" + _("Usage:") + "\n" +
89 " bitcoin-cli [options] <command> [params] " + strprintf(_("Send command to %s"), _(PACKAGE_NAME
)) + "\n" +
90 " bitcoin-cli [options] -named <command> [name=value] ... " + strprintf(_("Send command to %s (with named arguments)"), _(PACKAGE_NAME
)) + "\n" +
91 " bitcoin-cli [options] help " + _("List commands") + "\n" +
92 " bitcoin-cli [options] help <command> " + _("Get help for a command") + "\n";
94 strUsage
+= "\n" + HelpMessageCli();
97 fprintf(stdout
, "%s", strUsage
.c_str());
99 fprintf(stderr
, "Error: too few parameters\n");
104 if (!fs::is_directory(GetDataDir(false))) {
105 fprintf(stderr
, "Error: Specified data directory \"%s\" does not exist.\n", gArgs
.GetArg("-datadir", "").c_str());
109 gArgs
.ReadConfigFile(gArgs
.GetArg("-conf", BITCOIN_CONF_FILENAME
));
110 } catch (const std::exception
& e
) {
111 fprintf(stderr
,"Error reading configuration file: %s\n", e
.what());
114 // Check for -testnet or -regtest parameter (BaseParams() calls are only valid after this clause)
116 SelectBaseParams(ChainNameFromCommandLine());
117 } catch (const std::exception
& e
) {
118 fprintf(stderr
, "Error: %s\n", e
.what());
121 if (gArgs
.GetBoolArg("-rpcssl", false))
123 fprintf(stderr
, "Error: SSL mode for RPC (-rpcssl) is no longer supported.\n");
126 return CONTINUE_EXECUTION
;
130 /** Reply structure for request_done to fill in */
133 HTTPReply(): status(0), error(-1) {}
140 const char *http_errorstring(int code
)
143 #if LIBEVENT_VERSION_NUMBER >= 0x02010300
144 case EVREQ_HTTP_TIMEOUT
:
145 return "timeout reached";
147 return "EOF reached";
148 case EVREQ_HTTP_INVALID_HEADER
:
149 return "error while reading header, or invalid header";
150 case EVREQ_HTTP_BUFFER_ERROR
:
151 return "error encountered while reading or writing";
152 case EVREQ_HTTP_REQUEST_CANCEL
:
153 return "request was canceled";
154 case EVREQ_HTTP_DATA_TOO_LONG
:
155 return "response body is larger than allowed";
162 static void http_request_done(struct evhttp_request
*req
, void *ctx
)
164 HTTPReply
*reply
= static_cast<HTTPReply
*>(ctx
);
166 if (req
== nullptr) {
167 /* If req is nullptr, it means an error occurred while connecting: the
168 * error code will have been passed to http_error_cb.
174 reply
->status
= evhttp_request_get_response_code(req
);
176 struct evbuffer
*buf
= evhttp_request_get_input_buffer(req
);
179 size_t size
= evbuffer_get_length(buf
);
180 const char *data
= (const char*)evbuffer_pullup(buf
, size
);
182 reply
->body
= std::string(data
, size
);
183 evbuffer_drain(buf
, size
);
187 #if LIBEVENT_VERSION_NUMBER >= 0x02010300
188 static void http_error_cb(enum evhttp_request_error err
, void *ctx
)
190 HTTPReply
*reply
= static_cast<HTTPReply
*>(ctx
);
195 /** Class that handles the conversion from a command-line to a JSON-RPC request,
196 * as well as converting back to a JSON object that can be shown as result.
198 class BaseRequestHandler
201 virtual UniValue
PrepareRequest(const std::string
& method
, const std::vector
<std::string
>& args
) = 0;
202 virtual UniValue
ProcessReply(const UniValue
&batch_in
) = 0;
205 /** Process getinfo requests */
206 class GetinfoRequestHandler
: public BaseRequestHandler
209 const int ID_NETWORKINFO
= 0;
210 const int ID_BLOCKCHAININFO
= 1;
211 const int ID_WALLETINFO
= 2;
213 /** Create a simulated `getinfo` request. */
214 UniValue
PrepareRequest(const std::string
& method
, const std::vector
<std::string
>& args
) override
217 throw std::runtime_error("-getinfo takes no arguments");
219 UniValue
result(UniValue::VARR
);
220 result
.push_back(JSONRPCRequestObj("getnetworkinfo", NullUniValue
, ID_NETWORKINFO
));
221 result
.push_back(JSONRPCRequestObj("getblockchaininfo", NullUniValue
, ID_BLOCKCHAININFO
));
222 result
.push_back(JSONRPCRequestObj("getwalletinfo", NullUniValue
, ID_WALLETINFO
));
226 /** Collect values from the batch and form a simulated `getinfo` reply. */
227 UniValue
ProcessReply(const UniValue
&batch_in
) override
229 UniValue
result(UniValue::VOBJ
);
230 std::vector
<UniValue
> batch
= JSONRPCProcessBatchReply(batch_in
, 3);
231 // Errors in getnetworkinfo() and getblockchaininfo() are fatal, pass them on
232 // getwalletinfo() is allowed to fail in case there is no wallet.
233 if (!batch
[ID_NETWORKINFO
]["error"].isNull()) {
234 return batch
[ID_NETWORKINFO
];
236 if (!batch
[ID_BLOCKCHAININFO
]["error"].isNull()) {
237 return batch
[ID_BLOCKCHAININFO
];
239 result
.pushKV("version", batch
[ID_NETWORKINFO
]["result"]["version"]);
240 result
.pushKV("protocolversion", batch
[ID_NETWORKINFO
]["result"]["protocolversion"]);
241 if (!batch
[ID_WALLETINFO
].isNull()) {
242 result
.pushKV("walletversion", batch
[ID_WALLETINFO
]["result"]["walletversion"]);
243 result
.pushKV("balance", batch
[ID_WALLETINFO
]["result"]["balance"]);
245 result
.pushKV("blocks", batch
[ID_BLOCKCHAININFO
]["result"]["blocks"]);
246 result
.pushKV("timeoffset", batch
[ID_NETWORKINFO
]["result"]["timeoffset"]);
247 result
.pushKV("connections", batch
[ID_NETWORKINFO
]["result"]["connections"]);
248 result
.pushKV("proxy", batch
[ID_NETWORKINFO
]["result"]["networks"][0]["proxy"]);
249 result
.pushKV("difficulty", batch
[ID_BLOCKCHAININFO
]["result"]["difficulty"]);
250 result
.pushKV("testnet", UniValue(batch
[ID_BLOCKCHAININFO
]["result"]["chain"].get_str() == "test"));
251 if (!batch
[ID_WALLETINFO
].isNull()) {
252 result
.pushKV("walletversion", batch
[ID_WALLETINFO
]["result"]["walletversion"]);
253 result
.pushKV("balance", batch
[ID_WALLETINFO
]["result"]["balance"]);
254 result
.pushKV("keypoololdest", batch
[ID_WALLETINFO
]["result"]["keypoololdest"]);
255 result
.pushKV("keypoolsize", batch
[ID_WALLETINFO
]["result"]["keypoolsize"]);
256 if (!batch
[ID_WALLETINFO
]["result"]["unlocked_until"].isNull()) {
257 result
.pushKV("unlocked_until", batch
[ID_WALLETINFO
]["result"]["unlocked_until"]);
259 result
.pushKV("paytxfee", batch
[ID_WALLETINFO
]["result"]["paytxfee"]);
261 result
.pushKV("relayfee", batch
[ID_NETWORKINFO
]["result"]["relayfee"]);
262 result
.pushKV("warnings", batch
[ID_NETWORKINFO
]["result"]["warnings"]);
263 return JSONRPCReplyObj(result
, NullUniValue
, 1);
267 /** Process default single requests */
268 class DefaultRequestHandler
: public BaseRequestHandler
{
270 UniValue
PrepareRequest(const std::string
& method
, const std::vector
<std::string
>& args
) override
273 if(gArgs
.GetBoolArg("-named", DEFAULT_NAMED
)) {
274 params
= RPCConvertNamedValues(method
, args
);
276 params
= RPCConvertValues(method
, args
);
278 return JSONRPCRequestObj(method
, params
, 1);
281 UniValue
ProcessReply(const UniValue
&reply
) override
283 return reply
.get_obj();
287 static UniValue
CallRPC(BaseRequestHandler
*rh
, const std::string
& strMethod
, const std::vector
<std::string
>& args
)
290 // In preference order, we choose the following for the port:
292 // 2. port in -rpcconnect (ie following : in ipv4 or ]: in ipv6)
293 // 3. default port for chain
294 int port
= BaseParams().RPCPort();
295 SplitHostPort(gArgs
.GetArg("-rpcconnect", DEFAULT_RPCCONNECT
), port
, host
);
296 port
= gArgs
.GetArg("-rpcport", port
);
299 raii_event_base base
= obtain_event_base();
301 // Synchronously look up hostname
302 raii_evhttp_connection evcon
= obtain_evhttp_connection_base(base
.get(), host
, port
);
303 evhttp_connection_set_timeout(evcon
.get(), gArgs
.GetArg("-rpcclienttimeout", DEFAULT_HTTP_CLIENT_TIMEOUT
));
306 raii_evhttp_request req
= obtain_evhttp_request(http_request_done
, (void*)&response
);
308 throw std::runtime_error("create http request failed");
309 #if LIBEVENT_VERSION_NUMBER >= 0x02010300
310 evhttp_request_set_error_cb(req
.get(), http_error_cb
);
314 std::string strRPCUserColonPass
;
315 if (gArgs
.GetArg("-rpcpassword", "") == "") {
316 // Try fall back to cookie-based authentication if no password is provided
317 if (!GetAuthCookie(&strRPCUserColonPass
)) {
318 throw std::runtime_error(strprintf(
319 _("Could not locate RPC credentials. No authentication cookie could be found, and RPC password is not set. See -rpcpassword and -stdinrpcpass. Configuration file: (%s)"),
320 GetConfigFile(gArgs
.GetArg("-conf", BITCOIN_CONF_FILENAME
)).string().c_str()));
324 strRPCUserColonPass
= gArgs
.GetArg("-rpcuser", "") + ":" + gArgs
.GetArg("-rpcpassword", "");
327 struct evkeyvalq
* output_headers
= evhttp_request_get_output_headers(req
.get());
328 assert(output_headers
);
329 evhttp_add_header(output_headers
, "Host", host
.c_str());
330 evhttp_add_header(output_headers
, "Connection", "close");
331 evhttp_add_header(output_headers
, "Authorization", (std::string("Basic ") + EncodeBase64(strRPCUserColonPass
)).c_str());
333 // Attach request data
334 std::string strRequest
= rh
->PrepareRequest(strMethod
, args
).write() + "\n";
335 struct evbuffer
* output_buffer
= evhttp_request_get_output_buffer(req
.get());
336 assert(output_buffer
);
337 evbuffer_add(output_buffer
, strRequest
.data(), strRequest
.size());
339 // check if we should use a special wallet endpoint
340 std::string endpoint
= "/";
341 std::string walletName
= gArgs
.GetArg("-rpcwallet", "");
342 if (!walletName
.empty()) {
343 char *encodedURI
= evhttp_uriencode(walletName
.c_str(), walletName
.size(), false);
345 endpoint
= "/wallet/"+ std::string(encodedURI
);
349 throw CConnectionFailed("uri-encode failed");
352 int r
= evhttp_make_request(evcon
.get(), req
.get(), EVHTTP_REQ_POST
, endpoint
.c_str());
353 req
.release(); // ownership moved to evcon in above call
355 throw CConnectionFailed("send http request failed");
358 event_base_dispatch(base
.get());
360 if (response
.status
== 0)
361 throw CConnectionFailed(strprintf("couldn't connect to server: %s (code %d)\n(make sure server is running and you are connecting to the correct RPC port)", http_errorstring(response
.error
), response
.error
));
362 else if (response
.status
== HTTP_UNAUTHORIZED
)
363 throw std::runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
364 else if (response
.status
>= 400 && response
.status
!= HTTP_BAD_REQUEST
&& response
.status
!= HTTP_NOT_FOUND
&& response
.status
!= HTTP_INTERNAL_SERVER_ERROR
)
365 throw std::runtime_error(strprintf("server returned HTTP error %d", response
.status
));
366 else if (response
.body
.empty())
367 throw std::runtime_error("no response from server");
370 UniValue
valReply(UniValue::VSTR
);
371 if (!valReply
.read(response
.body
))
372 throw std::runtime_error("couldn't parse reply from server");
373 const UniValue reply
= rh
->ProcessReply(valReply
);
375 throw std::runtime_error("expected reply to have result, error and id properties");
380 int CommandLineRPC(int argc
, char *argv
[])
382 std::string strPrint
;
386 while (argc
> 1 && IsSwitchChar(argv
[1][0])) {
391 if (gArgs
.GetBoolArg("-stdinrpcpass", false)) {
392 if (!std::getline(std::cin
, rpcPass
)) {
393 throw std::runtime_error("-stdinrpcpass specified but failed to read from standard input");
395 gArgs
.ForceSetArg("-rpcpassword", rpcPass
);
397 std::vector
<std::string
> args
= std::vector
<std::string
>(&argv
[1], &argv
[argc
]);
398 if (gArgs
.GetBoolArg("-stdin", false)) {
399 // Read one arg per line from stdin and append
401 while (std::getline(std::cin
, line
)) {
402 args
.push_back(line
);
405 std::unique_ptr
<BaseRequestHandler
> rh
;
407 if (gArgs
.GetBoolArg("-getinfo", false)) {
408 rh
.reset(new GetinfoRequestHandler());
411 rh
.reset(new DefaultRequestHandler());
412 if (args
.size() < 1) {
413 throw std::runtime_error("too few parameters (need at least command)");
416 args
.erase(args
.begin()); // Remove trailing method name from arguments vector
419 // Execute and handle connection failures with -rpcwait
420 const bool fWait
= gArgs
.GetBoolArg("-rpcwait", false);
423 const UniValue reply
= CallRPC(rh
.get(), method
, args
);
426 const UniValue
& result
= find_value(reply
, "result");
427 const UniValue
& error
= find_value(reply
, "error");
429 if (!error
.isNull()) {
431 int code
= error
["code"].get_int();
432 if (fWait
&& code
== RPC_IN_WARMUP
)
433 throw CConnectionFailed("server in warmup");
434 strPrint
= "error: " + error
.write();
436 if (error
.isObject())
438 UniValue errCode
= find_value(error
, "code");
439 UniValue errMsg
= find_value(error
, "message");
440 strPrint
= errCode
.isNull() ? "" : "error code: "+errCode
.getValStr()+"\n";
443 strPrint
+= "error message:\n"+errMsg
.get_str();
445 if (errCode
.isNum() && errCode
.get_int() == RPC_WALLET_NOT_SPECIFIED
) {
446 strPrint
+= "\nTry adding \"-rpcwallet=<filename>\" option to bitcoin-cli command line.";
453 else if (result
.isStr())
454 strPrint
= result
.get_str();
456 strPrint
= result
.write(2);
458 // Connection succeeded, no need to retry.
461 catch (const CConnectionFailed
&) {
469 catch (const boost::thread_interrupted
&) {
472 catch (const std::exception
& e
) {
473 strPrint
= std::string("error: ") + e
.what();
477 PrintExceptionContinue(nullptr, "CommandLineRPC()");
481 if (strPrint
!= "") {
482 fprintf((nRet
== 0 ? stdout
: stderr
), "%s\n", strPrint
.c_str());
487 int main(int argc
, char* argv
[])
490 if (!SetupNetworking()) {
491 fprintf(stderr
, "Error: Initializing networking failed\n");
496 int ret
= AppInitRPC(argc
, argv
);
497 if (ret
!= CONTINUE_EXECUTION
)
500 catch (const std::exception
& e
) {
501 PrintExceptionContinue(&e
, "AppInitRPC()");
504 PrintExceptionContinue(nullptr, "AppInitRPC()");
508 int ret
= EXIT_FAILURE
;
510 ret
= CommandLineRPC(argc
, argv
);
512 catch (const std::exception
& e
) {
513 PrintExceptionContinue(&e
, "CommandLineRPC()");
515 PrintExceptionContinue(nullptr, "CommandLineRPC()");