]> Git Repo - VerusCoin.git/blame - src/bitcoin-cli.cpp
Increment build number
[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
c88fa588 78void 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 79{
725800f9 80}
81
6e1d2e7d 82uint32_t komodo_heightstamp(int32_t height)
83{
84 return(0);
85}
86
fadbbe1e
U
87//
88// This function returns either one of EXIT_ codes when it's expected to stop the process or
89// CONTINUE_EXECUTION when it's expected to continue further.
90//
91static int AppInitRPC(int argc, char* argv[])
2a03a390 92{
abf5dd31
JG
93 static_assert(CONTINUE_EXECUTION != EXIT_FAILURE,
94 "CONTINUE_EXECUTION should be different from EXIT_FAILURE");
95 static_assert(CONTINUE_EXECUTION != EXIT_SUCCESS,
96 "CONTINUE_EXECUTION should be different from EXIT_SUCCESS");
2a03a390
WL
97 //
98 // Parameters
99 //
100 ParseParameters(argc, argv);
59d405e8 101 komodo_args(argv[0]);
af6edac0 102 if (argc<2 || mapArgs.count("-?") || mapArgs.count("-h") || mapArgs.count("-help") || mapArgs.count("-version")) {
c207cddb 103 std::string strUsage = _("Verus RPC client version 0.6.0-301-PBaaS-Cross-chain-Technology-Preview") + " " + "\n" + PrivacyInfo();
4d37cb20 104 if (!mapArgs.count("-version")) { strUsage += "\n" + _("Usage:") + "\n" +
5915430d
AD
105 " verus [options] <command> [params] " + _("Send command to Komodo") + "\n" +
106 " verus [options] help " + _("List commands") + "\n" +
107 " verus [options] help <command> " + _("Get help for a command") + "\n";
3d0a1ce1
PJ
108
109 strUsage += "\n" + HelpMessageCli();
af021144
S
110 } else {
111 strUsage += LicenseInfo();
3d0a1ce1
PJ
112 }
113
114 fprintf(stdout, "%s", strUsage.c_str());
fadbbe1e
U
115 if (argc < 2) {
116 fprintf(stderr, "Error: too few parameters\n");
117 return EXIT_FAILURE;
118 }
119 return EXIT_SUCCESS;
3d0a1ce1 120 }
3ce7e669 121 if (!boost::filesystem::is_directory(GetDataDir(false))) {
2a03a390 122 fprintf(stderr, "Error: Specified data directory \"%s\" does not exist.\n", mapArgs["-datadir"].c_str());
fadbbe1e 123 return EXIT_FAILURE;
2a03a390 124 }
4ae5e721
WL
125 try {
126 ReadConfigFile(mapArgs, mapMultiArgs);
27df4123 127 } catch (const std::exception& e) {
4ae5e721 128 fprintf(stderr,"Error reading configuration file: %s\n", e.what());
fadbbe1e 129 return EXIT_FAILURE;
4ae5e721 130 }
84ce18ca
WL
131 // Check for -testnet or -regtest parameter (BaseParams() calls are only valid after this clause)
132 if (!SelectBaseParamsFromCommandLine()) {
9d2b73d1 133 fprintf(stderr, "Error: Invalid combination of -regtest and -testnet.\n");
fadbbe1e 134 return EXIT_FAILURE;
9d2b73d1 135 }
afd64f76
WL
136 if (GetBoolArg("-rpcssl", false))
137 {
138 fprintf(stderr, "Error: SSL mode for RPC (-rpcssl) is no longer supported.\n");
fadbbe1e 139 return EXIT_FAILURE;
afd64f76 140 }
fadbbe1e 141 return CONTINUE_EXECUTION;
2a03a390
WL
142}
143
afd64f76
WL
144
145/** Reply structure for request_done to fill in */
146struct HTTPReply
b750cf1f 147{
6415573a
WL
148 HTTPReply(): status(0), error(-1) {}
149
afd64f76 150 int status;
6415573a 151 int error;
afd64f76
WL
152 std::string body;
153};
154
6415573a
WL
155const char *http_errorstring(int code)
156{
157 switch(code) {
158#if LIBEVENT_VERSION_NUMBER >= 0x02010300
159 case EVREQ_HTTP_TIMEOUT:
160 return "timeout reached";
161 case EVREQ_HTTP_EOF:
162 return "EOF reached";
163 case EVREQ_HTTP_INVALID_HEADER:
164 return "error while reading header, or invalid header";
165 case EVREQ_HTTP_BUFFER_ERROR:
166 return "error encountered while reading or writing";
167 case EVREQ_HTTP_REQUEST_CANCEL:
168 return "request was canceled";
169 case EVREQ_HTTP_DATA_TOO_LONG:
170 return "response body is larger than allowed";
171#endif
172 default:
173 return "unknown";
174 }
175}
176
afd64f76
WL
177static void http_request_done(struct evhttp_request *req, void *ctx)
178{
179 HTTPReply *reply = static_cast<HTTPReply*>(ctx);
180
181 if (req == NULL) {
6415573a
WL
182 /* If req is NULL, it means an error occurred while connecting: the
183 * error code will have been passed to http_error_cb.
afd64f76
WL
184 */
185 reply->status = 0;
186 return;
187 }
b750cf1f 188
afd64f76
WL
189 reply->status = evhttp_request_get_response_code(req);
190
191 struct evbuffer *buf = evhttp_request_get_input_buffer(req);
192 if (buf)
193 {
194 size_t size = evbuffer_get_length(buf);
195 const char *data = (const char*)evbuffer_pullup(buf, size);
196 if (data)
197 reply->body = std::string(data, size);
198 evbuffer_drain(buf, size);
199 }
200}
201
6415573a
WL
202#if LIBEVENT_VERSION_NUMBER >= 0x02010300
203static void http_error_cb(enum evhttp_request_error err, void *ctx)
b750cf1f 204{
6415573a
WL
205 HTTPReply *reply = static_cast<HTTPReply*>(ctx);
206 reply->error = err;
207}
208#endif
209
3b26f5c3 210UniValue CallRPC(const std::string& strMethod, const UniValue& params)
afd64f76
WL
211{
212 std::string host = GetArg("-rpcconnect", "127.0.0.1");
213 int port = GetArg("-rpcport", BaseParams().RPCPort());
05c2ba63 214 BITCOIND_RPCPORT = port;
68377e18
KJA
215 // Obtain event base
216 raii_event_base base = obtain_event_base();
afd64f76
WL
217
218 // Synchronously look up hostname
68377e18
KJA
219 raii_evhttp_connection evcon = obtain_evhttp_connection_base(base.get(), host, port);
220 evhttp_connection_set_timeout(evcon.get(), GetArg("-rpcclienttimeout", DEFAULT_HTTP_CLIENT_TIMEOUT));
afd64f76
WL
221
222 HTTPReply response;
68377e18 223 raii_evhttp_request req = obtain_evhttp_request(http_request_done, (void*)&response);
afd64f76 224 if (req == NULL)
3b26f5c3 225 throw std::runtime_error("create http request failed");
6415573a 226#if LIBEVENT_VERSION_NUMBER >= 0x02010300
68377e18 227 evhttp_request_set_error_cb(req.get(), http_error_cb);
6415573a 228#endif
afd64f76
WL
229
230 // Get credentials
e957192c
WL
231 std::string strRPCUserColonPass;
232 if (mapArgs["-rpcpassword"] == "") {
233 // Try fall back to cookie-based authentication if no password is provided
234 if (!GetAuthCookie(&strRPCUserColonPass)) {
3b26f5c3 235 throw std::runtime_error(strprintf(
206e2b97
JG
236 _("Could not locate RPC credentials. No authentication cookie could be found,\n"
237 "and no rpcpassword is set in the configuration file (%s)."),
e957192c
WL
238 GetConfigFile().string().c_str()));
239
240 }
241 } else {
242 strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"];
243 }
244
68377e18 245 struct evkeyvalq* output_headers = evhttp_request_get_output_headers(req.get());
afd64f76
WL
246 assert(output_headers);
247 evhttp_add_header(output_headers, "Host", host.c_str());
248 evhttp_add_header(output_headers, "Connection", "close");
249 evhttp_add_header(output_headers, "Authorization", (std::string("Basic ") + EncodeBase64(strRPCUserColonPass)).c_str());
250
251 // Attach request data
252 std::string strRequest = JSONRPCRequest(strMethod, params, 1);
68377e18 253 struct evbuffer* output_buffer = evhttp_request_get_output_buffer(req.get());
afd64f76
WL
254 assert(output_buffer);
255 evbuffer_add(output_buffer, strRequest.data(), strRequest.size());
256
68377e18
KJA
257 int r = evhttp_make_request(evcon.get(), req.get(), EVHTTP_REQ_POST, "/");
258 req.release(); // ownership moved to evcon in above call
afd64f76 259 if (r != 0) {
afd64f76
WL
260 throw CConnectionFailed("send http request failed");
261 }
b750cf1f 262
68377e18 263 event_base_dispatch(base.get());
b750cf1f 264
afd64f76 265 if (response.status == 0)
7c2ab059 266 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 267 else if (response.status == HTTP_UNAUTHORIZED)
3b26f5c3 268 throw std::runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
afd64f76 269 else if (response.status >= 400 && response.status != HTTP_BAD_REQUEST && response.status != HTTP_NOT_FOUND && response.status != HTTP_INTERNAL_SERVER_ERROR)
3b26f5c3 270 throw std::runtime_error(strprintf("server returned HTTP error %d", response.status));
afd64f76 271 else if (response.body.empty())
3b26f5c3 272 throw std::runtime_error("no response from server");
b750cf1f
WL
273
274 // Parse reply
851f58f9 275 UniValue valReply(UniValue::VSTR);
afd64f76 276 if (!valReply.read(response.body))
3b26f5c3 277 throw std::runtime_error("couldn't parse reply from server");
d014114d 278 const UniValue& reply = valReply.get_obj();
b750cf1f 279 if (reply.empty())
3b26f5c3 280 throw std::runtime_error("expected reply to have result, error and id properties");
b750cf1f
WL
281
282 return reply;
283}
284
285int CommandLineRPC(int argc, char *argv[])
286{
3b26f5c3 287 std::string strPrint;
b750cf1f 288 int nRet = 0;
3ce7e669 289 try {
b750cf1f 290 // Skip switches
3ce7e669 291 while (argc > 1 && IsSwitchChar(argv[1][0])) {
b750cf1f
WL
292 argc--;
293 argv++;
294 }
21e33231
WL
295 std::vector<std::string> args = std::vector<std::string>(&argv[1], &argv[argc]);
296 if (GetBoolArg("-stdin", false)) {
297 // Read one arg per line from stdin and append
298 std::string line;
299 while (std::getline(std::cin,line))
300 args.push_back(line);
301 }
302 if (args.size() < 1)
3b26f5c3 303 throw std::runtime_error("too few parameters (need at least command)");
21e33231
WL
304 std::string strMethod = args[0];
305 UniValue params = RPCConvertValues(strMethod, std::vector<std::string>(args.begin()+1, args.end()));
b750cf1f 306
af82884a
DK
307 // Execute and handle connection failures with -rpcwait
308 const bool fWait = GetBoolArg("-rpcwait", false);
309 do {
310 try {
851f58f9 311 const UniValue reply = CallRPC(strMethod, params);
af82884a
DK
312
313 // Parse reply
d014114d
JS
314 const UniValue& result = find_value(reply, "result");
315 const UniValue& error = find_value(reply, "error");
af82884a 316
ed21d5bd 317 if (!error.isNull()) {
af82884a 318 // Error
ed21d5bd 319 int code = error["code"].get_int();
af82884a
DK
320 if (fWait && code == RPC_IN_WARMUP)
321 throw CConnectionFailed("server in warmup");
d014114d 322 strPrint = "error: " + error.write();
af82884a 323 nRet = abs(code);
f061578b
JS
324 if (error.isObject())
325 {
326 UniValue errCode = find_value(error, "code");
327 UniValue errMsg = find_value(error, "message");
328 strPrint = errCode.isNull() ? "" : "error code: "+errCode.getValStr()+"\n";
329
330 if (errMsg.isStr())
331 strPrint += "error message:\n"+errMsg.get_str();
332 }
af82884a
DK
333 } else {
334 // Result
ed21d5bd 335 if (result.isNull())
af82884a 336 strPrint = "";
ed21d5bd 337 else if (result.isStr())
af82884a
DK
338 strPrint = result.get_str();
339 else
ed21d5bd 340 strPrint = result.write(2);
af82884a 341 }
af82884a
DK
342 // Connection succeeded, no need to retry.
343 break;
344 }
27df4123 345 catch (const CConnectionFailed&) {
af82884a
DK
346 if (fWait)
347 MilliSleep(1000);
348 else
349 throw;
350 }
351 } while (fWait);
b750cf1f 352 }
27df4123 353 catch (const boost::thread_interrupted&) {
b750cf1f
WL
354 throw;
355 }
27df4123 356 catch (const std::exception& e) {
3b26f5c3 357 strPrint = std::string("error: ") + e.what();
b750cf1f
WL
358 nRet = EXIT_FAILURE;
359 }
360 catch (...) {
361 PrintExceptionContinue(NULL, "CommandLineRPC()");
362 throw;
363 }
364
3ce7e669 365 if (strPrint != "") {
b750cf1f
WL
366 fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
367 }
368 return nRet;
369}
370
2a03a390
WL
371int main(int argc, char* argv[])
372{
5248ff40 373 SetupEnvironment();
167b6231
WL
374 if (!SetupNetworking()) {
375 fprintf(stderr, "Error: Initializing networking failed\n");
e8f5b027 376 return EXIT_FAILURE;
167b6231 377 }
5248ff40 378
3ce7e669 379 try {
fadbbe1e
U
380 int ret = AppInitRPC(argc, argv);
381 if (ret != CONTINUE_EXECUTION)
382 return ret;
2a03a390 383 }
27df4123 384 catch (const std::exception& e) {
2a03a390 385 PrintExceptionContinue(&e, "AppInitRPC()");
0cafb630 386 return EXIT_FAILURE;
2a03a390
WL
387 } catch (...) {
388 PrintExceptionContinue(NULL, "AppInitRPC()");
0cafb630 389 return EXIT_FAILURE;
2a03a390
WL
390 }
391
0cafb630 392 int ret = EXIT_FAILURE;
3ce7e669 393 try {
a7199038 394 ret = CommandLineRPC(argc, argv);
2a03a390 395 }
27df4123 396 catch (const std::exception& e) {
2a03a390
WL
397 PrintExceptionContinue(&e, "CommandLineRPC()");
398 } catch (...) {
399 PrintExceptionContinue(NULL, "CommandLineRPC()");
400 }
a7199038 401 return ret;
2a03a390 402}
This page took 0.333726 seconds and 4 git commands to generate.