255b7cad26b467e9fc0fd9e3197f35941e96af14
[novacoin.git] / src / bitcoinrpc.cpp
1 // Copyright (c) 2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2012 The Bitcoin developers
3 // Distributed under the MIT/X11 software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5
6 #include "init.h"
7 #include "util.h"
8 #include "sync.h"
9 #include "ui_interface.h"
10 #include "base58.h"
11 #include "bitcoinrpc.h"
12 #include "db.h"
13
14 #undef printf
15 #include <memory>
16 #include <ixwebsocket/IXHttpServer.h>
17 #include <ixwebsocket/IXHttpClient.h>
18 #include <boost/asio.hpp>
19 #include <boost/asio/ip/v6_only.hpp>
20 #include <boost/bind.hpp>
21 #include <boost/filesystem.hpp>
22 #include <boost/foreach.hpp>
23 #include <boost/iostreams/concepts.hpp>
24 #include <boost/iostreams/stream.hpp>
25 #include <boost/algorithm/string.hpp>
26 #include <boost/lexical_cast.hpp>
27 #include <boost/asio/ssl.hpp>
28 #include <boost/filesystem/fstream.hpp>
29 #include <boost/shared_ptr.hpp>
30 #include <list>
31
32 #define printf OutputDebugStringF
33
34 using namespace std;
35 using namespace boost;
36 using namespace json_spirit;
37
38 std::unique_ptr<ix::HttpServer> g_server;
39
40 static std::string strRPCUserColonPass;
41
42 const Object emptyobj;
43
44 static inline unsigned short GetDefaultRPCPort()
45 {
46     return GetBoolArg("-testnet", false) ? 18344 : 8344;
47 }
48
49 Object JSONRPCError(int code, const string& message)
50 {
51     Object error;
52     error.push_back(Pair("code", code));
53     error.push_back(Pair("message", message));
54     return error;
55 }
56
57 void RPCTypeCheck(const Array& params,
58                   const list<Value_type>& typesExpected,
59                   bool fAllowNull)
60 {
61     unsigned int i = 0;
62     BOOST_FOREACH(Value_type t, typesExpected)
63     {
64         if (params.size() <= i)
65             break;
66
67         const Value& v = params[i];
68         if (!((v.type() == t) || (fAllowNull && (v.type() == null_type))))
69         {
70             string err = strprintf("Expected type %s, got %s",
71                                    Value_type_name[t], Value_type_name[v.type()]);
72             throw JSONRPCError(RPC_TYPE_ERROR, err);
73         }
74         i++;
75     }
76 }
77
78 void RPCTypeCheck(const Object& o,
79                   const map<string, Value_type>& typesExpected,
80                   bool fAllowNull)
81 {
82     BOOST_FOREACH(const PAIRTYPE(string, Value_type)& t, typesExpected)
83     {
84         const Value& v = find_value(o, t.first);
85         if (!fAllowNull && v.type() == null_type)
86             throw JSONRPCError(RPC_TYPE_ERROR, strprintf("Missing %s", t.first.c_str()));
87
88         if (!((v.type() == t.second) || (fAllowNull && (v.type() == null_type))))
89         {
90             string err = strprintf("Expected type %s for %s, got %s",
91                                    Value_type_name[t.second], t.first.c_str(), Value_type_name[v.type()]);
92             throw JSONRPCError(RPC_TYPE_ERROR, err);
93         }
94     }
95 }
96
97 int64_t AmountFromValue(const Value& value)
98 {
99     double dAmount = value.get_real();
100     if (dAmount <= 0.0 || dAmount > MAX_MONEY)
101         throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount");
102     int64_t nAmount = roundint64(dAmount * COIN);
103     if (!MoneyRange(nAmount))
104         throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount");
105     return nAmount;
106 }
107
108 Value ValueFromAmount(int64_t amount)
109 {
110     return (double)amount / (double)COIN;
111 }
112
113 std::string HexBits(unsigned int nBits)
114 {
115     union {
116         int32_t nBits;
117         char cBits[4];
118     } uBits;
119     uBits.nBits = htonl((int32_t)nBits);
120     return HexStr(BEGIN(uBits.cBits), END(uBits.cBits));
121 }
122
123
124 //
125 // Utilities: convert hex-encoded Values
126 // (throws error if not hex).
127 //
128 uint256 ParseHashV(const Value& v, string strName)
129 {
130     string strHex;
131     if (v.type() == str_type)
132         strHex = v.get_str();
133     if (!IsHex(strHex)) // Note: IsHex("") is false
134         throw JSONRPCError(RPC_INVALID_PARAMETER, strName+" must be hexadecimal string (not '"+strHex+"')");
135     uint256 result;
136     result.SetHex(strHex);
137     return result;
138 }
139
140 uint256 ParseHashO(const Object& o, string strKey)
141 {
142     return ParseHashV(find_value(o, strKey), strKey);
143 }
144
145 vector<unsigned char> ParseHexV(const Value& v, string strName)
146 {
147     string strHex;
148     if (v.type() == str_type)
149         strHex = v.get_str();
150     if (!IsHex(strHex))
151         throw JSONRPCError(RPC_INVALID_PARAMETER, strName+" must be hexadecimal string (not '"+strHex+"')");
152     return ParseHex(strHex);
153 }
154
155 vector<unsigned char> ParseHexO(const Object& o, string strKey)
156 {
157     return ParseHexV(find_value(o, strKey), strKey);
158 }
159
160
161 ///
162 /// Note: This interface may still be subject to change.
163 ///
164
165 string CRPCTable::help(string strCommand) const
166 {
167     string strRet;
168     set<rpcfn_type> setDone;
169     for (map<string, const CRPCCommand*>::const_iterator mi = mapCommands.begin(); mi != mapCommands.end(); ++mi)
170     {
171         const CRPCCommand *pcmd = mi->second;
172         string strMethod = mi->first;
173         // We already filter duplicates, but these deprecated screw up the sort order
174         if (strMethod.find("label") != string::npos)
175             continue;
176         if (!strCommand.empty() && strMethod != strCommand)
177             continue;
178         try
179         {
180             Array params;
181             rpcfn_type pfn = pcmd->actor;
182             if (setDone.insert(pfn).second)
183                 (*pfn)(params, true);
184         }
185         catch (std::exception& e)
186         {
187             // Help text is returned in an exception
188             string strHelp = string(e.what());
189             if (strCommand.empty())
190                 if (strHelp.find('\n') != string::npos)
191                     strHelp = strHelp.substr(0, strHelp.find('\n'));
192             strRet += strHelp + "\n";
193         }
194     }
195     if (strRet.empty())
196         strRet = strprintf("help: unknown command: %s\n", strCommand.c_str());
197     strRet = strRet.substr(0,strRet.size()-1);
198     return strRet;
199 }
200
201 Value help(const Array& params, bool fHelp)
202 {
203     if (fHelp || params.size() > 1)
204         throw runtime_error(
205             "help [command]\n"
206             "List commands, or get help for a command.");
207
208     string strCommand;
209     if (params.size() > 0)
210         strCommand = params[0].get_str();
211
212     return tableRPC.help(strCommand);
213 }
214
215
216 Value stop(const Array& params, bool fHelp)
217 {
218     if (fHelp || params.size() > 1)
219         throw runtime_error(
220             "stop <detach>\n"
221             "<detach> is true or false to detach the database or not for this stop only\n"
222             "Stop NovaCoin server (and possibly override the detachdb config value).");
223     // Shutdown will take long enough that the response should get back
224     if (params.size() > 0)
225         bitdb.SetDetach(params[0].get_bool());
226     StartShutdown();
227     return "NovaCoin server stopping";
228 }
229
230
231
232 //
233 // Call Table
234 //
235
236
237 static const CRPCCommand vRPCCommands[] =
238 { //  name                      function                 safemd  unlocked
239   //  ------------------------  -----------------------  ------  --------
240     { "help",                       &help,                        true,   true },
241     { "stop",                       &stop,                        true,   true },
242     { "getbestblockhash",           &getbestblockhash,            true,   false },
243     { "getblockcount",              &getblockcount,               true,   false },
244     { "getconnectioncount",         &getconnectioncount,          true,   false },
245     { "getaddrmaninfo",             &getaddrmaninfo,              true,   false },
246     { "getpeerinfo",                &getpeerinfo,                 true,   false },
247     { "addnode",                    &addnode,                     true,   true  },
248     { "getaddednodeinfo",           &getaddednodeinfo,            true,   true  },
249     { "getdifficulty",              &getdifficulty,               true,   false },
250     { "getinfo",                    &getinfo,                     true,   false },
251     { "getsubsidy",                 &getsubsidy,                  true,   false },
252     { "getmininginfo",              &getmininginfo,               true,   false },
253     { "scaninput",                  &scaninput,                   true,   true },
254     { "getnewaddress",              &getnewaddress,               true,   false },
255     { "getnettotals",               &getnettotals,                true,   true  },
256     { "ntptime",                    &ntptime,                     true,   true  },
257     { "getaccountaddress",          &getaccountaddress,           true,   false },
258     { "setaccount",                 &setaccount,                  true,   false },
259     { "getaccount",                 &getaccount,                  false,  false },
260     { "getaddressesbyaccount",      &getaddressesbyaccount,       true,   false },
261     { "sendtoaddress",              &sendtoaddress,               false,  false },
262     { "mergecoins",                 &mergecoins,                  false,  false },
263     { "getreceivedbyaddress",       &getreceivedbyaddress,        false,  false },
264     { "getreceivedbyaccount",       &getreceivedbyaccount,        false,  false },
265     { "listreceivedbyaddress",      &listreceivedbyaddress,       false,  false },
266     { "listreceivedbyaccount",      &listreceivedbyaccount,       false,  false },
267     { "backupwallet",               &backupwallet,                true,   false },
268     { "keypoolrefill",              &keypoolrefill,               true,   false },
269     { "keypoolreset",               &keypoolreset,                true,   false },
270     { "walletpassphrase",           &walletpassphrase,            true,   false },
271     { "walletpassphrasechange",     &walletpassphrasechange,      false,  false },
272     { "walletlock",                 &walletlock,                  true,   false },
273     { "encryptwallet",              &encryptwallet,               false,  false },
274     { "validateaddress",            &validateaddress,             true,   false },
275     { "getbalance",                 &getbalance,                  false,  false },
276     { "move",                       &movecmd,                     false,  false },
277     { "sendfrom",                   &sendfrom,                    false,  false },
278     { "sendmany",                   &sendmany,                    false,  false },
279     { "addmultisigaddress",         &addmultisigaddress,          false,  false },
280     { "addredeemscript",            &addredeemscript,             false,  false },
281     { "getrawmempool",              &getrawmempool,               true,   false },
282     { "getblock",                   &getblock,                    false,  false },
283     { "getblockbynumber",           &getblockbynumber,            false,  false },
284     { "dumpblock",                  &dumpblock,                   false,  false },
285     { "dumpblockbynumber",          &dumpblockbynumber,           false,  false },
286     { "getblockhash",               &getblockhash,                false,  false },
287     { "gettransaction",             &gettransaction,              false,  false },
288     { "listtransactions",           &listtransactions,            false,  false },
289     { "listaddressgroupings",       &listaddressgroupings,        false,  false },
290     { "signmessage",                &signmessage,                 false,  false },
291     { "verifymessage",              &verifymessage,               false,  false },
292     { "getwork",                    &getwork,                     true,   false },
293     { "getworkex",                  &getworkex,                   true,   false },
294     { "listaccounts",               &listaccounts,                false,  false },
295     { "settxfee",                   &settxfee,                    false,  false },
296     { "getblocktemplate",           &getblocktemplate,            true,   false },
297     { "submitblock",                &submitblock,                 false,  false },
298     { "listsinceblock",             &listsinceblock,              false,  false },
299     { "dumpprivkey",                &dumpprivkey,                 false,  false },
300     { "dumpwallet",                 &dumpwallet,                  true,   false },
301     { "importwallet",               &importwallet,                false,  false },
302     { "importprivkey",              &importprivkey,               false,  false },
303     { "importaddress",              &importaddress,               false,  true  },
304     { "removeaddress",              &removeaddress,               false,  true  },
305     { "listunspent",                &listunspent,                 false,  false },
306     { "getrawtransaction",          &getrawtransaction,           false,  false },
307     { "createrawtransaction",       &createrawtransaction,        false,  false },
308     { "decoderawtransaction",       &decoderawtransaction,        false,  false },
309     { "createmultisig",             &createmultisig,              false,  false },
310     { "decodescript",               &decodescript,                false,  false },
311     { "signrawtransaction",         &signrawtransaction,          false,  false },
312     { "sendrawtransaction",         &sendrawtransaction,          false,  false },
313     { "getcheckpoint",              &getcheckpoint,               true,   false },
314     { "reservebalance",             &reservebalance,              false,  true},
315     { "checkwallet",                &checkwallet,                 false,  true},
316     { "repairwallet",               &repairwallet,                false,  true},
317     { "resendwallettransactions",   &resendwallettransactions,    false,  true},
318     { "makekeypair",                &makekeypair,                 false,  true},
319     { "newmalleablekey",            &newmalleablekey,             false,  false},
320     { "adjustmalleablekey",         &adjustmalleablekey,          false,  false},
321     { "adjustmalleablepubkey",      &adjustmalleablepubkey,       false,  false},
322     { "listmalleableviews",         &listmalleableviews,          false,  false},
323     { "dumpmalleablekey",           &dumpmalleablekey,            false,  false},
324     { "importmalleablekey",         &importmalleablekey,          true,   false },
325     { "sendalert",                  &sendalert,                   false,  false},
326 };
327
328 CRPCTable::CRPCTable()
329 {
330     unsigned int vcidx;
331     for (vcidx = 0; vcidx < (sizeof(vRPCCommands) / sizeof(vRPCCommands[0])); vcidx++)
332     {
333         const CRPCCommand *pcmd;
334
335         pcmd = &vRPCCommands[vcidx];
336         mapCommands[pcmd->name] = pcmd;
337     }
338 }
339
340 const CRPCCommand *CRPCTable::operator[](string name) const
341 {
342     map<string, const CRPCCommand*>::const_iterator it = mapCommands.find(name);
343     if (it == mapCommands.end())
344         return NULL;
345     return (*it).second;
346 }
347
348 string rfc1123Time()
349 {
350     return DateTimeStrFormat("%a, %d %b %Y %H:%M:%S +0000", GetTime());
351 }
352
353 static string HTTPReply(int nStatus, const string& strMsg, bool keepalive)
354 {
355     if (nStatus == HTTP_UNAUTHORIZED)
356         return strprintf("HTTP/1.0 401 Authorization Required\r\n"
357             "Date: %s\r\n"
358             "Server: novacoin-json-rpc/%s\r\n"
359             "WWW-Authenticate: Basic realm=\"jsonrpc\"\r\n"
360             "Content-Type: text/html\r\n"
361             "Content-Length: 296\r\n"
362             "\r\n"
363             "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\r\n"
364             "\"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd\">\r\n"
365             "<HTML>\r\n"
366             "<HEAD>\r\n"
367             "<TITLE>Error</TITLE>\r\n"
368             "<META HTTP-EQUIV='Content-Type' CONTENT='text/html; charset=ISO-8859-1'>\r\n"
369             "</HEAD>\r\n"
370             "<BODY><H1>401 Unauthorized.</H1></BODY>\r\n"
371             "</HTML>\r\n", rfc1123Time().c_str(), FormatFullVersion().c_str());
372     const char *cStatus;
373          if (nStatus == HTTP_OK) cStatus = "OK";
374     else if (nStatus == HTTP_BAD_REQUEST) cStatus = "Bad Request";
375     else if (nStatus == HTTP_FORBIDDEN) cStatus = "Forbidden";
376     else if (nStatus == HTTP_NOT_FOUND) cStatus = "Not Found";
377     else if (nStatus == HTTP_INTERNAL_SERVER_ERROR) cStatus = "Internal Server Error";
378     else cStatus = "";
379     return strprintf(
380             "HTTP/1.1 %d %s\r\n"
381             "Date: %s\r\n"
382             "Connection: %s\r\n"
383             "Content-Length: %" PRIszu "\r\n"
384             "Content-Type: application/json\r\n"
385             "Server: novacoin-json-rpc/%s\r\n"
386             "\r\n"
387             "%s",
388         nStatus,
389         cStatus,
390         rfc1123Time().c_str(),
391         keepalive ? "keep-alive" : "close",
392         strMsg.size(),
393         FormatFullVersion().c_str(),
394         strMsg.c_str());
395 }
396
397 int ReadHTTPStatus(std::basic_istream<char>& stream, int &proto)
398 {
399     string str;
400     getline(stream, str);
401     vector<string> vWords;
402     istringstream iss(str);
403     copy(istream_iterator<string>(iss), istream_iterator<string>(), back_inserter(vWords));
404     if (vWords.size() < 2)
405         return HTTP_INTERNAL_SERVER_ERROR;
406     proto = 0;
407     const char *ver = strstr(str.c_str(), "HTTP/1.");
408     if (ver != NULL)
409         proto = atoi(ver+7);
410     return atoi(vWords[1].c_str());
411 }
412
413 int ReadHTTPHeader(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet)
414 {
415     int nLen = 0;
416     for ( ; ; )
417     {
418         string str;
419         std::getline(stream, str);
420         if (str.empty() || str == "\r")
421             break;
422         string::size_type nColon = str.find(":");
423         if (nColon != string::npos)
424         {
425             string strHeader = str.substr(0, nColon);
426             boost::trim(strHeader);
427             boost::to_lower(strHeader);
428             string strValue = str.substr(nColon+1);
429             boost::trim(strValue);
430             mapHeadersRet[strHeader] = strValue;
431             if (strHeader == "content-length")
432                 nLen = atoi(strValue.c_str());
433         }
434     }
435     return nLen;
436 }
437
438 int ReadHTTP(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet, string& strMessageRet)
439 {
440     mapHeadersRet.clear();
441     strMessageRet.clear();
442
443     // Read status
444     int nProto = 0;
445     int nStatus = ReadHTTPStatus(stream, nProto);
446
447     // Read header
448     int nLen = ReadHTTPHeader(stream, mapHeadersRet);
449     if (nLen < 0 || nLen > (int)MAX_SIZE)
450         return HTTP_INTERNAL_SERVER_ERROR;
451
452     // Read message
453     if (nLen > 0)
454     {
455         vector<char> vch(nLen);
456         stream.read(&vch[0], nLen);
457         strMessageRet = string(vch.begin(), vch.end());
458     }
459
460     string sConHdr = mapHeadersRet["connection"];
461
462     if ((sConHdr != "close") && (sConHdr != "keep-alive"))
463     {
464         if (nProto >= 1)
465             mapHeadersRet["connection"] = "keep-alive";
466         else
467             mapHeadersRet["connection"] = "close";
468     }
469
470     return nStatus;
471 }
472
473 bool HTTPAuthorized(map<string, string>& mapHeaders)
474 {
475     string strAuth = mapHeaders["authorization"];
476     if (strAuth.substr(0,6) != "Basic ")
477         return false;
478     string strUserPass64 = strAuth.substr(6); boost::trim(strUserPass64);
479     string strUserPass = DecodeBase64(strUserPass64);
480     return TimingResistantEqual(strUserPass, strRPCUserColonPass);
481 }
482
483 //
484 // JSON-RPC protocol.  Bitcoin speaks version 1.0 for maximum compatibility,
485 // but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
486 // unspecified (HTTP errors and contents of 'error').
487 //
488 // 1.0 spec: http://json-rpc.org/wiki/specification
489 // 1.2 spec: http://groups.google.com/group/json-rpc/web/json-rpc-over-http
490 // http://www.codeproject.com/KB/recipes/JSON_Spirit.aspx
491 //
492
493 string JSONRPCRequest(const string& strMethod, const Array& params, const Value& id)
494 {
495     Object request;
496     request.push_back(Pair("method", strMethod));
497     request.push_back(Pair("params", params));
498     request.push_back(Pair("id", id));
499     return write_string(Value(request), false) + "\n";
500 }
501
502 Object JSONRPCReplyObj(const Value& result, const Value& error, const Value& id)
503 {
504     Object reply;
505     if (error.type() != null_type)
506         reply.push_back(Pair("result", Value::null));
507     else
508         reply.push_back(Pair("result", result));
509     reply.push_back(Pair("error", error));
510     reply.push_back(Pair("id", id));
511     return reply;
512 }
513
514 string JSONRPCReply(const Value& result, const Value& error, const Value& id)
515 {
516     Object reply = JSONRPCReplyObj(result, error, id);
517     return write_string(Value(reply), false) + "\n";
518 }
519
520 string ErrorReply(const Object& objError, const Value& id)
521 {
522     // Send error reply from json-rpc error object
523     int nStatus = HTTP_INTERNAL_SERVER_ERROR;
524     int code = find_value(objError, "code").get_int();
525     if (code == RPC_INVALID_REQUEST) nStatus = HTTP_BAD_REQUEST;
526     else if (code == RPC_METHOD_NOT_FOUND) nStatus = HTTP_NOT_FOUND;
527     return JSONRPCReply(Value::null, objError, id);
528 }
529
530 class JSONRequest
531 {
532 public:
533     Value id;
534     string strMethod;
535     Array params;
536
537     JSONRequest() { id = Value::null; }
538     void parse(const Value& valRequest);
539 };
540
541 void JSONRequest::parse(const Value& valRequest)
542 {
543     // Parse request
544     if (valRequest.type() != obj_type)
545         throw JSONRPCError(RPC_INVALID_REQUEST, "Invalid Request object");
546     const Object& request = valRequest.get_obj();
547
548     // Parse id now so errors from here on will have the id
549     id = find_value(request, "id");
550
551     // Parse method
552     Value valMethod = find_value(request, "method");
553     if (valMethod.type() == null_type)
554         throw JSONRPCError(RPC_INVALID_REQUEST, "Missing method");
555     if (valMethod.type() != str_type)
556         throw JSONRPCError(RPC_INVALID_REQUEST, "Method must be a string");
557     strMethod = valMethod.get_str();
558     if (strMethod != "getwork" && strMethod != "getblocktemplate")
559         printf("RPCServer method=%s\n", strMethod.c_str());
560
561     // Parse params
562     Value valParams = find_value(request, "params");
563     if (valParams.type() == array_type)
564         params = valParams.get_array();
565     else if (valParams.type() == null_type)
566         params = Array();
567     else
568         throw JSONRPCError(RPC_INVALID_REQUEST, "Params must be an array");
569 }
570
571 static Object JSONRPCExecOne(const Value& req)
572 {
573     Object rpc_result;
574
575     JSONRequest jreq;
576     try {
577         jreq.parse(req);
578
579         Value result = tableRPC.execute(jreq.strMethod, jreq.params);
580         rpc_result = JSONRPCReplyObj(result, Value::null, jreq.id);
581     }
582     catch (Object& objError)
583     {
584         rpc_result = JSONRPCReplyObj(Value::null, objError, jreq.id);
585     }
586     catch (std::exception& e)
587     {
588         rpc_result = JSONRPCReplyObj(Value::null,
589                                      JSONRPCError(RPC_PARSE_ERROR, e.what()), jreq.id);
590     }
591
592     return rpc_result;
593 }
594
595 static string JSONRPCExecBatch(const Array& vReq)
596 {
597     Array ret;
598     for (unsigned int reqIdx = 0; reqIdx < vReq.size(); reqIdx++)
599         ret.push_back(JSONRPCExecOne(vReq[reqIdx]));
600
601     return write_string(Value(ret), false) + "\n";
602 }
603
604 static CCriticalSection cs_THREAD_RPCHANDLER;
605
606 void StartRPCServer()
607 {
608     string host = GetArg("-rpchost", "127.0.0.1");
609     int port = GetArg("-rpcport", GetDefaultRPCPort());
610
611     g_server = std::unique_ptr<ix::HttpServer>(new ix::HttpServer(port, host));
612
613     LOCK(cs_THREAD_RPCHANDLER);
614
615     g_server->setOnConnectionCallback([](ix::HttpRequestPtr request, std::shared_ptr<ix::ConnectionState> connectionState) -> ix::HttpResponsePtr {
616
617         ix::WebSocketHttpHeaders headers;
618
619         if (request->method != "POST") {
620             return std::make_shared<ix::HttpResponse>(400, "Bad request", ix::HttpErrorCode::Ok, headers, "Bad request");
621         }
622
623         JSONRequest jreq;
624
625         try
626         {
627             // Parse request
628             Value valRequest;
629             if (!read_string(request->body, valRequest))
630                 throw JSONRPCError(RPC_PARSE_ERROR, "Parse error"); 
631
632             string strReply;
633
634             // singleton request
635             if (valRequest.type() == obj_type) {
636                 jreq.parse(valRequest);
637
638                 // Execute request
639                 Value result = tableRPC.execute(jreq.strMethod, jreq.params);
640
641                 // Send reply
642                 strReply = JSONRPCReply(result, Value::null, jreq.id);
643
644             // array of requests
645             } else if (valRequest.type() == array_type)
646                 // Execute batch of requests
647                 strReply = JSONRPCExecBatch(valRequest.get_array());
648             else
649                 throw JSONRPCError(RPC_PARSE_ERROR, "Top-level object parse error");
650
651             // Send reply to client
652             return std::make_shared<ix::HttpResponse>(200, "OK", ix::HttpErrorCode::Ok, headers, strReply);
653         
654         }
655         catch(Object& objError)
656         {
657             return std::make_shared<ix::HttpResponse>(500, "Internal Server Error", ix::HttpErrorCode::Ok, headers, ErrorReply(objError, jreq.id));
658         }
659         catch(std::exception& e)
660         {
661             return std::make_shared<ix::HttpResponse>(500, "Internal Server Error", ix::HttpErrorCode::Ok, headers, ErrorReply(JSONRPCError(RPC_PARSE_ERROR, e.what()), jreq.id));
662         }
663     });
664
665     std::pair<bool, std::string> result = g_server->listen();
666     if (!result.first) {
667         auto strerr = strprintf(_("An error occurred while setting up the RPC port %u for listening on host %s: %s"), port, host.c_str(), result.second.c_str());
668         uiInterface.ThreadSafeMessageBox(strerr, _("Error"), CClientUIInterface::OK | CClientUIInterface::MODAL);
669         return StartShutdown();
670     }
671
672     // We're listening now
673     vnThreadsRunning[THREAD_RPCLISTENER]++;
674 }
675
676 void StopRPCServer()
677 {
678     LOCK(cs_THREAD_RPCHANDLER);
679     if (g_server) g_server->stop();
680     vnThreadsRunning[THREAD_RPCLISTENER]--;
681 }
682
683 json_spirit::Value CRPCTable::execute(const std::string &strMethod, const json_spirit::Array &params) const
684 {
685     // Find method
686     const CRPCCommand *pcmd = tableRPC[strMethod];
687     if (!pcmd)
688         throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found");
689
690     // Observe safe mode
691     string strWarning = GetWarnings("rpc");
692     if (!strWarning.empty() && !GetBoolArg("-disablesafemode") &&
693         !pcmd->okSafeMode)
694         throw JSONRPCError(RPC_FORBIDDEN_BY_SAFE_MODE, string("Safe mode: ") + strWarning);
695
696     try
697     {
698         // Execute
699         Value result;
700         {
701             if (pcmd->unlocked)
702                 result = pcmd->actor(params, false);
703             else {
704                 LOCK2(cs_main, pwalletMain->cs_wallet);
705                 result = pcmd->actor(params, false);
706             }
707         }
708         return result;
709     }
710     catch (std::exception& e)
711     {
712         throw JSONRPCError(RPC_MISC_ERROR, e.what());
713     }
714 }
715
716 std::vector<std::string> CRPCTable::listCommands() const
717 {
718     std::vector<std::string> commandList;
719     typedef std::map<std::string, const CRPCCommand*> commandMap;
720
721     std::transform( mapCommands.begin(), mapCommands.end(),
722                    std::back_inserter(commandList),
723                    boost::bind(&commandMap::value_type::first,_1) );
724     return commandList;
725 }
726
727 Object CallRPC(const string& strMethod, const Array& params)
728 {
729     if (mapArgs["-rpcuser"].empty() && mapArgs["-rpcpassword"].empty())
730         throw runtime_error(strprintf(
731             _("You must set rpcpassword=<password> in the configuration file:\n%s\n"
732               "If the file does not exist, create it with owner-readable-only file permissions."),
733                 GetConfigFile().string().c_str()));
734
735     // Create HTTP client
736     ix::HttpClient httpClient;
737     ix::HttpRequestArgsPtr args = httpClient.createRequest();
738
739     // HTTP basic authentication
740     ix::WebSocketHttpHeaders mapRequestHeaders;
741     string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
742     mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64;
743     args->extraHeaders = mapRequestHeaders;
744
745     // Timeouts
746     args->connectTimeout = GetArgInt("-rpc_connecttimeout", 30000);
747     args->transferTimeout = GetArgInt("-rpc_transfertimeout", 30000);
748
749     bool fUseSSL = GetBoolArg("-rpcssl");
750     string url = string(fUseSSL ? "https://" : "http://") + GetArg("-rpcconnect", "127.0.0.1") + ":" + GetArg("-rpcport", itostr(GetDefaultRPCPort()));
751
752     // Send request
753     string strRequest = JSONRPCRequest(strMethod, params, GetRandInt(INT32_MAX));
754     auto out = httpClient.post(url, strRequest, args);
755
756     // Process reply
757     int nStatus = out->statusCode;
758     string strReply = out->body;
759     ix::WebSocketHttpHeaders mapHeaders = out->headers;
760
761     // Receive reply
762     if (nStatus == HTTP_UNAUTHORIZED)
763         throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
764     else if (nStatus >= 400 && nStatus != HTTP_BAD_REQUEST && nStatus != HTTP_NOT_FOUND && nStatus != HTTP_INTERNAL_SERVER_ERROR)
765         throw runtime_error(strprintf("server returned HTTP error %d", nStatus));
766     else if (strReply.empty())
767         throw runtime_error("no response from server");
768
769     // Parse reply
770     Value valReply;
771     if (!read_string(strReply, valReply))
772         throw runtime_error("couldn't parse reply from server");
773     const Object& reply = valReply.get_obj();
774     if (reply.empty())
775         throw runtime_error("expected reply to have result, error and id properties");
776
777     return reply;
778 }
779
780
781
782
783 template<typename T>
784 void ConvertTo(Value& value, bool fAllowNull=false)
785 {
786     if (fAllowNull && value.type() == null_type)
787         return;
788     if (value.type() == str_type)
789     {
790         // reinterpret string as unquoted json value
791         Value value2;
792         string strJSON = value.get_str();
793         if (!read_string(strJSON, value2))
794             throw runtime_error(string("Error parsing JSON:")+strJSON);
795         ConvertTo<T>(value2, fAllowNull);
796         value = value2;
797     }
798     else
799     {
800         value = value.get_value<T>();
801     }
802 }
803
804 // Convert strings to command-specific RPC representation
805 Array RPCConvertValues(const std::string &strMethod, const std::vector<std::string> &strParams)
806 {
807     Array params;
808     BOOST_FOREACH(const std::string &param, strParams)
809         params.push_back(param);
810
811     size_t n = params.size();
812
813     //
814     // Special case non-string parameter types
815     //
816     if (strMethod == "stop"                   && n > 0) ConvertTo<bool>(params[0]);
817     if (strMethod == "getaddednodeinfo"       && n > 0) ConvertTo<bool>(params[0]);
818     if (strMethod == "sendtoaddress"          && n > 1) ConvertTo<double>(params[1]);
819     if (strMethod == "mergecoins"            && n > 0) ConvertTo<double>(params[0]);
820     if (strMethod == "mergecoins"            && n > 1) ConvertTo<double>(params[1]);
821     if (strMethod == "mergecoins"            && n > 2) ConvertTo<double>(params[2]);
822     if (strMethod == "settxfee"               && n > 0) ConvertTo<double>(params[0]);
823     if (strMethod == "getreceivedbyaddress"   && n > 1) ConvertTo<int64_t>(params[1]);
824     if (strMethod == "getreceivedbyaccount"   && n > 1) ConvertTo<int64_t>(params[1]);
825     if (strMethod == "listreceivedbyaddress"  && n > 0) ConvertTo<int64_t>(params[0]);
826     if (strMethod == "listreceivedbyaddress"  && n > 1) ConvertTo<bool>(params[1]);
827     if (strMethod == "listreceivedbyaccount"  && n > 0) ConvertTo<int64_t>(params[0]);
828     if (strMethod == "listreceivedbyaccount"  && n > 1) ConvertTo<bool>(params[1]);
829     if (strMethod == "getbalance"             && n > 1) ConvertTo<int64_t>(params[1]);
830     if (strMethod == "getblock"               && n > 1) ConvertTo<bool>(params[1]);
831     if (strMethod == "getblockbynumber"       && n > 0) ConvertTo<int64_t>(params[0]);
832     if (strMethod == "dumpblockbynumber"      && n > 0) ConvertTo<int64_t>(params[0]);
833     if (strMethod == "getblockbynumber"       && n > 1) ConvertTo<bool>(params[1]);
834     if (strMethod == "getblockhash"           && n > 0) ConvertTo<int64_t>(params[0]);
835     if (strMethod == "move"                   && n > 2) ConvertTo<double>(params[2]);
836     if (strMethod == "move"                   && n > 3) ConvertTo<int64_t>(params[3]);
837     if (strMethod == "sendfrom"               && n > 2) ConvertTo<double>(params[2]);
838     if (strMethod == "sendfrom"               && n > 3) ConvertTo<int64_t>(params[3]);
839     if (strMethod == "listtransactions"       && n > 1) ConvertTo<int64_t>(params[1]);
840     if (strMethod == "listtransactions"       && n > 2) ConvertTo<int64_t>(params[2]);
841     if (strMethod == "listaccounts"           && n > 0) ConvertTo<int64_t>(params[0]);
842     if (strMethod == "walletpassphrase"       && n > 1) ConvertTo<int64_t>(params[1]);
843     if (strMethod == "walletpassphrase"       && n > 2) ConvertTo<bool>(params[2]);
844     if (strMethod == "getblocktemplate"       && n > 0) ConvertTo<Object>(params[0]);
845     if (strMethod == "listsinceblock"         && n > 1) ConvertTo<int64_t>(params[1]);
846
847     if (strMethod == "scaninput"              && n > 0) ConvertTo<Object>(params[0]);
848
849     if (strMethod == "sendalert"              && n > 2) ConvertTo<int64_t>(params[2]);
850     if (strMethod == "sendalert"              && n > 3) ConvertTo<int64_t>(params[3]);
851     if (strMethod == "sendalert"              && n > 4) ConvertTo<int64_t>(params[4]);
852     if (strMethod == "sendalert"              && n > 5) ConvertTo<int64_t>(params[5]);
853     if (strMethod == "sendalert"              && n > 6) ConvertTo<int64_t>(params[6]);
854
855     if (strMethod == "sendmany"               && n > 1) ConvertTo<Object>(params[1]);
856     if (strMethod == "sendmany"               && n > 2) ConvertTo<int64_t>(params[2]);
857     if (strMethod == "reservebalance"         && n > 0) ConvertTo<bool>(params[0]);
858     if (strMethod == "reservebalance"         && n > 1) ConvertTo<double>(params[1]);
859     if (strMethod == "addmultisigaddress"     && n > 0) ConvertTo<int64_t>(params[0]);
860     if (strMethod == "addmultisigaddress"     && n > 1) ConvertTo<Array>(params[1]);
861     if (strMethod == "listunspent"            && n > 0) ConvertTo<int64_t>(params[0]);
862     if (strMethod == "listunspent"            && n > 1) ConvertTo<int64_t>(params[1]);
863     if (strMethod == "listunspent"            && n > 2) ConvertTo<Array>(params[2]);
864     if (strMethod == "getrawtransaction"      && n > 1) ConvertTo<int64_t>(params[1]);
865     if (strMethod == "createrawtransaction"   && n > 0) ConvertTo<Array>(params[0]);
866     if (strMethod == "createrawtransaction"   && n > 1) ConvertTo<Object>(params[1]);
867     if (strMethod == "createmultisig"         && n > 0) ConvertTo<int64_t>(params[0]);
868     if (strMethod == "createmultisig"         && n > 1) ConvertTo<Array>(params[1]);
869     if (strMethod == "signrawtransaction"     && n > 1) ConvertTo<Array>(params[1], true);
870     if (strMethod == "signrawtransaction"     && n > 2) ConvertTo<Array>(params[2], true);
871     if (strMethod == "keypoolrefill"          && n > 0) ConvertTo<int64_t>(params[0]);
872     if (strMethod == "keypoolreset"           && n > 0) ConvertTo<int64_t>(params[0]);
873     if (strMethod == "importaddress"          && n > 2) ConvertTo<bool>(params[2]);
874     if (strMethod == "importprivkey"          && n > 2) ConvertTo<bool>(params[2]);
875
876     return params;
877 }
878
879 int CommandLineRPC(int argc, char *argv[])
880 {
881     string strPrint;
882     int nRet = 0;
883     try
884     {
885         // Skip switches
886         while (argc > 1 && IsSwitchChar(argv[1][0]))
887         {
888             argc--;
889             argv++;
890         }
891
892         // Method
893         if (argc < 2)
894             throw runtime_error("too few parameters");
895         string strMethod = argv[1];
896
897         // Parameters default to strings
898         std::vector<std::string> strParams(&argv[2], &argv[argc]);
899         Array params = RPCConvertValues(strMethod, strParams);
900
901         // Execute
902         Object reply = CallRPC(strMethod, params);
903
904         // Parse reply
905         const Value& result = find_value(reply, "result");
906         const Value& error  = find_value(reply, "error");
907
908         if (error.type() != null_type)
909         {
910             // Error
911             strPrint = "error: " + write_string(error, false);
912             int code = find_value(error.get_obj(), "code").get_int();
913             nRet = abs(code);
914         }
915         else
916         {
917             // Result
918             if (result.type() == null_type)
919                 strPrint.clear();
920             else if (result.type() == str_type)
921                 strPrint = result.get_str();
922             else
923                 strPrint = write_string(result, true);
924         }
925     }
926     catch (std::exception& e)
927     {
928         strPrint = string("error: ") + e.what();
929         nRet = 87;
930     }
931     catch (...)
932     {
933         PrintException(NULL, "CommandLineRPC()");
934     }
935
936     if (!strPrint.empty())
937     {
938         fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
939     }
940     return nRet;
941 }
942
943
944 const CRPCTable tableRPC;