Merge #10953: [Refactor] Combine scriptPubKey and amount as CTxOut in CScriptCheck
[bitcoinplatinum.git] / src / bitcoin-cli.cpp
blob3c94c99b3e2c7039fc5b0fa46e4cbc6d6753ae79
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.
6 #if defined(HAVE_CONFIG_H)
7 #include "config/bitcoin-config.h"
8 #endif
10 #include "chainparamsbase.h"
11 #include "clientversion.h"
12 #include "fs.h"
13 #include "rpc/client.h"
14 #include "rpc/protocol.h"
15 #include "util.h"
16 #include "utilstrencodings.h"
18 #include <stdio.h>
20 #include <event2/buffer.h>
21 #include <event2/keyvalq_struct.h>
22 #include "support/events.h"
24 #include <univalue.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);
35 std::string strUsage;
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 AppendParamsHelpMessages(strUsage);
41 strUsage += HelpMessageOpt("-named", strprintf(_("Pass named instead of positional arguments (default: %s)"), DEFAULT_NAMED));
42 strUsage += HelpMessageOpt("-rpcconnect=<ip>", strprintf(_("Send commands to node running on <ip> (default: %s)"), DEFAULT_RPCCONNECT));
43 strUsage += HelpMessageOpt("-rpcport=<port>", strprintf(_("Connect to JSON-RPC on <port> (default: %u or testnet: %u)"), defaultBaseParams->RPCPort(), testnetBaseParams->RPCPort()));
44 strUsage += HelpMessageOpt("-rpcwait", _("Wait for RPC server to start"));
45 strUsage += HelpMessageOpt("-rpcuser=<user>", _("Username for JSON-RPC connections"));
46 strUsage += HelpMessageOpt("-rpcpassword=<pw>", _("Password for JSON-RPC connections"));
47 strUsage += HelpMessageOpt("-rpcclienttimeout=<n>", strprintf(_("Timeout in seconds during HTTP requests, or 0 for no timeout. (default: %d)"), DEFAULT_HTTP_CLIENT_TIMEOUT));
48 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.")));
49 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."));
50 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)"));
52 return strUsage;
55 //////////////////////////////////////////////////////////////////////////////
57 // Start
61 // Exception thrown on connection error. This error is used to determine
62 // when to wait if -rpcwait is given.
64 class CConnectionFailed : public std::runtime_error
66 public:
68 explicit inline CConnectionFailed(const std::string& msg) :
69 std::runtime_error(msg)
75 // This function returns either one of EXIT_ codes when it's expected to stop the process or
76 // CONTINUE_EXECUTION when it's expected to continue further.
78 static int AppInitRPC(int argc, char* argv[])
81 // Parameters
83 gArgs.ParseParameters(argc, argv);
84 if (argc<2 || gArgs.IsArgSet("-?") || gArgs.IsArgSet("-h") || gArgs.IsArgSet("-help") || gArgs.IsArgSet("-version")) {
85 std::string strUsage = strprintf(_("%s RPC client version"), _(PACKAGE_NAME)) + " " + FormatFullVersion() + "\n";
86 if (!gArgs.IsArgSet("-version")) {
87 strUsage += "\n" + _("Usage:") + "\n" +
88 " bitcoin-cli [options] <command> [params] " + strprintf(_("Send command to %s"), _(PACKAGE_NAME)) + "\n" +
89 " bitcoin-cli [options] -named <command> [name=value] ... " + strprintf(_("Send command to %s (with named arguments)"), _(PACKAGE_NAME)) + "\n" +
90 " bitcoin-cli [options] help " + _("List commands") + "\n" +
91 " bitcoin-cli [options] help <command> " + _("Get help for a command") + "\n";
93 strUsage += "\n" + HelpMessageCli();
96 fprintf(stdout, "%s", strUsage.c_str());
97 if (argc < 2) {
98 fprintf(stderr, "Error: too few parameters\n");
99 return EXIT_FAILURE;
101 return EXIT_SUCCESS;
103 if (!fs::is_directory(GetDataDir(false))) {
104 fprintf(stderr, "Error: Specified data directory \"%s\" does not exist.\n", gArgs.GetArg("-datadir", "").c_str());
105 return EXIT_FAILURE;
107 try {
108 gArgs.ReadConfigFile(gArgs.GetArg("-conf", BITCOIN_CONF_FILENAME));
109 } catch (const std::exception& e) {
110 fprintf(stderr,"Error reading configuration file: %s\n", e.what());
111 return EXIT_FAILURE;
113 // Check for -testnet or -regtest parameter (BaseParams() calls are only valid after this clause)
114 try {
115 SelectBaseParams(ChainNameFromCommandLine());
116 } catch (const std::exception& e) {
117 fprintf(stderr, "Error: %s\n", e.what());
118 return EXIT_FAILURE;
120 if (gArgs.GetBoolArg("-rpcssl", false))
122 fprintf(stderr, "Error: SSL mode for RPC (-rpcssl) is no longer supported.\n");
123 return EXIT_FAILURE;
125 return CONTINUE_EXECUTION;
129 /** Reply structure for request_done to fill in */
130 struct HTTPReply
132 HTTPReply(): status(0), error(-1) {}
134 int status;
135 int error;
136 std::string body;
139 const char *http_errorstring(int code)
141 switch(code) {
142 #if LIBEVENT_VERSION_NUMBER >= 0x02010300
143 case EVREQ_HTTP_TIMEOUT:
144 return "timeout reached";
145 case EVREQ_HTTP_EOF:
146 return "EOF reached";
147 case EVREQ_HTTP_INVALID_HEADER:
148 return "error while reading header, or invalid header";
149 case EVREQ_HTTP_BUFFER_ERROR:
150 return "error encountered while reading or writing";
151 case EVREQ_HTTP_REQUEST_CANCEL:
152 return "request was canceled";
153 case EVREQ_HTTP_DATA_TOO_LONG:
154 return "response body is larger than allowed";
155 #endif
156 default:
157 return "unknown";
161 static void http_request_done(struct evhttp_request *req, void *ctx)
163 HTTPReply *reply = static_cast<HTTPReply*>(ctx);
165 if (req == nullptr) {
166 /* If req is nullptr, it means an error occurred while connecting: the
167 * error code will have been passed to http_error_cb.
169 reply->status = 0;
170 return;
173 reply->status = evhttp_request_get_response_code(req);
175 struct evbuffer *buf = evhttp_request_get_input_buffer(req);
176 if (buf)
178 size_t size = evbuffer_get_length(buf);
179 const char *data = (const char*)evbuffer_pullup(buf, size);
180 if (data)
181 reply->body = std::string(data, size);
182 evbuffer_drain(buf, size);
186 #if LIBEVENT_VERSION_NUMBER >= 0x02010300
187 static void http_error_cb(enum evhttp_request_error err, void *ctx)
189 HTTPReply *reply = static_cast<HTTPReply*>(ctx);
190 reply->error = err;
192 #endif
194 static UniValue CallRPC(const std::string& strMethod, const UniValue& params)
196 std::string host;
197 // In preference order, we choose the following for the port:
198 // 1. -rpcport
199 // 2. port in -rpcconnect (ie following : in ipv4 or ]: in ipv6)
200 // 3. default port for chain
201 int port = BaseParams().RPCPort();
202 SplitHostPort(gArgs.GetArg("-rpcconnect", DEFAULT_RPCCONNECT), port, host);
203 port = gArgs.GetArg("-rpcport", port);
205 // Obtain event base
206 raii_event_base base = obtain_event_base();
208 // Synchronously look up hostname
209 raii_evhttp_connection evcon = obtain_evhttp_connection_base(base.get(), host, port);
210 evhttp_connection_set_timeout(evcon.get(), gArgs.GetArg("-rpcclienttimeout", DEFAULT_HTTP_CLIENT_TIMEOUT));
212 HTTPReply response;
213 raii_evhttp_request req = obtain_evhttp_request(http_request_done, (void*)&response);
214 if (req == nullptr)
215 throw std::runtime_error("create http request failed");
216 #if LIBEVENT_VERSION_NUMBER >= 0x02010300
217 evhttp_request_set_error_cb(req.get(), http_error_cb);
218 #endif
220 // Get credentials
221 std::string strRPCUserColonPass;
222 if (gArgs.GetArg("-rpcpassword", "") == "") {
223 // Try fall back to cookie-based authentication if no password is provided
224 if (!GetAuthCookie(&strRPCUserColonPass)) {
225 throw std::runtime_error(strprintf(
226 _("Could not locate RPC credentials. No authentication cookie could be found, and RPC password is not set. See -rpcpassword and -stdinrpcpass. Configuration file: (%s)"),
227 GetConfigFile(gArgs.GetArg("-conf", BITCOIN_CONF_FILENAME)).string().c_str()));
230 } else {
231 strRPCUserColonPass = gArgs.GetArg("-rpcuser", "") + ":" + gArgs.GetArg("-rpcpassword", "");
234 struct evkeyvalq* output_headers = evhttp_request_get_output_headers(req.get());
235 assert(output_headers);
236 evhttp_add_header(output_headers, "Host", host.c_str());
237 evhttp_add_header(output_headers, "Connection", "close");
238 evhttp_add_header(output_headers, "Authorization", (std::string("Basic ") + EncodeBase64(strRPCUserColonPass)).c_str());
240 // Attach request data
241 std::string strRequest = JSONRPCRequestObj(strMethod, params, 1).write() + "\n";
242 struct evbuffer* output_buffer = evhttp_request_get_output_buffer(req.get());
243 assert(output_buffer);
244 evbuffer_add(output_buffer, strRequest.data(), strRequest.size());
246 // check if we should use a special wallet endpoint
247 std::string endpoint = "/";
248 std::string walletName = gArgs.GetArg("-rpcwallet", "");
249 if (!walletName.empty()) {
250 char *encodedURI = evhttp_uriencode(walletName.c_str(), walletName.size(), false);
251 if (encodedURI) {
252 endpoint = "/wallet/"+ std::string(encodedURI);
253 free(encodedURI);
255 else {
256 throw CConnectionFailed("uri-encode failed");
259 int r = evhttp_make_request(evcon.get(), req.get(), EVHTTP_REQ_POST, endpoint.c_str());
260 req.release(); // ownership moved to evcon in above call
261 if (r != 0) {
262 throw CConnectionFailed("send http request failed");
265 event_base_dispatch(base.get());
267 if (response.status == 0)
268 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));
269 else if (response.status == HTTP_UNAUTHORIZED)
270 throw std::runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
271 else if (response.status >= 400 && response.status != HTTP_BAD_REQUEST && response.status != HTTP_NOT_FOUND && response.status != HTTP_INTERNAL_SERVER_ERROR)
272 throw std::runtime_error(strprintf("server returned HTTP error %d", response.status));
273 else if (response.body.empty())
274 throw std::runtime_error("no response from server");
276 // Parse reply
277 UniValue valReply(UniValue::VSTR);
278 if (!valReply.read(response.body))
279 throw std::runtime_error("couldn't parse reply from server");
280 const UniValue& reply = valReply.get_obj();
281 if (reply.empty())
282 throw std::runtime_error("expected reply to have result, error and id properties");
284 return reply;
287 int CommandLineRPC(int argc, char *argv[])
289 std::string strPrint;
290 int nRet = 0;
291 try {
292 // Skip switches
293 while (argc > 1 && IsSwitchChar(argv[1][0])) {
294 argc--;
295 argv++;
297 std::string rpcPass;
298 if (gArgs.GetBoolArg("-stdinrpcpass", false)) {
299 if (!std::getline(std::cin, rpcPass)) {
300 throw std::runtime_error("-stdinrpcpass specified but failed to read from standard input");
302 gArgs.ForceSetArg("-rpcpassword", rpcPass);
304 std::vector<std::string> args = std::vector<std::string>(&argv[1], &argv[argc]);
305 if (gArgs.GetBoolArg("-stdin", false)) {
306 // Read one arg per line from stdin and append
307 std::string line;
308 while (std::getline(std::cin, line)) {
309 args.push_back(line);
312 if (args.size() < 1) {
313 throw std::runtime_error("too few parameters (need at least command)");
315 std::string strMethod = args[0];
316 args.erase(args.begin()); // Remove trailing method name from arguments vector
318 UniValue params;
319 if(gArgs.GetBoolArg("-named", DEFAULT_NAMED)) {
320 params = RPCConvertNamedValues(strMethod, args);
321 } else {
322 params = RPCConvertValues(strMethod, args);
325 // Execute and handle connection failures with -rpcwait
326 const bool fWait = gArgs.GetBoolArg("-rpcwait", false);
327 do {
328 try {
329 const UniValue reply = CallRPC(strMethod, params);
331 // Parse reply
332 const UniValue& result = find_value(reply, "result");
333 const UniValue& error = find_value(reply, "error");
335 if (!error.isNull()) {
336 // Error
337 int code = error["code"].get_int();
338 if (fWait && code == RPC_IN_WARMUP)
339 throw CConnectionFailed("server in warmup");
340 strPrint = "error: " + error.write();
341 nRet = abs(code);
342 if (error.isObject())
344 UniValue errCode = find_value(error, "code");
345 UniValue errMsg = find_value(error, "message");
346 strPrint = errCode.isNull() ? "" : "error code: "+errCode.getValStr()+"\n";
348 if (errMsg.isStr())
349 strPrint += "error message:\n"+errMsg.get_str();
351 if (errCode.isNum() && errCode.get_int() == RPC_WALLET_NOT_SPECIFIED) {
352 strPrint += "\nTry adding \"-rpcwallet=<filename>\" option to bitcoin-cli command line.";
355 } else {
356 // Result
357 if (result.isNull())
358 strPrint = "";
359 else if (result.isStr())
360 strPrint = result.get_str();
361 else
362 strPrint = result.write(2);
364 // Connection succeeded, no need to retry.
365 break;
367 catch (const CConnectionFailed&) {
368 if (fWait)
369 MilliSleep(1000);
370 else
371 throw;
373 } while (fWait);
375 catch (const boost::thread_interrupted&) {
376 throw;
378 catch (const std::exception& e) {
379 strPrint = std::string("error: ") + e.what();
380 nRet = EXIT_FAILURE;
382 catch (...) {
383 PrintExceptionContinue(nullptr, "CommandLineRPC()");
384 throw;
387 if (strPrint != "") {
388 fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
390 return nRet;
393 int main(int argc, char* argv[])
395 SetupEnvironment();
396 if (!SetupNetworking()) {
397 fprintf(stderr, "Error: Initializing networking failed\n");
398 return EXIT_FAILURE;
401 try {
402 int ret = AppInitRPC(argc, argv);
403 if (ret != CONTINUE_EXECUTION)
404 return ret;
406 catch (const std::exception& e) {
407 PrintExceptionContinue(&e, "AppInitRPC()");
408 return EXIT_FAILURE;
409 } catch (...) {
410 PrintExceptionContinue(nullptr, "AppInitRPC()");
411 return EXIT_FAILURE;
414 int ret = EXIT_FAILURE;
415 try {
416 ret = CommandLineRPC(argc, argv);
418 catch (const std::exception& e) {
419 PrintExceptionContinue(&e, "CommandLineRPC()");
420 } catch (...) {
421 PrintExceptionContinue(nullptr, "CommandLineRPC()");
423 return ret;