]> Git Repo - VerusCoin.git/blame - src/bitcoin-cli.cpp
Auto merge of #2259 - nathan-at-least:simplify-joinsplit-priority2, r=ebfull
[VerusCoin.git] / src / bitcoin-cli.cpp
CommitLineData
2a03a390 1// Copyright (c) 2009-2010 Satoshi Nakamoto
f914f1a7 2// Copyright (c) 2009-2013 The Bitcoin Core developers
78253fcb 3// Distributed under the MIT software license, see the accompanying
2a03a390
WL
4// file COPYING or http://www.opensource.org/licenses/mit-license.php.
5
611116d4 6#include "chainparamsbase.h"
71697f97 7#include "clientversion.h"
fb78cc23 8#include "rpcclient.h"
a7199038 9#include "rpcprotocol.h"
611116d4 10#include "util.h"
ad49c256 11#include "utilstrencodings.h"
2a03a390 12
51ed9ec9 13#include <boost/filesystem/operations.hpp>
afd64f76
WL
14#include <stdio.h>
15
afd64f76
WL
16#include <event2/buffer.h>
17#include <event2/keyvalq_struct.h>
68377e18 18#include "support/events.h"
51ed9ec9 19
a10a6e2a 20#include <univalue.h>
d014114d 21
09eb201b 22using namespace std;
b750cf1f 23
89bccddc
WL
24static const int DEFAULT_HTTP_CLIENT_TIMEOUT=900;
25
b750cf1f
WL
26std::string HelpMessageCli()
27{
28 string strUsage;
1fdb9fa3
LV
29 strUsage += HelpMessageGroup(_("Options:"));
30 strUsage += HelpMessageOpt("-?", _("This help message"));
aaf64959 31 strUsage += HelpMessageOpt("-conf=<file>", strprintf(_("Specify configuration file (default: %s)"), "zcash.conf"));
1fdb9fa3
LV
32 strUsage += HelpMessageOpt("-datadir=<dir>", _("Specify data directory"));
33 strUsage += HelpMessageOpt("-testnet", _("Use the test network"));
34 strUsage += HelpMessageOpt("-regtest", _("Enter regression test mode, which uses a special chain in which blocks can be "
35 "solved instantly. This is intended for regression testing tools and app development."));
36 strUsage += HelpMessageOpt("-rpcconnect=<ip>", strprintf(_("Send commands to node running on <ip> (default: %s)"), "127.0.0.1"));
3985a40d 37 strUsage += HelpMessageOpt("-rpcport=<port>", strprintf(_("Connect to JSON-RPC on <port> (default: %u or testnet: %u)"), 8232, 18232));
1fdb9fa3
LV
38 strUsage += HelpMessageOpt("-rpcwait", _("Wait for RPC server to start"));
39 strUsage += HelpMessageOpt("-rpcuser=<user>", _("Username for JSON-RPC connections"));
40 strUsage += HelpMessageOpt("-rpcpassword=<pw>", _("Password for JSON-RPC connections"));
629a8752 41 strUsage += HelpMessageOpt("-rpcclienttimeout=<n>", strprintf(_("Timeout in seconds during HTTP requests, or 0 for no timeout. (default: %d)"), DEFAULT_HTTP_CLIENT_TIMEOUT));
b750cf1f 42
b750cf1f
WL
43 return strUsage;
44}
45
2a03a390
WL
46//////////////////////////////////////////////////////////////////////////////
47//
48// Start
49//
af82884a
DK
50
51//
52// Exception thrown on connection error. This error is used to determine
53// when to wait if -rpcwait is given.
54//
55class CConnectionFailed : public std::runtime_error
56{
57public:
58
59 explicit inline CConnectionFailed(const std::string& msg) :
60 std::runtime_error(msg)
61 {}
62
63};
64
2a03a390
WL
65static bool AppInitRPC(int argc, char* argv[])
66{
67 //
68 // Parameters
69 //
70 ParseParameters(argc, argv);
af6edac0 71 if (argc<2 || mapArgs.count("-?") || mapArgs.count("-h") || mapArgs.count("-help") || mapArgs.count("-version")) {
f0d1accb 72 std::string strUsage = _("Zcash RPC client version") + " " + FormatFullVersion() + "\n" + PrivacyInfo();
3d0a1ce1
PJ
73 if (!mapArgs.count("-version")) {
74 strUsage += "\n" + _("Usage:") + "\n" +
a1de76c7
JG
75 " zcash-cli [options] <command> [params] " + _("Send command to Zcash") + "\n" +
76 " zcash-cli [options] help " + _("List commands") + "\n" +
77 " zcash-cli [options] help <command> " + _("Get help for a command") + "\n";
3d0a1ce1
PJ
78
79 strUsage += "\n" + HelpMessageCli();
af021144
S
80 } else {
81 strUsage += LicenseInfo();
3d0a1ce1
PJ
82 }
83
84 fprintf(stdout, "%s", strUsage.c_str());
85 return false;
86 }
3ce7e669 87 if (!boost::filesystem::is_directory(GetDataDir(false))) {
2a03a390
WL
88 fprintf(stderr, "Error: Specified data directory \"%s\" does not exist.\n", mapArgs["-datadir"].c_str());
89 return false;
90 }
4ae5e721
WL
91 try {
92 ReadConfigFile(mapArgs, mapMultiArgs);
27df4123 93 } catch (const std::exception& e) {
4ae5e721
WL
94 fprintf(stderr,"Error reading configuration file: %s\n", e.what());
95 return false;
96 }
84ce18ca
WL
97 // Check for -testnet or -regtest parameter (BaseParams() calls are only valid after this clause)
98 if (!SelectBaseParamsFromCommandLine()) {
9d2b73d1
WL
99 fprintf(stderr, "Error: Invalid combination of -regtest and -testnet.\n");
100 return false;
101 }
afd64f76
WL
102 if (GetBoolArg("-rpcssl", false))
103 {
104 fprintf(stderr, "Error: SSL mode for RPC (-rpcssl) is no longer supported.\n");
105 return false;
106 }
2a03a390
WL
107 return true;
108}
109
afd64f76
WL
110
111/** Reply structure for request_done to fill in */
112struct HTTPReply
b750cf1f 113{
6415573a
WL
114 HTTPReply(): status(0), error(-1) {}
115
afd64f76 116 int status;
6415573a 117 int error;
afd64f76
WL
118 std::string body;
119};
120
6415573a
WL
121const char *http_errorstring(int code)
122{
123 switch(code) {
124#if LIBEVENT_VERSION_NUMBER >= 0x02010300
125 case EVREQ_HTTP_TIMEOUT:
126 return "timeout reached";
127 case EVREQ_HTTP_EOF:
128 return "EOF reached";
129 case EVREQ_HTTP_INVALID_HEADER:
130 return "error while reading header, or invalid header";
131 case EVREQ_HTTP_BUFFER_ERROR:
132 return "error encountered while reading or writing";
133 case EVREQ_HTTP_REQUEST_CANCEL:
134 return "request was canceled";
135 case EVREQ_HTTP_DATA_TOO_LONG:
136 return "response body is larger than allowed";
137#endif
138 default:
139 return "unknown";
140 }
141}
142
afd64f76
WL
143static void http_request_done(struct evhttp_request *req, void *ctx)
144{
145 HTTPReply *reply = static_cast<HTTPReply*>(ctx);
146
147 if (req == NULL) {
6415573a
WL
148 /* If req is NULL, it means an error occurred while connecting: the
149 * error code will have been passed to http_error_cb.
afd64f76
WL
150 */
151 reply->status = 0;
152 return;
153 }
b750cf1f 154
afd64f76
WL
155 reply->status = evhttp_request_get_response_code(req);
156
157 struct evbuffer *buf = evhttp_request_get_input_buffer(req);
158 if (buf)
159 {
160 size_t size = evbuffer_get_length(buf);
161 const char *data = (const char*)evbuffer_pullup(buf, size);
162 if (data)
163 reply->body = std::string(data, size);
164 evbuffer_drain(buf, size);
165 }
166}
167
6415573a
WL
168#if LIBEVENT_VERSION_NUMBER >= 0x02010300
169static void http_error_cb(enum evhttp_request_error err, void *ctx)
170{
171 HTTPReply *reply = static_cast<HTTPReply*>(ctx);
172 reply->error = err;
173}
174#endif
175
afd64f76
WL
176UniValue CallRPC(const string& strMethod, const UniValue& params)
177{
178 std::string host = GetArg("-rpcconnect", "127.0.0.1");
179 int port = GetArg("-rpcport", BaseParams().RPCPort());
180
68377e18
KJA
181 // Obtain event base
182 raii_event_base base = obtain_event_base();
afd64f76
WL
183
184 // Synchronously look up hostname
68377e18
KJA
185 raii_evhttp_connection evcon = obtain_evhttp_connection_base(base.get(), host, port);
186 evhttp_connection_set_timeout(evcon.get(), GetArg("-rpcclienttimeout", DEFAULT_HTTP_CLIENT_TIMEOUT));
afd64f76
WL
187
188 HTTPReply response;
68377e18 189 raii_evhttp_request req = obtain_evhttp_request(http_request_done, (void*)&response);
afd64f76
WL
190 if (req == NULL)
191 throw runtime_error("create http request failed");
6415573a 192#if LIBEVENT_VERSION_NUMBER >= 0x02010300
68377e18 193 evhttp_request_set_error_cb(req.get(), http_error_cb);
6415573a 194#endif
afd64f76
WL
195
196 // Get credentials
e957192c
WL
197 std::string strRPCUserColonPass;
198 if (mapArgs["-rpcpassword"] == "") {
199 // Try fall back to cookie-based authentication if no password is provided
200 if (!GetAuthCookie(&strRPCUserColonPass)) {
201 throw runtime_error(strprintf(
206e2b97
JG
202 _("Could not locate RPC credentials. No authentication cookie could be found,\n"
203 "and no rpcpassword is set in the configuration file (%s)."),
e957192c
WL
204 GetConfigFile().string().c_str()));
205
206 }
207 } else {
208 strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"];
209 }
210
68377e18 211 struct evkeyvalq* output_headers = evhttp_request_get_output_headers(req.get());
afd64f76
WL
212 assert(output_headers);
213 evhttp_add_header(output_headers, "Host", host.c_str());
214 evhttp_add_header(output_headers, "Connection", "close");
215 evhttp_add_header(output_headers, "Authorization", (std::string("Basic ") + EncodeBase64(strRPCUserColonPass)).c_str());
216
217 // Attach request data
218 std::string strRequest = JSONRPCRequest(strMethod, params, 1);
68377e18 219 struct evbuffer* output_buffer = evhttp_request_get_output_buffer(req.get());
afd64f76
WL
220 assert(output_buffer);
221 evbuffer_add(output_buffer, strRequest.data(), strRequest.size());
222
68377e18
KJA
223 int r = evhttp_make_request(evcon.get(), req.get(), EVHTTP_REQ_POST, "/");
224 req.release(); // ownership moved to evcon in above call
afd64f76 225 if (r != 0) {
afd64f76
WL
226 throw CConnectionFailed("send http request failed");
227 }
b750cf1f 228
68377e18 229 event_base_dispatch(base.get());
b750cf1f 230
afd64f76 231 if (response.status == 0)
7c2ab059 232 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));
afd64f76 233 else if (response.status == HTTP_UNAUTHORIZED)
b750cf1f 234 throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
afd64f76
WL
235 else if (response.status >= 400 && response.status != HTTP_BAD_REQUEST && response.status != HTTP_NOT_FOUND && response.status != HTTP_INTERNAL_SERVER_ERROR)
236 throw runtime_error(strprintf("server returned HTTP error %d", response.status));
237 else if (response.body.empty())
b750cf1f
WL
238 throw runtime_error("no response from server");
239
240 // Parse reply
851f58f9 241 UniValue valReply(UniValue::VSTR);
afd64f76 242 if (!valReply.read(response.body))
b750cf1f 243 throw runtime_error("couldn't parse reply from server");
d014114d 244 const UniValue& reply = valReply.get_obj();
b750cf1f
WL
245 if (reply.empty())
246 throw runtime_error("expected reply to have result, error and id properties");
247
248 return reply;
249}
250
251int CommandLineRPC(int argc, char *argv[])
252{
253 string strPrint;
254 int nRet = 0;
3ce7e669 255 try {
b750cf1f 256 // Skip switches
3ce7e669 257 while (argc > 1 && IsSwitchChar(argv[1][0])) {
b750cf1f
WL
258 argc--;
259 argv++;
260 }
261
262 // Method
263 if (argc < 2)
264 throw runtime_error("too few parameters");
265 string strMethod = argv[1];
266
267 // Parameters default to strings
268 std::vector<std::string> strParams(&argv[2], &argv[argc]);
851f58f9 269 UniValue params = RPCConvertValues(strMethod, strParams);
b750cf1f 270
af82884a
DK
271 // Execute and handle connection failures with -rpcwait
272 const bool fWait = GetBoolArg("-rpcwait", false);
273 do {
274 try {
851f58f9 275 const UniValue reply = CallRPC(strMethod, params);
af82884a
DK
276
277 // Parse reply
d014114d
JS
278 const UniValue& result = find_value(reply, "result");
279 const UniValue& error = find_value(reply, "error");
af82884a 280
ed21d5bd 281 if (!error.isNull()) {
af82884a 282 // Error
ed21d5bd 283 int code = error["code"].get_int();
d014114d
JS
284 if (fWait && code == RPC_IN_WARMUP)
285 throw CConnectionFailed("server in warmup");
286 strPrint = "error: " + error.write();
af82884a 287 nRet = abs(code);
f061578b
JS
288 if (error.isObject())
289 {
290 UniValue errCode = find_value(error, "code");
291 UniValue errMsg = find_value(error, "message");
292 strPrint = errCode.isNull() ? "" : "error code: "+errCode.getValStr()+"\n";
293
294 if (errMsg.isStr())
295 strPrint += "error message:\n"+errMsg.get_str();
296 }
af82884a
DK
297 } else {
298 // Result
ed21d5bd 299 if (result.isNull())
af82884a 300 strPrint = "";
ed21d5bd 301 else if (result.isStr())
af82884a
DK
302 strPrint = result.get_str();
303 else
ed21d5bd 304 strPrint = result.write(2);
af82884a 305 }
af82884a
DK
306 // Connection succeeded, no need to retry.
307 break;
308 }
27df4123 309 catch (const CConnectionFailed&) {
af82884a
DK
310 if (fWait)
311 MilliSleep(1000);
312 else
313 throw;
314 }
315 } while (fWait);
b750cf1f 316 }
27df4123 317 catch (const boost::thread_interrupted&) {
b750cf1f
WL
318 throw;
319 }
27df4123 320 catch (const std::exception& e) {
b750cf1f
WL
321 strPrint = string("error: ") + e.what();
322 nRet = EXIT_FAILURE;
323 }
324 catch (...) {
325 PrintExceptionContinue(NULL, "CommandLineRPC()");
326 throw;
327 }
328
3ce7e669 329 if (strPrint != "") {
b750cf1f
WL
330 fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
331 }
332 return nRet;
333}
334
2a03a390
WL
335int main(int argc, char* argv[])
336{
5248ff40 337 SetupEnvironment();
167b6231
WL
338 if (!SetupNetworking()) {
339 fprintf(stderr, "Error: Initializing networking failed\n");
340 exit(1);
341 }
5248ff40 342
3ce7e669 343 try {
2a03a390 344 if(!AppInitRPC(argc, argv))
0cafb630 345 return EXIT_FAILURE;
2a03a390 346 }
27df4123 347 catch (const std::exception& e) {
2a03a390 348 PrintExceptionContinue(&e, "AppInitRPC()");
0cafb630 349 return EXIT_FAILURE;
2a03a390
WL
350 } catch (...) {
351 PrintExceptionContinue(NULL, "AppInitRPC()");
0cafb630 352 return EXIT_FAILURE;
2a03a390
WL
353 }
354
0cafb630 355 int ret = EXIT_FAILURE;
3ce7e669 356 try {
a7199038 357 ret = CommandLineRPC(argc, argv);
2a03a390 358 }
27df4123 359 catch (const std::exception& e) {
2a03a390
WL
360 PrintExceptionContinue(&e, "CommandLineRPC()");
361 } catch (...) {
362 PrintExceptionContinue(NULL, "CommandLineRPC()");
363 }
a7199038 364 return ret;
2a03a390 365}
This page took 0.199962 seconds and 4 git commands to generate.