]> Git Repo - VerusCoin.git/blame - src/bitcoin-cli.cpp
Ability to define, list, start and connect to PBaaS chains
[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"
4519a766
DC
8#include "rpc/client.h"
9#include "rpc/protocol.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>
51ed9ec9 21
09eb201b 22using namespace std;
6e9f40ca 23
89bccddc 24static const int DEFAULT_HTTP_CLIENT_TIMEOUT=900;
fadbbe1e 25static const int CONTINUE_EXECUTION=-1;
89bccddc 26
b750cf1f
WL
27std::string HelpMessageCli()
28{
3b26f5c3 29 std::string strUsage;
1fdb9fa3
LV
30 strUsage += HelpMessageGroup(_("Options:"));
31 strUsage += HelpMessageOpt("-?", _("This help message"));
5166804f 32 strUsage += HelpMessageOpt("-conf=<file>", strprintf(_("Specify configuration file (default: %s)"), "komodo.conf"));
1fdb9fa3
LV
33 strUsage += HelpMessageOpt("-datadir=<dir>", _("Specify data directory"));
34 strUsage += HelpMessageOpt("-testnet", _("Use the test network"));
35 strUsage += HelpMessageOpt("-regtest", _("Enter regression test mode, which uses a special chain in which blocks can be "
36 "solved instantly. This is intended for regression testing tools and app development."));
37 strUsage += HelpMessageOpt("-rpcconnect=<ip>", strprintf(_("Send commands to node running on <ip> (default: %s)"), "127.0.0.1"));
3985a40d 38 strUsage += HelpMessageOpt("-rpcport=<port>", strprintf(_("Connect to JSON-RPC on <port> (default: %u or testnet: %u)"), 8232, 18232));
1fdb9fa3
LV
39 strUsage += HelpMessageOpt("-rpcwait", _("Wait for RPC server to start"));
40 strUsage += HelpMessageOpt("-rpcuser=<user>", _("Username for JSON-RPC connections"));
41 strUsage += HelpMessageOpt("-rpcpassword=<pw>", _("Password for JSON-RPC connections"));
629a8752 42 strUsage += HelpMessageOpt("-rpcclienttimeout=<n>", strprintf(_("Timeout in seconds during HTTP requests, or 0 for no timeout. (default: %d)"), DEFAULT_HTTP_CLIENT_TIMEOUT));
21e33231 43 strUsage += HelpMessageOpt("-stdin", _("Read extra arguments from standard input, one per line until EOF/Ctrl-D (recommended for sensitive information such as passphrases)"));
b750cf1f
WL
44
45 return strUsage;
46}
47
2a03a390
WL
48//////////////////////////////////////////////////////////////////////////////
49//
50// Start
51//
af82884a
DK
52
53//
54// Exception thrown on connection error. This error is used to determine
55// when to wait if -rpcwait is given.
56//
57class CConnectionFailed : public std::runtime_error
58{
59public:
60
61 explicit inline CConnectionFailed(const std::string& msg) :
62 std::runtime_error(msg)
63 {}
64
65};
66
95c46396 67#define FROM_CLI
d73f0799 68#include "uint256.h"
ba381f65 69#include "arith_uint256.h"
39eb0ec7 70
3face669 71#include "komodo_structs.h"
3824fe8c 72
98f2e433 73#include "komodo_globals.h"
6dede29e 74#include "komodo_utils.h"
d430a5e8 75#include "komodo_cJSON.c"
0e2400aa 76#include "komodo_notary.h"
9a2f3a40 77
f8f61a6d 78int32_t uni_get_int(UniValue uv, int32_t def)
79{
80 try
81 {
82 return uv.get_int();
83 }
84 catch(const std::exception& e)
85 {
86 return def;
87 }
88}
89
90int64_t uni_get_int64(UniValue uv, int64_t def)
91{
92 try
93 {
94 return uv.get_int64();
95 }
96 catch(const std::exception& e)
97 {
98 return def;
99 }
100}
101
102std::string uni_get_str(UniValue uv, std::string def)
103{
104 try
105 {
106 return uv.get_str();
107 }
108 catch(const std::exception& e)
109 {
110 return def;
111 }
112}
113
114std::vector<UniValue> uni_getValues(UniValue uv, std::vector<UniValue> def)
115{
116 try
117 {
118 return uv.getValues();
119 }
120 catch(const std::exception& e)
121 {
122 return def;
123 }
124}
125
c88fa588 126void komodo_stateupdate(int32_t height,uint8_t notarypubs[][33],uint8_t numnotaries,uint8_t notaryid,uint256 txhash,uint64_t voutmask,uint8_t numvouts,uint32_t *pvals,uint8_t numpvals,int32_t KMDheight,uint32_t KMDtimestamp,uint64_t opretvalue,uint8_t *opretbuf,uint16_t opretlen,uint16_t vout,uint256 MoM,int32_t MoMdepth)
725800f9 127{
128
129}
130
6e1d2e7d 131uint32_t komodo_heightstamp(int32_t height)
132{
133 return(0);
134}
135
fadbbe1e
U
136//
137// This function returns either one of EXIT_ codes when it's expected to stop the process or
138// CONTINUE_EXECUTION when it's expected to continue further.
139//
140static int AppInitRPC(int argc, char* argv[])
2a03a390 141{
abf5dd31
JG
142 static_assert(CONTINUE_EXECUTION != EXIT_FAILURE,
143 "CONTINUE_EXECUTION should be different from EXIT_FAILURE");
144 static_assert(CONTINUE_EXECUTION != EXIT_SUCCESS,
145 "CONTINUE_EXECUTION should be different from EXIT_SUCCESS");
2a03a390
WL
146 //
147 // Parameters
148 //
149 ParseParameters(argc, argv);
59d405e8 150 komodo_args(argv[0]);
af6edac0 151 if (argc<2 || mapArgs.count("-?") || mapArgs.count("-h") || mapArgs.count("-help") || mapArgs.count("-version")) {
945f015d 152 std::string strUsage = _("Komodo RPC client version") + " " + FormatFullVersion() + "\n" + PrivacyInfo();
3d0a1ce1
PJ
153 if (!mapArgs.count("-version")) {
154 strUsage += "\n" + _("Usage:") + "\n" +
5166804f 155 " komodo-cli [options] <command> [params] " + _("Send command to Komodo") + "\n" +
156 " komodo-cli [options] help " + _("List commands") + "\n" +
157 " komodo-cli [options] help <command> " + _("Get help for a command") + "\n";
3d0a1ce1
PJ
158
159 strUsage += "\n" + HelpMessageCli();
af021144
S
160 } else {
161 strUsage += LicenseInfo();
3d0a1ce1
PJ
162 }
163
164 fprintf(stdout, "%s", strUsage.c_str());
fadbbe1e
U
165 if (argc < 2) {
166 fprintf(stderr, "Error: too few parameters\n");
167 return EXIT_FAILURE;
168 }
169 return EXIT_SUCCESS;
3d0a1ce1 170 }
3ce7e669 171 if (!boost::filesystem::is_directory(GetDataDir(false))) {
2a03a390 172 fprintf(stderr, "Error: Specified data directory \"%s\" does not exist.\n", mapArgs["-datadir"].c_str());
fadbbe1e 173 return EXIT_FAILURE;
2a03a390 174 }
4ae5e721
WL
175 try {
176 ReadConfigFile(mapArgs, mapMultiArgs);
27df4123 177 } catch (const std::exception& e) {
4ae5e721 178 fprintf(stderr,"Error reading configuration file: %s\n", e.what());
fadbbe1e 179 return EXIT_FAILURE;
4ae5e721 180 }
84ce18ca
WL
181 // Check for -testnet or -regtest parameter (BaseParams() calls are only valid after this clause)
182 if (!SelectBaseParamsFromCommandLine()) {
9d2b73d1 183 fprintf(stderr, "Error: Invalid combination of -regtest and -testnet.\n");
fadbbe1e 184 return EXIT_FAILURE;
9d2b73d1 185 }
afd64f76
WL
186 if (GetBoolArg("-rpcssl", false))
187 {
188 fprintf(stderr, "Error: SSL mode for RPC (-rpcssl) is no longer supported.\n");
fadbbe1e 189 return EXIT_FAILURE;
afd64f76 190 }
fadbbe1e 191 return CONTINUE_EXECUTION;
2a03a390
WL
192}
193
afd64f76
WL
194
195/** Reply structure for request_done to fill in */
196struct HTTPReply
b750cf1f 197{
6415573a
WL
198 HTTPReply(): status(0), error(-1) {}
199
afd64f76 200 int status;
6415573a 201 int error;
afd64f76
WL
202 std::string body;
203};
204
6415573a
WL
205const char *http_errorstring(int code)
206{
207 switch(code) {
208#if LIBEVENT_VERSION_NUMBER >= 0x02010300
209 case EVREQ_HTTP_TIMEOUT:
210 return "timeout reached";
211 case EVREQ_HTTP_EOF:
212 return "EOF reached";
213 case EVREQ_HTTP_INVALID_HEADER:
214 return "error while reading header, or invalid header";
215 case EVREQ_HTTP_BUFFER_ERROR:
216 return "error encountered while reading or writing";
217 case EVREQ_HTTP_REQUEST_CANCEL:
218 return "request was canceled";
219 case EVREQ_HTTP_DATA_TOO_LONG:
220 return "response body is larger than allowed";
221#endif
222 default:
223 return "unknown";
224 }
225}
226
afd64f76
WL
227static void http_request_done(struct evhttp_request *req, void *ctx)
228{
229 HTTPReply *reply = static_cast<HTTPReply*>(ctx);
230
231 if (req == NULL) {
6415573a
WL
232 /* If req is NULL, it means an error occurred while connecting: the
233 * error code will have been passed to http_error_cb.
afd64f76
WL
234 */
235 reply->status = 0;
236 return;
237 }
b750cf1f 238
afd64f76
WL
239 reply->status = evhttp_request_get_response_code(req);
240
241 struct evbuffer *buf = evhttp_request_get_input_buffer(req);
242 if (buf)
243 {
244 size_t size = evbuffer_get_length(buf);
245 const char *data = (const char*)evbuffer_pullup(buf, size);
246 if (data)
247 reply->body = std::string(data, size);
248 evbuffer_drain(buf, size);
249 }
250}
251
6415573a
WL
252#if LIBEVENT_VERSION_NUMBER >= 0x02010300
253static void http_error_cb(enum evhttp_request_error err, void *ctx)
b750cf1f 254{
6415573a
WL
255 HTTPReply *reply = static_cast<HTTPReply*>(ctx);
256 reply->error = err;
257}
258#endif
259
3b26f5c3 260UniValue CallRPC(const std::string& strMethod, const UniValue& params)
afd64f76
WL
261{
262 std::string host = GetArg("-rpcconnect", "127.0.0.1");
263 int port = GetArg("-rpcport", BaseParams().RPCPort());
05c2ba63 264 BITCOIND_RPCPORT = port;
68377e18
KJA
265 // Obtain event base
266 raii_event_base base = obtain_event_base();
afd64f76
WL
267
268 // Synchronously look up hostname
68377e18
KJA
269 raii_evhttp_connection evcon = obtain_evhttp_connection_base(base.get(), host, port);
270 evhttp_connection_set_timeout(evcon.get(), GetArg("-rpcclienttimeout", DEFAULT_HTTP_CLIENT_TIMEOUT));
afd64f76
WL
271
272 HTTPReply response;
68377e18 273 raii_evhttp_request req = obtain_evhttp_request(http_request_done, (void*)&response);
afd64f76 274 if (req == NULL)
3b26f5c3 275 throw std::runtime_error("create http request failed");
6415573a 276#if LIBEVENT_VERSION_NUMBER >= 0x02010300
68377e18 277 evhttp_request_set_error_cb(req.get(), http_error_cb);
6415573a 278#endif
afd64f76
WL
279
280 // Get credentials
e957192c
WL
281 std::string strRPCUserColonPass;
282 if (mapArgs["-rpcpassword"] == "") {
283 // Try fall back to cookie-based authentication if no password is provided
284 if (!GetAuthCookie(&strRPCUserColonPass)) {
3b26f5c3 285 throw std::runtime_error(strprintf(
206e2b97
JG
286 _("Could not locate RPC credentials. No authentication cookie could be found,\n"
287 "and no rpcpassword is set in the configuration file (%s)."),
e957192c
WL
288 GetConfigFile().string().c_str()));
289
290 }
291 } else {
292 strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"];
293 }
294
68377e18 295 struct evkeyvalq* output_headers = evhttp_request_get_output_headers(req.get());
afd64f76
WL
296 assert(output_headers);
297 evhttp_add_header(output_headers, "Host", host.c_str());
298 evhttp_add_header(output_headers, "Connection", "close");
299 evhttp_add_header(output_headers, "Authorization", (std::string("Basic ") + EncodeBase64(strRPCUserColonPass)).c_str());
300
301 // Attach request data
302 std::string strRequest = JSONRPCRequest(strMethod, params, 1);
68377e18 303 struct evbuffer* output_buffer = evhttp_request_get_output_buffer(req.get());
afd64f76
WL
304 assert(output_buffer);
305 evbuffer_add(output_buffer, strRequest.data(), strRequest.size());
306
68377e18
KJA
307 int r = evhttp_make_request(evcon.get(), req.get(), EVHTTP_REQ_POST, "/");
308 req.release(); // ownership moved to evcon in above call
afd64f76 309 if (r != 0) {
afd64f76
WL
310 throw CConnectionFailed("send http request failed");
311 }
b750cf1f 312
68377e18 313 event_base_dispatch(base.get());
b750cf1f 314
afd64f76 315 if (response.status == 0)
7c2ab059 316 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 317 else if (response.status == HTTP_UNAUTHORIZED)
3b26f5c3 318 throw std::runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
afd64f76 319 else if (response.status >= 400 && response.status != HTTP_BAD_REQUEST && response.status != HTTP_NOT_FOUND && response.status != HTTP_INTERNAL_SERVER_ERROR)
3b26f5c3 320 throw std::runtime_error(strprintf("server returned HTTP error %d", response.status));
afd64f76 321 else if (response.body.empty())
3b26f5c3 322 throw std::runtime_error("no response from server");
b750cf1f
WL
323
324 // Parse reply
851f58f9 325 UniValue valReply(UniValue::VSTR);
afd64f76 326 if (!valReply.read(response.body))
3b26f5c3 327 throw std::runtime_error("couldn't parse reply from server");
d014114d 328 const UniValue& reply = valReply.get_obj();
b750cf1f 329 if (reply.empty())
3b26f5c3 330 throw std::runtime_error("expected reply to have result, error and id properties");
b750cf1f
WL
331
332 return reply;
333}
334
335int CommandLineRPC(int argc, char *argv[])
336{
3b26f5c3 337 std::string strPrint;
b750cf1f 338 int nRet = 0;
3ce7e669 339 try {
b750cf1f 340 // Skip switches
3ce7e669 341 while (argc > 1 && IsSwitchChar(argv[1][0])) {
b750cf1f
WL
342 argc--;
343 argv++;
344 }
21e33231
WL
345 std::vector<std::string> args = std::vector<std::string>(&argv[1], &argv[argc]);
346 if (GetBoolArg("-stdin", false)) {
347 // Read one arg per line from stdin and append
348 std::string line;
349 while (std::getline(std::cin,line))
350 args.push_back(line);
351 }
352 if (args.size() < 1)
3b26f5c3 353 throw std::runtime_error("too few parameters (need at least command)");
21e33231
WL
354 std::string strMethod = args[0];
355 UniValue params = RPCConvertValues(strMethod, std::vector<std::string>(args.begin()+1, args.end()));
b750cf1f 356
af82884a
DK
357 // Execute and handle connection failures with -rpcwait
358 const bool fWait = GetBoolArg("-rpcwait", false);
359 do {
360 try {
851f58f9 361 const UniValue reply = CallRPC(strMethod, params);
af82884a
DK
362
363 // Parse reply
d014114d
JS
364 const UniValue& result = find_value(reply, "result");
365 const UniValue& error = find_value(reply, "error");
af82884a 366
ed21d5bd 367 if (!error.isNull()) {
af82884a 368 // Error
ed21d5bd 369 int code = error["code"].get_int();
af82884a
DK
370 if (fWait && code == RPC_IN_WARMUP)
371 throw CConnectionFailed("server in warmup");
d014114d 372 strPrint = "error: " + error.write();
af82884a 373 nRet = abs(code);
f061578b
JS
374 if (error.isObject())
375 {
376 UniValue errCode = find_value(error, "code");
377 UniValue errMsg = find_value(error, "message");
378 strPrint = errCode.isNull() ? "" : "error code: "+errCode.getValStr()+"\n";
379
380 if (errMsg.isStr())
381 strPrint += "error message:\n"+errMsg.get_str();
382 }
af82884a
DK
383 } else {
384 // Result
ed21d5bd 385 if (result.isNull())
af82884a 386 strPrint = "";
ed21d5bd 387 else if (result.isStr())
af82884a
DK
388 strPrint = result.get_str();
389 else
ed21d5bd 390 strPrint = result.write(2);
af82884a 391 }
af82884a
DK
392 // Connection succeeded, no need to retry.
393 break;
394 }
27df4123 395 catch (const CConnectionFailed&) {
af82884a
DK
396 if (fWait)
397 MilliSleep(1000);
398 else
399 throw;
400 }
401 } while (fWait);
b750cf1f 402 }
27df4123 403 catch (const boost::thread_interrupted&) {
b750cf1f
WL
404 throw;
405 }
27df4123 406 catch (const std::exception& e) {
3b26f5c3 407 strPrint = std::string("error: ") + e.what();
b750cf1f
WL
408 nRet = EXIT_FAILURE;
409 }
410 catch (...) {
411 PrintExceptionContinue(NULL, "CommandLineRPC()");
412 throw;
413 }
414
3ce7e669 415 if (strPrint != "") {
b750cf1f
WL
416 fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
417 }
418 return nRet;
419}
420
2a03a390
WL
421int main(int argc, char* argv[])
422{
5248ff40 423 SetupEnvironment();
167b6231
WL
424 if (!SetupNetworking()) {
425 fprintf(stderr, "Error: Initializing networking failed\n");
e8f5b027 426 return EXIT_FAILURE;
167b6231 427 }
5248ff40 428
3ce7e669 429 try {
fadbbe1e
U
430 int ret = AppInitRPC(argc, argv);
431 if (ret != CONTINUE_EXECUTION)
432 return ret;
2a03a390 433 }
27df4123 434 catch (const std::exception& e) {
2a03a390 435 PrintExceptionContinue(&e, "AppInitRPC()");
0cafb630 436 return EXIT_FAILURE;
2a03a390
WL
437 } catch (...) {
438 PrintExceptionContinue(NULL, "AppInitRPC()");
0cafb630 439 return EXIT_FAILURE;
2a03a390
WL
440 }
441
0cafb630 442 int ret = EXIT_FAILURE;
3ce7e669 443 try {
a7199038 444 ret = CommandLineRPC(argc, argv);
2a03a390 445 }
27df4123 446 catch (const std::exception& e) {
2a03a390
WL
447 PrintExceptionContinue(&e, "CommandLineRPC()");
448 } catch (...) {
449 PrintExceptionContinue(NULL, "CommandLineRPC()");
450 }
a7199038 451 return ret;
2a03a390 452}
This page took 0.291638 seconds and 4 git commands to generate.