BN_zero -> BN_set_word
[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(ix::WebSocketHttpHeaders& 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 strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"];
609     if (mapArgs["-rpcpassword"].empty())
610     {
611         unsigned char rand_pwd[32];
612         RAND_bytes(rand_pwd, 32);
613         string strWhatAmI = "To use novacoind";
614         if (mapArgs.count("-server"))
615             strWhatAmI = strprintf(_("To use the %s option"), "\"-server\"");
616         else if (mapArgs.count("-daemon"))
617             strWhatAmI = strprintf(_("To use the %s option"), "\"-daemon\"");
618         uiInterface.ThreadSafeMessageBox(strprintf(
619             _("%s, you must set a rpcpassword in the configuration file:\n %s\n"
620               "It is recommended you use the following random password:\n"
621               "rpcuser=novacoinrpc\n"
622               "rpcpassword=%s\n"
623               "(you do not need to remember this password)\n"
624               "If the file does not exist, create it with owner-readable-only file permissions.\n"),
625                 strWhatAmI.c_str(),
626                 GetConfigFile().string().c_str(),
627                 EncodeBase58(&rand_pwd[0],&rand_pwd[0]+32).c_str()),
628             _("Error"), CClientUIInterface::OK | CClientUIInterface::MODAL);
629         StartShutdown();
630         return;
631     }
632
633     string host = GetArg("-rpchost", "127.0.0.1");
634     int port = GetArg("-rpcport", GetDefaultRPCPort());
635
636     g_server = std::unique_ptr<ix::HttpServer>(new ix::HttpServer(port, host));
637
638     LOCK(cs_THREAD_RPCHANDLER);
639
640     g_server->setOnConnectionCallback([](ix::HttpRequestPtr request, std::shared_ptr<ix::ConnectionState> connectionState) -> ix::HttpResponsePtr {
641
642         ix::WebSocketHttpHeaders headers;
643         headers["Server"] = string("novacoin-json-rpc/") + FormatFullVersion();
644         headers["WWW-Authenticate"] = "Basic realm=\"jsonrpc\"";
645
646         if (!HTTPAuthorized(request->headers))
647         {
648             printf("ThreadRPCServer incorrect password attempt from %s\n", connectionState->getRemoteIp().c_str());
649             connectionState->setTerminated();
650             return std::make_shared<ix::HttpResponse>(401, "Unauthorized", ix::HttpErrorCode::Ok, headers, "Not authorized");
651         }
652
653         if (request->method != "POST") {
654             connectionState->setTerminated();
655             return std::make_shared<ix::HttpResponse>(400, "Bad request", ix::HttpErrorCode::Ok, headers, "Bad request");
656         }
657
658         JSONRequest jreq;
659
660         try
661         {
662             // Parse request
663             Value valRequest;
664             if (!read_string(request->body, valRequest))
665                 throw JSONRPCError(RPC_PARSE_ERROR, "Parse error"); 
666
667             string strReply;
668
669             // singleton request
670             if (valRequest.type() == obj_type) {
671                 jreq.parse(valRequest);
672
673                 // Execute request
674                 Value result = tableRPC.execute(jreq.strMethod, jreq.params);
675
676                 // Send reply
677                 strReply = JSONRPCReply(result, Value::null, jreq.id);
678
679             // array of requests
680             } else if (valRequest.type() == array_type)
681                 // Execute batch of requests
682                 strReply = JSONRPCExecBatch(valRequest.get_array());
683             else
684                 throw JSONRPCError(RPC_PARSE_ERROR, "Top-level object parse error");
685
686             // Send reply to client
687             return std::make_shared<ix::HttpResponse>(200, "OK", ix::HttpErrorCode::Ok, headers, strReply);
688         
689         }
690         catch(Object& objError)
691         {
692             return std::make_shared<ix::HttpResponse>(500, "Internal Server Error", ix::HttpErrorCode::Ok, headers, ErrorReply(objError, jreq.id));
693         }
694         catch(std::exception& e)
695         {
696             return std::make_shared<ix::HttpResponse>(500, "Internal Server Error", ix::HttpErrorCode::Ok, headers, ErrorReply(JSONRPCError(RPC_PARSE_ERROR, e.what()), jreq.id));
697         }
698     });
699
700     std::pair<bool, std::string> result = g_server->listen();
701     if (!result.first) {
702         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());
703         uiInterface.ThreadSafeMessageBox(strerr, _("Error"), CClientUIInterface::OK | CClientUIInterface::MODAL);
704         return StartShutdown();
705     }
706
707     // Run listening thread
708     g_server->start();
709
710     // We're listening now
711     vnThreadsRunning[THREAD_RPCLISTENER]++;
712 }
713
714 void StopRPCServer()
715 {
716     LOCK(cs_THREAD_RPCHANDLER);
717     if (g_server) g_server->stop();
718     vnThreadsRunning[THREAD_RPCLISTENER]--;
719 }
720
721 json_spirit::Value CRPCTable::execute(const std::string &strMethod, const json_spirit::Array &params) const
722 {
723     // Find method
724     const CRPCCommand *pcmd = tableRPC[strMethod];
725     if (!pcmd)
726         throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found");
727
728     // Observe safe mode
729     string strWarning = GetWarnings("rpc");
730     if (!strWarning.empty() && !GetBoolArg("-disablesafemode") &&
731         !pcmd->okSafeMode)
732         throw JSONRPCError(RPC_FORBIDDEN_BY_SAFE_MODE, string("Safe mode: ") + strWarning);
733
734     try
735     {
736         // Execute
737         Value result;
738         {
739             if (pcmd->unlocked)
740                 result = pcmd->actor(params, false);
741             else {
742                 LOCK2(cs_main, pwalletMain->cs_wallet);
743                 result = pcmd->actor(params, false);
744             }
745         }
746         return result;
747     }
748     catch (std::exception& e)
749     {
750         throw JSONRPCError(RPC_MISC_ERROR, e.what());
751     }
752 }
753
754 std::vector<std::string> CRPCTable::listCommands() const
755 {
756     std::vector<std::string> commandList;
757     typedef std::map<std::string, const CRPCCommand*> commandMap;
758
759     std::transform( mapCommands.begin(), mapCommands.end(),
760                    std::back_inserter(commandList),
761                    boost::bind(&commandMap::value_type::first,_1) );
762     return commandList;
763 }
764
765 Object CallRPC(const string& strMethod, const Array& params)
766 {
767     if (mapArgs["-rpcuser"].empty() && mapArgs["-rpcpassword"].empty())
768         throw runtime_error(strprintf(
769             _("You must set rpcpassword=<password> in the configuration file:\n%s\n"
770               "If the file does not exist, create it with owner-readable-only file permissions."),
771                 GetConfigFile().string().c_str()));
772
773     // Create HTTP client
774     ix::HttpClient httpClient;
775     ix::HttpRequestArgsPtr args = httpClient.createRequest();
776
777     // HTTP basic authentication
778     ix::WebSocketHttpHeaders mapRequestHeaders;
779     string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
780     mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64;
781     args->extraHeaders = mapRequestHeaders;
782
783     // Timeouts
784     args->connectTimeout = GetArgInt("-rpc_connecttimeout", 30000);
785     args->transferTimeout = GetArgInt("-rpc_transfertimeout", 30000);
786
787     bool fUseSSL = GetBoolArg("-rpcssl");
788     string url = string(fUseSSL ? "https://" : "http://") + GetArg("-rpcconnect", "127.0.0.1") + ":" + GetArg("-rpcport", itostr(GetDefaultRPCPort()));
789
790     // Send request
791     string strRequest = JSONRPCRequest(strMethod, params, GetRandInt(INT32_MAX));
792     auto out = httpClient.post(url, strRequest, args);
793
794     // Process reply
795     int nStatus = out->statusCode;
796     string strReply = out->body;
797     ix::WebSocketHttpHeaders mapHeaders = out->headers;
798
799     // Receive reply
800     if (nStatus == HTTP_UNAUTHORIZED)
801         throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
802     else if (nStatus >= 400 && nStatus != HTTP_BAD_REQUEST && nStatus != HTTP_NOT_FOUND && nStatus != HTTP_INTERNAL_SERVER_ERROR)
803         throw runtime_error(strprintf("server returned HTTP error %d", nStatus));
804     else if (strReply.empty())
805         throw runtime_error("no response from server");
806
807     // Parse reply
808     Value valReply;
809     if (!read_string(strReply, valReply))
810         throw runtime_error("couldn't parse reply from server");
811     const Object& reply = valReply.get_obj();
812     if (reply.empty())
813         throw runtime_error("expected reply to have result, error and id properties");
814
815     return reply;
816 }
817
818
819
820
821 template<typename T>
822 void ConvertTo(Value& value, bool fAllowNull=false)
823 {
824     if (fAllowNull && value.type() == null_type)
825         return;
826     if (value.type() == str_type)
827     {
828         // reinterpret string as unquoted json value
829         Value value2;
830         string strJSON = value.get_str();
831         if (!read_string(strJSON, value2))
832             throw runtime_error(string("Error parsing JSON:")+strJSON);
833         ConvertTo<T>(value2, fAllowNull);
834         value = value2;
835     }
836     else
837     {
838         value = value.get_value<T>();
839     }
840 }
841
842 // Convert strings to command-specific RPC representation
843 Array RPCConvertValues(const std::string &strMethod, const std::vector<std::string> &strParams)
844 {
845     Array params;
846     BOOST_FOREACH(const std::string &param, strParams)
847         params.push_back(param);
848
849     size_t n = params.size();
850
851     //
852     // Special case non-string parameter types
853     //
854     if (strMethod == "stop"                   && n > 0) ConvertTo<bool>(params[0]);
855     if (strMethod == "getaddednodeinfo"       && n > 0) ConvertTo<bool>(params[0]);
856     if (strMethod == "sendtoaddress"          && n > 1) ConvertTo<double>(params[1]);
857     if (strMethod == "mergecoins"            && n > 0) ConvertTo<double>(params[0]);
858     if (strMethod == "mergecoins"            && n > 1) ConvertTo<double>(params[1]);
859     if (strMethod == "mergecoins"            && n > 2) ConvertTo<double>(params[2]);
860     if (strMethod == "settxfee"               && n > 0) ConvertTo<double>(params[0]);
861     if (strMethod == "getreceivedbyaddress"   && n > 1) ConvertTo<int64_t>(params[1]);
862     if (strMethod == "getreceivedbyaccount"   && n > 1) ConvertTo<int64_t>(params[1]);
863     if (strMethod == "listreceivedbyaddress"  && n > 0) ConvertTo<int64_t>(params[0]);
864     if (strMethod == "listreceivedbyaddress"  && n > 1) ConvertTo<bool>(params[1]);
865     if (strMethod == "listreceivedbyaccount"  && n > 0) ConvertTo<int64_t>(params[0]);
866     if (strMethod == "listreceivedbyaccount"  && n > 1) ConvertTo<bool>(params[1]);
867     if (strMethod == "getbalance"             && n > 1) ConvertTo<int64_t>(params[1]);
868     if (strMethod == "getblock"               && n > 1) ConvertTo<bool>(params[1]);
869     if (strMethod == "getblockbynumber"       && n > 0) ConvertTo<int64_t>(params[0]);
870     if (strMethod == "dumpblockbynumber"      && n > 0) ConvertTo<int64_t>(params[0]);
871     if (strMethod == "getblockbynumber"       && n > 1) ConvertTo<bool>(params[1]);
872     if (strMethod == "getblockhash"           && n > 0) ConvertTo<int64_t>(params[0]);
873     if (strMethod == "move"                   && n > 2) ConvertTo<double>(params[2]);
874     if (strMethod == "move"                   && n > 3) ConvertTo<int64_t>(params[3]);
875     if (strMethod == "sendfrom"               && n > 2) ConvertTo<double>(params[2]);
876     if (strMethod == "sendfrom"               && n > 3) ConvertTo<int64_t>(params[3]);
877     if (strMethod == "listtransactions"       && n > 1) ConvertTo<int64_t>(params[1]);
878     if (strMethod == "listtransactions"       && n > 2) ConvertTo<int64_t>(params[2]);
879     if (strMethod == "listaccounts"           && n > 0) ConvertTo<int64_t>(params[0]);
880     if (strMethod == "walletpassphrase"       && n > 1) ConvertTo<int64_t>(params[1]);
881     if (strMethod == "walletpassphrase"       && n > 2) ConvertTo<bool>(params[2]);
882     if (strMethod == "getblocktemplate"       && n > 0) ConvertTo<Object>(params[0]);
883     if (strMethod == "listsinceblock"         && n > 1) ConvertTo<int64_t>(params[1]);
884
885     if (strMethod == "scaninput"              && n > 0) ConvertTo<Object>(params[0]);
886
887     if (strMethod == "sendalert"              && n > 2) ConvertTo<int64_t>(params[2]);
888     if (strMethod == "sendalert"              && n > 3) ConvertTo<int64_t>(params[3]);
889     if (strMethod == "sendalert"              && n > 4) ConvertTo<int64_t>(params[4]);
890     if (strMethod == "sendalert"              && n > 5) ConvertTo<int64_t>(params[5]);
891     if (strMethod == "sendalert"              && n > 6) ConvertTo<int64_t>(params[6]);
892
893     if (strMethod == "sendmany"               && n > 1) ConvertTo<Object>(params[1]);
894     if (strMethod == "sendmany"               && n > 2) ConvertTo<int64_t>(params[2]);
895     if (strMethod == "reservebalance"         && n > 0) ConvertTo<bool>(params[0]);
896     if (strMethod == "reservebalance"         && n > 1) ConvertTo<double>(params[1]);
897     if (strMethod == "addmultisigaddress"     && n > 0) ConvertTo<int64_t>(params[0]);
898     if (strMethod == "addmultisigaddress"     && n > 1) ConvertTo<Array>(params[1]);
899     if (strMethod == "listunspent"            && n > 0) ConvertTo<int64_t>(params[0]);
900     if (strMethod == "listunspent"            && n > 1) ConvertTo<int64_t>(params[1]);
901     if (strMethod == "listunspent"            && n > 2) ConvertTo<Array>(params[2]);
902     if (strMethod == "getrawtransaction"      && n > 1) ConvertTo<int64_t>(params[1]);
903     if (strMethod == "createrawtransaction"   && n > 0) ConvertTo<Array>(params[0]);
904     if (strMethod == "createrawtransaction"   && n > 1) ConvertTo<Object>(params[1]);
905     if (strMethod == "createmultisig"         && n > 0) ConvertTo<int64_t>(params[0]);
906     if (strMethod == "createmultisig"         && n > 1) ConvertTo<Array>(params[1]);
907     if (strMethod == "signrawtransaction"     && n > 1) ConvertTo<Array>(params[1], true);
908     if (strMethod == "signrawtransaction"     && n > 2) ConvertTo<Array>(params[2], true);
909     if (strMethod == "keypoolrefill"          && n > 0) ConvertTo<int64_t>(params[0]);
910     if (strMethod == "keypoolreset"           && n > 0) ConvertTo<int64_t>(params[0]);
911     if (strMethod == "importaddress"          && n > 2) ConvertTo<bool>(params[2]);
912     if (strMethod == "importprivkey"          && n > 2) ConvertTo<bool>(params[2]);
913
914     return params;
915 }
916
917 int CommandLineRPC(int argc, char *argv[])
918 {
919     string strPrint;
920     int nRet = 0;
921     try
922     {
923         // Skip switches
924         while (argc > 1 && IsSwitchChar(argv[1][0]))
925         {
926             argc--;
927             argv++;
928         }
929
930         // Method
931         if (argc < 2)
932             throw runtime_error("too few parameters");
933         string strMethod = argv[1];
934
935         // Parameters default to strings
936         std::vector<std::string> strParams(&argv[2], &argv[argc]);
937         Array params = RPCConvertValues(strMethod, strParams);
938
939         // Execute
940         Object reply = CallRPC(strMethod, params);
941
942         // Parse reply
943         const Value& result = find_value(reply, "result");
944         const Value& error  = find_value(reply, "error");
945
946         if (error.type() != null_type)
947         {
948             // Error
949             strPrint = "error: " + write_string(error, false);
950             int code = find_value(error.get_obj(), "code").get_int();
951             nRet = abs(code);
952         }
953         else
954         {
955             // Result
956             if (result.type() == null_type)
957                 strPrint.clear();
958             else if (result.type() == str_type)
959                 strPrint = result.get_str();
960             else
961                 strPrint = write_string(result, true);
962         }
963     }
964     catch (std::exception& e)
965     {
966         strPrint = string("error: ") + e.what();
967         nRet = 87;
968     }
969     catch (...)
970     {
971         PrintException(NULL, "CommandLineRPC()");
972     }
973
974     if (!strPrint.empty())
975     {
976         fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
977     }
978     return nRet;
979 }
980
981
982 const CRPCTable tableRPC;