Add paytxfee to getinfo output
[novacoin.git] / rpc.cpp
1 // Copyright (c) 2010 Satoshi Nakamoto
2 // Distributed under the MIT/X11 software license, see the accompanying
3 // file license.txt or http://www.opensource.org/licenses/mit-license.php.
4
5 #include "headers.h"
6 #undef printf
7 #include <boost/asio.hpp>
8 #include <boost/iostreams/concepts.hpp>
9 #include <boost/iostreams/stream.hpp>
10 #ifdef USE_SSL
11 #include <boost/asio/ssl.hpp> 
12 typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> SSLStream;
13 #endif
14 #include "json/json_spirit_reader_template.h"
15 #include "json/json_spirit_writer_template.h"
16 #include "json/json_spirit_utils.h"
17 #define printf OutputDebugStringF
18 // MinGW 3.4.5 gets "fatal error: had to relocate PCH" if the json headers are
19 // precompiled in headers.h.  The problem might be when the pch file goes over
20 // a certain size around 145MB.  If we need access to json_spirit outside this
21 // file, we could use the compiled json_spirit option.
22
23 using namespace boost::asio;
24 using namespace json_spirit;
25
26 void ThreadRPCServer2(void* parg);
27 typedef Value(*rpcfn_type)(const Array& params, bool fHelp);
28 extern map<string, rpcfn_type> mapCallTable;
29
30
31 Object JSONRPCError(int code, const string& message)
32 {
33     Object error;
34     error.push_back(Pair("code", code));
35     error.push_back(Pair("message", message));
36     return error;
37 }
38
39
40 void PrintConsole(const char* format, ...)
41 {
42     char buffer[50000];
43     int limit = sizeof(buffer);
44     va_list arg_ptr;
45     va_start(arg_ptr, format);
46     int ret = _vsnprintf(buffer, limit, format, arg_ptr);
47     va_end(arg_ptr);
48     if (ret < 0 || ret >= limit)
49     {
50         ret = limit - 1;
51         buffer[limit-1] = 0;
52     }
53 #if defined(__WXMSW__) && defined(GUI)
54     MyMessageBox(buffer, "Bitcoin", wxOK | wxICON_EXCLAMATION);
55 #else
56     fprintf(stdout, "%s", buffer);
57 #endif
58 }
59
60
61
62
63
64
65
66 ///
67 /// Note: This interface may still be subject to change.
68 ///
69
70
71 Value help(const Array& params, bool fHelp)
72 {
73     if (fHelp || params.size() > 1)
74         throw runtime_error(
75             "help [command]\n"
76             "List commands, or get help for a command.");
77
78     string strCommand;
79     if (params.size() > 0)
80         strCommand = params[0].get_str();
81
82     string strRet;
83     set<rpcfn_type> setDone;
84     for (map<string, rpcfn_type>::iterator mi = mapCallTable.begin(); mi != mapCallTable.end(); ++mi)
85     {
86         string strMethod = (*mi).first;
87         // We already filter duplicates, but these deprecated screw up the sort order
88         if (strMethod == "getamountreceived" ||
89             strMethod == "getallreceived")
90             continue;
91         if (strCommand != "" && strMethod != strCommand)
92             continue;
93         try
94         {
95             Array params;
96             rpcfn_type pfn = (*mi).second;
97             if (setDone.insert(pfn).second)
98                 (*pfn)(params, true);
99         }
100         catch (std::exception& e)
101         {
102             // Help text is returned in an exception
103             string strHelp = string(e.what());
104             if (strCommand == "")
105                 if (strHelp.find('\n') != -1)
106                     strHelp = strHelp.substr(0, strHelp.find('\n'));
107             strRet += strHelp + "\n";
108         }
109     }
110     if (strRet == "")
111         strRet = strprintf("help: unknown command: %s\n", strCommand.c_str());
112     strRet = strRet.substr(0,strRet.size()-1);
113     return strRet;
114 }
115
116
117 Value stop(const Array& params, bool fHelp)
118 {
119     if (fHelp || params.size() != 0)
120         throw runtime_error(
121             "stop\n"
122             "Stop bitcoin server.");
123
124     // Shutdown will take long enough that the response should get back
125     CreateThread(Shutdown, NULL);
126     return "bitcoin server stopping";
127 }
128
129
130 Value getblockcount(const Array& params, bool fHelp)
131 {
132     if (fHelp || params.size() != 0)
133         throw runtime_error(
134             "getblockcount\n"
135             "Returns the number of blocks in the longest block chain.");
136
137     return nBestHeight;
138 }
139
140
141 Value getblocknumber(const Array& params, bool fHelp)
142 {
143     if (fHelp || params.size() != 0)
144         throw runtime_error(
145             "getblocknumber\n"
146             "Returns the block number of the latest block in the longest block chain.");
147
148     return nBestHeight;
149 }
150
151
152 Value getconnectioncount(const Array& params, bool fHelp)
153 {
154     if (fHelp || params.size() != 0)
155         throw runtime_error(
156             "getconnectioncount\n"
157             "Returns the number of connections to other nodes.");
158
159     return (int)vNodes.size();
160 }
161
162
163 double GetDifficulty()
164 {
165     // Floating point number that is a multiple of the minimum difficulty,
166     // minimum difficulty = 1.0.
167     if (pindexBest == NULL)
168         return 1.0;
169     int nShift = 256 - 32 - 31; // to fit in a uint
170     double dMinimum = (CBigNum().SetCompact(bnProofOfWorkLimit.GetCompact()) >> nShift).getuint();
171     double dCurrently = (CBigNum().SetCompact(pindexBest->nBits) >> nShift).getuint();
172     return dMinimum / dCurrently;
173 }
174
175 Value getdifficulty(const Array& params, bool fHelp)
176 {
177     if (fHelp || params.size() != 0)
178         throw runtime_error(
179             "getdifficulty\n"
180             "Returns the proof-of-work difficulty as a multiple of the minimum difficulty.");
181
182     return GetDifficulty();
183 }
184
185
186 Value getbalance(const Array& params, bool fHelp)
187 {
188     if (fHelp || params.size() != 0)
189         throw runtime_error(
190             "getbalance\n"
191             "Returns the server's available balance.");
192
193     return ((double)GetBalance() / (double)COIN);
194 }
195
196
197 Value getgenerate(const Array& params, bool fHelp)
198 {
199     if (fHelp || params.size() != 0)
200         throw runtime_error(
201             "getgenerate\n"
202             "Returns true or false.");
203
204     return (bool)fGenerateBitcoins;
205 }
206
207
208 Value setgenerate(const Array& params, bool fHelp)
209 {
210     if (fHelp || params.size() < 1 || params.size() > 2)
211         throw runtime_error(
212             "setgenerate <generate> [genproclimit]\n"
213             "<generate> is true or false to turn generation on or off.\n"
214             "Generation is limited to [genproclimit] processors, -1 is unlimited.");
215
216     bool fGenerate = true;
217     if (params.size() > 0)
218         fGenerate = params[0].get_bool();
219
220     if (params.size() > 1)
221     {
222         int nGenProcLimit = params[1].get_int();
223         fLimitProcessors = (nGenProcLimit != -1);
224         CWalletDB().WriteSetting("fLimitProcessors", fLimitProcessors);
225         if (nGenProcLimit != -1)
226             CWalletDB().WriteSetting("nLimitProcessors", nLimitProcessors = nGenProcLimit);
227     }
228
229     GenerateBitcoins(fGenerate);
230     return Value::null;
231 }
232
233
234 Value gethashespersec(const Array& params, bool fHelp)
235 {
236     if (fHelp || params.size() != 0)
237         throw runtime_error(
238             "gethashespersec\n"
239             "Returns a recent hashes per second performance measurement while generating.");
240
241     if (GetTimeMillis() - nHPSTimerStart > 8000)
242         return (boost::int64_t)0;
243     return (boost::int64_t)dHashesPerSec;
244 }
245
246
247 Value getinfo(const Array& params, bool fHelp)
248 {
249     if (fHelp || params.size() != 0)
250         throw runtime_error(
251             "getinfo\n"
252             "Returns an object containing various state info.");
253
254     Object obj;
255     obj.push_back(Pair("version",       (int)VERSION));
256     obj.push_back(Pair("balance",       (double)GetBalance() / (double)COIN));
257     obj.push_back(Pair("blocks",        (int)nBestHeight));
258     obj.push_back(Pair("connections",   (int)vNodes.size()));
259     obj.push_back(Pair("proxy",         (fUseProxy ? addrProxy.ToStringIPPort() : string())));
260     obj.push_back(Pair("generate",      (bool)fGenerateBitcoins));
261     obj.push_back(Pair("genproclimit",  (int)(fLimitProcessors ? nLimitProcessors : -1)));
262     obj.push_back(Pair("difficulty",    (double)GetDifficulty()));
263     obj.push_back(Pair("hashespersec",  gethashespersec(params, false)));
264     obj.push_back(Pair("testnet",       fTestNet));
265     obj.push_back(Pair("keypoololdest", (boost::int64_t)CWalletDB().GetOldestKeyPoolTime()));
266     obj.push_back(Pair("paytxfee",      (double)nTransactionFee / (double)COIN));
267     obj.push_back(Pair("errors",        GetWarnings("statusbar")));
268     return obj;
269 }
270
271
272 Value getnewaddress(const Array& params, bool fHelp)
273 {
274     if (fHelp || params.size() > 1)
275         throw runtime_error(
276             "getnewaddress [label]\n"
277             "Returns a new bitcoin address for receiving payments.  "
278             "If [label] is specified (recommended), it is added to the address book "
279             "so payments received with the address will be labeled.");
280
281     // Parse the label first so we don't generate a key if there's an error
282     string strLabel;
283     if (params.size() > 0)
284         strLabel = params[0].get_str();
285
286     // Generate a new key that is added to wallet
287     string strAddress = PubKeyToAddress(CWalletDB().GetKeyFromKeyPool());
288
289     SetAddressBookName(strAddress, strLabel);
290     return strAddress;
291 }
292
293
294 Value setlabel(const Array& params, bool fHelp)
295 {
296     if (fHelp || params.size() < 1 || params.size() > 2)
297         throw runtime_error(
298             "setlabel <bitcoinaddress> <label>\n"
299             "Sets the label associated with the given address.");
300
301     string strAddress = params[0].get_str();
302     string strLabel;
303     if (params.size() > 1)
304         strLabel = params[1].get_str();
305
306     SetAddressBookName(strAddress, strLabel);
307     return Value::null;
308 }
309
310
311 Value getlabel(const Array& params, bool fHelp)
312 {
313     if (fHelp || params.size() != 1)
314         throw runtime_error(
315             "getlabel <bitcoinaddress>\n"
316             "Returns the label associated with the given address.");
317
318     string strAddress = params[0].get_str();
319
320     string strLabel;
321     CRITICAL_BLOCK(cs_mapAddressBook)
322     {
323         map<string, string>::iterator mi = mapAddressBook.find(strAddress);
324         if (mi != mapAddressBook.end() && !(*mi).second.empty())
325             strLabel = (*mi).second;
326     }
327     return strLabel;
328 }
329
330
331 Value getaddressesbylabel(const Array& params, bool fHelp)
332 {
333     if (fHelp || params.size() != 1)
334         throw runtime_error(
335             "getaddressesbylabel <label>\n"
336             "Returns the list of addresses with the given label.");
337
338     string strLabel = params[0].get_str();
339
340     // Find all addresses that have the given label
341     Array ret;
342     CRITICAL_BLOCK(cs_mapAddressBook)
343     {
344         foreach(const PAIRTYPE(string, string)& item, mapAddressBook)
345         {
346             const string& strAddress = item.first;
347             const string& strName = item.second;
348             if (strName == strLabel)
349             {
350                 // We're only adding valid bitcoin addresses and not ip addresses
351                 CScript scriptPubKey;
352                 if (scriptPubKey.SetBitcoinAddress(strAddress))
353                     ret.push_back(strAddress);
354             }
355         }
356     }
357     return ret;
358 }
359
360
361 Value sendtoaddress(const Array& params, bool fHelp)
362 {
363     if (fHelp || params.size() < 2 || params.size() > 4)
364         throw runtime_error(
365             "sendtoaddress <bitcoinaddress> <amount> [comment] [comment-to]\n"
366             "<amount> is a real and is rounded to the nearest 0.01");
367
368     string strAddress = params[0].get_str();
369
370     // Amount
371     if (params[1].get_real() <= 0.0 || params[1].get_real() > 21000000.0)
372         throw JSONRPCError(-3, "Invalid amount");
373     int64 nAmount = roundint64(params[1].get_real() * 100.00) * CENT;
374
375     // Wallet comments
376     CWalletTx wtx;
377     if (params.size() > 2 && params[2].type() != null_type && !params[2].get_str().empty())
378         wtx.mapValue["message"] = params[2].get_str();
379     if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
380         wtx.mapValue["to"]      = params[3].get_str();
381
382     string strError = SendMoneyToBitcoinAddress(strAddress, nAmount, wtx);
383     if (strError != "")
384         throw JSONRPCError(-4, strError);
385     return "sent";
386 }
387
388
389 Value listtransactions(const Array& params, bool fHelp)
390 {
391     if (fHelp || params.size() > 2)
392         throw runtime_error(
393             "listtransactions [count=10] [includegenerated=false]\n"
394             "Returns up to [count] most recent transactions.");
395
396     int64 nCount = 10;
397     if (params.size() > 0)
398         nCount = params[0].get_int64();
399     bool fGenerated = false;
400     if (params.size() > 1)
401         fGenerated = params[1].get_bool();
402
403     Array ret;
404     //// not finished
405     ret.push_back("not implemented yet");
406     return ret;
407 }
408
409
410 Value getreceivedbyaddress(const Array& params, bool fHelp)
411 {
412     if (fHelp || params.size() < 1 || params.size() > 2)
413         throw runtime_error(
414             "getreceivedbyaddress <bitcoinaddress> [minconf=1]\n"
415             "Returns the total amount received by <bitcoinaddress> in transactions with at least [minconf] confirmations.");
416
417     // Bitcoin address
418     string strAddress = params[0].get_str();
419     CScript scriptPubKey;
420     if (!scriptPubKey.SetBitcoinAddress(strAddress))
421         throw JSONRPCError(-5, "Invalid bitcoin address");
422     if (!IsMine(scriptPubKey))
423         return (double)0.0;
424
425     // Minimum confirmations
426     int nMinDepth = 1;
427     if (params.size() > 1)
428         nMinDepth = params[1].get_int();
429
430     // Tally
431     int64 nAmount = 0;
432     CRITICAL_BLOCK(cs_mapWallet)
433     {
434         for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
435         {
436             const CWalletTx& wtx = (*it).second;
437             if (wtx.IsCoinBase() || !wtx.IsFinal())
438                 continue;
439
440             foreach(const CTxOut& txout, wtx.vout)
441                 if (txout.scriptPubKey == scriptPubKey)
442                     if (wtx.GetDepthInMainChain() >= nMinDepth)
443                         nAmount += txout.nValue;
444         }
445     }
446
447     return (double)nAmount / (double)COIN;
448 }
449
450
451 Value getreceivedbylabel(const Array& params, bool fHelp)
452 {
453     if (fHelp || params.size() < 1 || params.size() > 2)
454         throw runtime_error(
455             "getreceivedbylabel <label> [minconf=1]\n"
456             "Returns the total amount received by addresses with <label> in transactions with at least [minconf] confirmations.");
457
458     // Get the set of pub keys that have the label
459     string strLabel = params[0].get_str();
460     set<CScript> setPubKey;
461     CRITICAL_BLOCK(cs_mapAddressBook)
462     {
463         foreach(const PAIRTYPE(string, string)& item, mapAddressBook)
464         {
465             const string& strAddress = item.first;
466             const string& strName = item.second;
467             if (strName == strLabel)
468             {
469                 // We're only counting our own valid bitcoin addresses and not ip addresses
470                 CScript scriptPubKey;
471                 if (scriptPubKey.SetBitcoinAddress(strAddress))
472                     if (IsMine(scriptPubKey))
473                         setPubKey.insert(scriptPubKey);
474             }
475         }
476     }
477
478     // Minimum confirmations
479     int nMinDepth = 1;
480     if (params.size() > 1)
481         nMinDepth = params[1].get_int();
482
483     // Tally
484     int64 nAmount = 0;
485     CRITICAL_BLOCK(cs_mapWallet)
486     {
487         for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
488         {
489             const CWalletTx& wtx = (*it).second;
490             if (wtx.IsCoinBase() || !wtx.IsFinal())
491                 continue;
492
493             foreach(const CTxOut& txout, wtx.vout)
494                 if (setPubKey.count(txout.scriptPubKey))
495                     if (wtx.GetDepthInMainChain() >= nMinDepth)
496                         nAmount += txout.nValue;
497         }
498     }
499
500     return (double)nAmount / (double)COIN;
501 }
502
503
504
505 struct tallyitem
506 {
507     int64 nAmount;
508     int nConf;
509     tallyitem()
510     {
511         nAmount = 0;
512         nConf = INT_MAX;
513     }
514 };
515
516 Value ListReceived(const Array& params, bool fByLabels)
517 {
518     // Minimum confirmations
519     int nMinDepth = 1;
520     if (params.size() > 0)
521         nMinDepth = params[0].get_int();
522
523     // Whether to include empty accounts
524     bool fIncludeEmpty = false;
525     if (params.size() > 1)
526         fIncludeEmpty = params[1].get_bool();
527
528     // Tally
529     map<uint160, tallyitem> mapTally;
530     CRITICAL_BLOCK(cs_mapWallet)
531     {
532         for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
533         {
534             const CWalletTx& wtx = (*it).second;
535             if (wtx.IsCoinBase() || !wtx.IsFinal())
536                 continue;
537
538             int nDepth = wtx.GetDepthInMainChain();
539             if (nDepth < nMinDepth)
540                 continue;
541
542             foreach(const CTxOut& txout, wtx.vout)
543             {
544                 // Only counting our own bitcoin addresses and not ip addresses
545                 uint160 hash160 = txout.scriptPubKey.GetBitcoinAddressHash160();
546                 if (hash160 == 0 || !mapPubKeys.count(hash160)) // IsMine
547                     continue;
548
549                 tallyitem& item = mapTally[hash160];
550                 item.nAmount += txout.nValue;
551                 item.nConf = min(item.nConf, nDepth);
552             }
553         }
554     }
555
556     // Reply
557     Array ret;
558     map<string, tallyitem> mapLabelTally;
559     CRITICAL_BLOCK(cs_mapAddressBook)
560     {
561         foreach(const PAIRTYPE(string, string)& item, mapAddressBook)
562         {
563             const string& strAddress = item.first;
564             const string& strLabel = item.second;
565             uint160 hash160;
566             if (!AddressToHash160(strAddress, hash160))
567                 continue;
568             map<uint160, tallyitem>::iterator it = mapTally.find(hash160);
569             if (it == mapTally.end() && !fIncludeEmpty)
570                 continue;
571
572             int64 nAmount = 0;
573             int nConf = INT_MAX;
574             if (it != mapTally.end())
575             {
576                 nAmount = (*it).second.nAmount;
577                 nConf = (*it).second.nConf;
578             }
579
580             if (fByLabels)
581             {
582                 tallyitem& item = mapLabelTally[strLabel];
583                 item.nAmount += nAmount;
584                 item.nConf = min(item.nConf, nConf);
585             }
586             else
587             {
588                 Object obj;
589                 obj.push_back(Pair("address",       strAddress));
590                 obj.push_back(Pair("label",         strLabel));
591                 obj.push_back(Pair("amount",        (double)nAmount / (double)COIN));
592                 obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf)));
593                 ret.push_back(obj);
594             }
595         }
596     }
597
598     if (fByLabels)
599     {
600         for (map<string, tallyitem>::iterator it = mapLabelTally.begin(); it != mapLabelTally.end(); ++it)
601         {
602             int64 nAmount = (*it).second.nAmount;
603             int nConf = (*it).second.nConf;
604             Object obj;
605             obj.push_back(Pair("label",         (*it).first));
606             obj.push_back(Pair("amount",        (double)nAmount / (double)COIN));
607             obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf)));
608             ret.push_back(obj);
609         }
610     }
611
612     return ret;
613 }
614
615 Value listreceivedbyaddress(const Array& params, bool fHelp)
616 {
617     if (fHelp || params.size() > 2)
618         throw runtime_error(
619             "listreceivedbyaddress [minconf=1] [includeempty=false]\n"
620             "[minconf] is the minimum number of confirmations before payments are included.\n"
621             "[includeempty] whether to include addresses that haven't received any payments.\n"
622             "Returns an array of objects containing:\n"
623             "  \"address\" : receiving address\n"
624             "  \"label\" : the label of the receiving address\n"
625             "  \"amount\" : total amount received by the address\n"
626             "  \"confirmations\" : number of confirmations of the most recent transaction included");
627
628     return ListReceived(params, false);
629 }
630
631 Value listreceivedbylabel(const Array& params, bool fHelp)
632 {
633     if (fHelp || params.size() > 2)
634         throw runtime_error(
635             "listreceivedbylabel [minconf=1] [includeempty=false]\n"
636             "[minconf] is the minimum number of confirmations before payments are included.\n"
637             "[includeempty] whether to include labels that haven't received any payments.\n"
638             "Returns an array of objects containing:\n"
639             "  \"label\" : the label of the receiving addresses\n"
640             "  \"amount\" : total amount received by addresses with this label\n"
641             "  \"confirmations\" : number of confirmations of the most recent transaction included");
642
643     return ListReceived(params, true);
644 }
645
646
647 Value backupwallet(const Array& params, bool fHelp)
648 {
649     if (fHelp || params.size() != 1)
650         throw runtime_error(
651             "backupwallet <destination>\n"
652             "Safely copies wallet.dat to destination, which can be a directory or a path with filename.");
653
654     string strDest = params[0].get_str();
655     BackupWallet(strDest);
656
657     return Value::null;
658 }
659
660
661 Value validateaddress(const Array& params, bool fHelp)
662 {
663     if (fHelp || params.size() != 1)
664         throw runtime_error(
665             "validateaddress <bitcoinaddress>\n"
666             "Return information about <bitcoinaddress>.");
667
668     string strAddress = params[0].get_str();
669     uint160 hash160;
670     bool isValid = AddressToHash160(strAddress, hash160);
671
672     Object ret;
673     ret.push_back(Pair("isvalid", isValid));
674     if (isValid)
675     {
676         // Call Hash160ToAddress() so we always return current ADDRESSVERSION
677         // version of the address:
678         ret.push_back(Pair("address", Hash160ToAddress(hash160)));
679         ret.push_back(Pair("ismine", (mapPubKeys.count(hash160) > 0)));
680     }
681     return ret;
682 }
683
684
685
686
687
688
689
690
691
692
693
694 //
695 // Call Table
696 //
697
698 pair<string, rpcfn_type> pCallTable[] =
699 {
700     make_pair("help",                  &help),
701     make_pair("stop",                  &stop),
702     make_pair("getblockcount",         &getblockcount),
703     make_pair("getblocknumber",        &getblocknumber),
704     make_pair("getconnectioncount",    &getconnectioncount),
705     make_pair("getdifficulty",         &getdifficulty),
706     make_pair("getbalance",            &getbalance),
707     make_pair("getgenerate",           &getgenerate),
708     make_pair("setgenerate",           &setgenerate),
709     make_pair("gethashespersec",       &gethashespersec),
710     make_pair("getinfo",               &getinfo),
711     make_pair("getnewaddress",         &getnewaddress),
712     make_pair("setlabel",              &setlabel),
713     make_pair("getlabel",              &getlabel),
714     make_pair("getaddressesbylabel",   &getaddressesbylabel),
715     make_pair("sendtoaddress",         &sendtoaddress),
716     make_pair("getamountreceived",     &getreceivedbyaddress), // deprecated, renamed to getreceivedbyaddress
717     make_pair("getallreceived",        &listreceivedbyaddress), // deprecated, renamed to listreceivedbyaddress
718     make_pair("getreceivedbyaddress",  &getreceivedbyaddress),
719     make_pair("getreceivedbylabel",    &getreceivedbylabel),
720     make_pair("listreceivedbyaddress", &listreceivedbyaddress),
721     make_pair("listreceivedbylabel",   &listreceivedbylabel),
722     make_pair("backupwallet",          &backupwallet),
723     make_pair("validateaddress",       &validateaddress),
724 };
725 map<string, rpcfn_type> mapCallTable(pCallTable, pCallTable + sizeof(pCallTable)/sizeof(pCallTable[0]));
726
727 string pAllowInSafeMode[] =
728 {
729     "help",
730     "stop",
731     "getblockcount",
732     "getblocknumber",
733     "getconnectioncount",
734     "getdifficulty",
735     "getgenerate",
736     "setgenerate",
737     "gethashespersec",
738     "getinfo",
739     "getnewaddress",
740     "setlabel",
741     "getlabel",
742     "getaddressesbylabel",
743     "backupwallet",
744     "validateaddress",
745 };
746 set<string> setAllowInSafeMode(pAllowInSafeMode, pAllowInSafeMode + sizeof(pAllowInSafeMode)/sizeof(pAllowInSafeMode[0]));
747
748
749
750
751 //
752 // HTTP protocol
753 //
754 // This ain't Apache.  We're just using HTTP header for the length field
755 // and to be compatible with other JSON-RPC implementations.
756 //
757
758 string HTTPPost(const string& strMsg, const map<string,string>& mapRequestHeaders)
759 {
760     ostringstream s;
761     s << "POST / HTTP/1.1\r\n"
762       << "User-Agent: json-rpc/1.0\r\n"
763       << "Host: 127.0.0.1\r\n"
764       << "Content-Type: application/json\r\n"
765       << "Content-Length: " << strMsg.size() << "\r\n"
766       << "Accept: application/json\r\n";
767     foreach(const PAIRTYPE(string, string)& item, mapRequestHeaders)
768         s << item.first << ": " << item.second << "\r\n";
769     s << "\r\n" << strMsg;
770
771     return s.str();
772 }
773
774 string rfc1123Time()
775 {
776     char buffer[32];
777     time_t now;
778     time(&now);
779     struct tm* now_gmt = gmtime(&now);
780     strftime(buffer, sizeof(buffer), "%a, %d %b %Y %H:%M:%S %Z", now_gmt);
781     return string(buffer);
782 }
783
784 string HTTPReply(int nStatus, const string& strMsg)
785 {
786     if (nStatus == 401)
787         return strprintf("HTTP/1.0 401 Authorization Required\r\n"
788             "Date: %s\r\n"
789             "Server: bitcoin-json-rpc\r\n"
790             "WWW-Authenticate: Basic realm=\"jsonrpc\"\r\n"
791             "Content-Type: text/html\r\n"
792             "Content-Length: 311\r\n"
793             "\r\n"
794             "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\r\n"
795             "\"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd\">\r\n"
796             "<HTML>\r\n"
797             "<HEAD>\r\n"
798             "<TITLE>Error</TITLE>\r\n"
799             "<META HTTP-EQUIV='Content-Type' CONTENT='text/html; charset=ISO-8859-1'>\r\n"
800             "</HEAD>\r\n"
801             "<BODY><H1>401 Unauthorized.</H1></BODY>\r\n"
802             "</HTML>\r\n", rfc1123Time().c_str());
803     string strStatus;
804          if (nStatus == 200) strStatus = "OK";
805     else if (nStatus == 400) strStatus = "Bad Request";
806     else if (nStatus == 404) strStatus = "Not Found";
807     else if (nStatus == 500) strStatus = "Internal Server Error";
808     return strprintf(
809             "HTTP/1.1 %d %s\r\n"
810             "Date: %s\r\n"
811             "Connection: close\r\n"
812             "Content-Length: %d\r\n"
813             "Content-Type: application/json\r\n"
814             "Server: bitcoin-json-rpc/1.0\r\n"
815             "\r\n"
816             "%s",
817         nStatus,
818         strStatus.c_str(),
819         rfc1123Time().c_str(),
820         strMsg.size(),
821         strMsg.c_str());
822 }
823
824 int ReadHTTPStatus(std::basic_istream<char>& stream)
825 {
826     string str;
827     getline(stream, str);
828     vector<string> vWords;
829     boost::split(vWords, str, boost::is_any_of(" "));
830     if (vWords.size() < 2)
831         return 500;
832     return atoi(vWords[1].c_str());
833 }
834
835 int ReadHTTPHeader(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet)
836 {
837     int nLen = 0;
838     loop
839     {
840         string str;
841         std::getline(stream, str);
842         if (str.empty() || str == "\r")
843             break;
844         string::size_type nColon = str.find(":");
845         if (nColon != string::npos)
846         {
847             string strHeader = str.substr(0, nColon);
848             boost::trim(strHeader);
849             string strValue = str.substr(nColon+1);
850             boost::trim(strValue);
851             mapHeadersRet[strHeader] = strValue;
852             if (strHeader == "Content-Length")
853                 nLen = atoi(strValue.c_str());
854         }
855     }
856     return nLen;
857 }
858
859 int ReadHTTP(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet, string& strMessageRet)
860 {
861     mapHeadersRet.clear();
862     strMessageRet = "";
863
864     // Read status
865     int nStatus = ReadHTTPStatus(stream);
866
867     // Read header
868     int nLen = ReadHTTPHeader(stream, mapHeadersRet);
869     if (nLen < 0 || nLen > MAX_SIZE)
870         return 500;
871
872     // Read message
873     if (nLen > 0)
874     {
875         vector<char> vch(nLen);
876         stream.read(&vch[0], nLen);
877         strMessageRet = string(vch.begin(), vch.end());
878     }
879
880     return nStatus;
881 }
882
883 string EncodeBase64(string s)
884 {
885     BIO *b64, *bmem;
886     BUF_MEM *bptr;
887
888     b64 = BIO_new(BIO_f_base64());
889     BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
890     bmem = BIO_new(BIO_s_mem());
891     b64 = BIO_push(b64, bmem);
892     BIO_write(b64, s.c_str(), s.size());
893     BIO_flush(b64);
894     BIO_get_mem_ptr(b64, &bptr);
895
896     string result(bptr->data, bptr->length);
897     BIO_free_all(b64);
898
899     return result;
900 }
901
902 string DecodeBase64(string s)
903 {
904     BIO *b64, *bmem;
905
906     char* buffer = static_cast<char*>(calloc(s.size(), sizeof(char)));
907
908     b64 = BIO_new(BIO_f_base64());
909     BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
910     bmem = BIO_new_mem_buf(const_cast<char*>(s.c_str()), s.size());
911     bmem = BIO_push(b64, bmem);
912     BIO_read(bmem, buffer, s.size());
913     BIO_free_all(bmem);
914
915     string result(buffer);
916     free(buffer);
917     return result;
918 }
919
920 bool HTTPAuthorized(map<string, string>& mapHeaders)
921 {
922     string strAuth = mapHeaders["Authorization"];
923     if (strAuth.substr(0,6) != "Basic ")
924         return false;
925     string strUserPass64 = strAuth.substr(6); boost::trim(strUserPass64);
926     string strUserPass = DecodeBase64(strUserPass64);
927     string::size_type nColon = strUserPass.find(":");
928     if (nColon == string::npos)
929         return false;
930     string strUser = strUserPass.substr(0, nColon);
931     string strPassword = strUserPass.substr(nColon+1);
932     return (strUser == mapArgs["-rpcuser"] && strPassword == mapArgs["-rpcpassword"]);
933 }
934
935 //
936 // JSON-RPC protocol.  Bitcoin speaks version 1.0 for maximum compatibility,
937 // but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
938 // unspecified (HTTP errors and contents of 'error').
939 //
940 // 1.0 spec: http://json-rpc.org/wiki/specification
941 // 1.2 spec: http://groups.google.com/group/json-rpc/web/json-rpc-over-http
942 // http://www.codeproject.com/KB/recipes/JSON_Spirit.aspx
943 //
944
945 string JSONRPCRequest(const string& strMethod, const Array& params, const Value& id)
946 {
947     Object request;
948     request.push_back(Pair("method", strMethod));
949     request.push_back(Pair("params", params));
950     request.push_back(Pair("id", id));
951     return write_string(Value(request), false) + "\n";
952 }
953
954 string JSONRPCReply(const Value& result, const Value& error, const Value& id)
955 {
956     Object reply;
957     if (error.type() != null_type)
958         reply.push_back(Pair("result", Value::null));
959     else
960         reply.push_back(Pair("result", result));
961     reply.push_back(Pair("error", error));
962     reply.push_back(Pair("id", id));
963     return write_string(Value(reply), false) + "\n";
964 }
965
966 bool ClientAllowed(const string& strAddress)
967 {
968     if (strAddress == asio::ip::address_v4::loopback().to_string())
969         return true;
970     const vector<string>& vAllow = mapMultiArgs["-rpcallowip"];
971     foreach(string strAllow, vAllow)
972         if (WildcardMatch(strAddress, strAllow))
973             return true;
974     return false;
975 }
976
977 #ifdef USE_SSL
978 //
979 // IOStream device that speaks SSL but can also speak non-SSL
980 //
981 class SSLIOStreamDevice : public iostreams::device<iostreams::bidirectional> {
982 public:
983     SSLIOStreamDevice(SSLStream &streamIn, bool fUseSSLIn) : stream(streamIn)
984     {
985         fUseSSL = fUseSSLIn;
986         fNeedHandshake = fUseSSLIn;
987     }
988
989     void handshake(ssl::stream_base::handshake_type role)
990     {
991         if (!fNeedHandshake) return;
992         fNeedHandshake = false;
993         stream.handshake(role);
994     }
995     std::streamsize read(char* s, std::streamsize n)
996     {
997         handshake(ssl::stream_base::server); // HTTPS servers read first
998         if (fUseSSL) return stream.read_some(asio::buffer(s, n));
999         return stream.next_layer().read_some(asio::buffer(s, n));
1000     }
1001     std::streamsize write(const char* s, std::streamsize n)
1002     {
1003         handshake(ssl::stream_base::client); // HTTPS clients write first
1004         if (fUseSSL) return asio::write(stream, asio::buffer(s, n));
1005         return asio::write(stream.next_layer(), asio::buffer(s, n));
1006     }
1007     bool connect(const std::string& server, const std::string& port)
1008     {
1009         ip::tcp::resolver resolver(stream.get_io_service());
1010         ip::tcp::resolver::query query(server.c_str(), port.c_str());
1011         ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
1012         ip::tcp::resolver::iterator end;
1013         boost::system::error_code error = asio::error::host_not_found;
1014         while (error && endpoint_iterator != end)
1015         {
1016             stream.lowest_layer().close();
1017             stream.lowest_layer().connect(*endpoint_iterator++, error);
1018         }
1019         if (error)
1020             return false;
1021         return true;
1022     }
1023
1024 private:
1025     bool fNeedHandshake;
1026     bool fUseSSL;
1027     SSLStream& stream;
1028 };
1029 #endif
1030
1031 void ThreadRPCServer(void* parg)
1032 {
1033     IMPLEMENT_RANDOMIZE_STACK(ThreadRPCServer(parg));
1034     try
1035     {
1036         vnThreadsRunning[4]++;
1037         ThreadRPCServer2(parg);
1038         vnThreadsRunning[4]--;
1039     }
1040     catch (std::exception& e) {
1041         vnThreadsRunning[4]--;
1042         PrintException(&e, "ThreadRPCServer()");
1043     } catch (...) {
1044         vnThreadsRunning[4]--;
1045         PrintException(NULL, "ThreadRPCServer()");
1046     }
1047     printf("ThreadRPCServer exiting\n");
1048 }
1049
1050 void ThreadRPCServer2(void* parg)
1051 {
1052     printf("ThreadRPCServer started\n");
1053
1054     if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
1055     {
1056         string strWhatAmI = "To use bitcoind";
1057         if (mapArgs.count("-server"))
1058             strWhatAmI = strprintf(_("To use the %s option"), "\"-server\"");
1059         else if (mapArgs.count("-daemon"))
1060             strWhatAmI = strprintf(_("To use the %s option"), "\"-daemon\"");
1061         PrintConsole(
1062             _("Warning: %s, you must set rpcpassword=<password>\nin the configuration file: %s\n"
1063               "If the file does not exist, create it with owner-readable-only file permissions.\n"),
1064                 strWhatAmI.c_str(),
1065                 GetConfigFile().c_str());
1066         CreateThread(Shutdown, NULL);
1067         return;
1068     }
1069
1070     bool fUseSSL = (mapArgs.count("-rpcssl") > 0);
1071     asio::ip::address bindAddress = mapArgs.count("-rpcallowip") ? asio::ip::address_v4::any() : asio::ip::address_v4::loopback();
1072
1073     asio::io_service io_service;
1074     ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", 8332));
1075     ip::tcp::acceptor acceptor(io_service, endpoint);
1076
1077 #ifdef USE_SSL
1078     ssl::context context(io_service, ssl::context::sslv23);
1079     if (fUseSSL)
1080     {
1081         context.set_options(ssl::context::no_sslv2);
1082         filesystem::path certfile = GetArg("-rpcsslcertificatechainfile", "server.cert");
1083         if (!certfile.is_complete()) certfile = filesystem::path(GetDataDir()) / certfile;
1084         if (filesystem::exists(certfile)) context.use_certificate_chain_file(certfile.string().c_str());
1085         else printf("ThreadRPCServer ERROR: missing server certificate file %s\n", certfile.string().c_str());
1086         filesystem::path pkfile = GetArg("-rpcsslprivatekeyfile", "server.pem");
1087         if (!pkfile.is_complete()) pkfile = filesystem::path(GetDataDir()) / pkfile;
1088         if (filesystem::exists(pkfile)) context.use_private_key_file(pkfile.string().c_str(), ssl::context::pem);
1089         else printf("ThreadRPCServer ERROR: missing server private key file %s\n", pkfile.string().c_str());
1090
1091         string ciphers = GetArg("-rpcsslciphers",
1092                                          "TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH");
1093         SSL_CTX_set_cipher_list(context.impl(), ciphers.c_str());
1094     }
1095 #else
1096     if (fUseSSL)
1097         throw runtime_error("-rpcssl=true, but bitcoin compiled without full openssl libraries.");
1098 #endif
1099
1100     loop
1101     {
1102         // Accept connection
1103 #ifdef USE_SSL
1104         SSLStream sslStream(io_service, context);
1105         SSLIOStreamDevice d(sslStream, fUseSSL);
1106         iostreams::stream<SSLIOStreamDevice> stream(d);
1107 #else
1108         ip::tcp::iostream stream;
1109 #endif
1110
1111         ip::tcp::endpoint peer;
1112         vnThreadsRunning[4]--;
1113 #ifdef USE_SSL
1114         acceptor.accept(sslStream.lowest_layer(), peer);
1115 #else
1116         acceptor.accept(*stream.rdbuf(), peer);
1117 #endif
1118         vnThreadsRunning[4]++;
1119         if (fShutdown)
1120             return;
1121
1122         // Restrict callers by IP
1123         if (!ClientAllowed(peer.address().to_string()))
1124             continue;
1125
1126         // Receive request
1127         map<string, string> mapHeaders;
1128         string strRequest;
1129         ReadHTTP(stream, mapHeaders, strRequest);
1130
1131         // Check authorization
1132         if (mapHeaders.count("Authorization") == 0)
1133         {
1134             stream << HTTPReply(401, "") << std::flush;
1135             continue;
1136         }
1137         if (!HTTPAuthorized(mapHeaders))
1138         {
1139             // Deter brute-forcing short passwords
1140             if (mapArgs["-rpcpassword"].size() < 15)
1141                 Sleep(50);
1142
1143             stream << HTTPReply(401, "") << std::flush;
1144             printf("ThreadRPCServer incorrect password attempt\n");
1145             continue;
1146         }
1147
1148         Value id = Value::null;
1149         try
1150         {
1151             // Parse request
1152             Value valRequest;
1153             if (!read_string(strRequest, valRequest) || valRequest.type() != obj_type)
1154                 throw JSONRPCError(-32700, "Parse error");
1155             const Object& request = valRequest.get_obj();
1156
1157             // Parse id now so errors from here on will have the id
1158             id = find_value(request, "id");
1159
1160             // Parse method
1161             Value valMethod = find_value(request, "method");
1162             if (valMethod.type() == null_type)
1163                 throw JSONRPCError(-32600, "Missing method");
1164             if (valMethod.type() != str_type)
1165                 throw JSONRPCError(-32600, "Method must be a string");
1166             string strMethod = valMethod.get_str();
1167             printf("ThreadRPCServer method=%s\n", strMethod.c_str());
1168
1169             // Parse params
1170             Value valParams = find_value(request, "params");
1171             Array params;
1172             if (valParams.type() == array_type)
1173                 params = valParams.get_array();
1174             else if (valParams.type() == null_type)
1175                 params = Array();
1176             else
1177                 throw JSONRPCError(-32600, "Params must be an array");
1178
1179             // Find method
1180             map<string, rpcfn_type>::iterator mi = mapCallTable.find(strMethod);
1181             if (mi == mapCallTable.end())
1182                 throw JSONRPCError(-32601, "Method not found");
1183
1184             // Observe safe mode
1185             string strWarning = GetWarnings("rpc");
1186             if (strWarning != "" && !mapArgs.count("-disablesafemode") && !setAllowInSafeMode.count(strMethod))
1187                 throw JSONRPCError(-2, string("Safe mode: ") + strWarning);
1188
1189             try
1190             {
1191                 // Execute
1192                 Value result = (*(*mi).second)(params, false);
1193
1194                 // Send reply
1195                 string strReply = JSONRPCReply(result, Value::null, id);
1196                 stream << HTTPReply(200, strReply) << std::flush;
1197             }
1198             catch (std::exception& e)
1199             {
1200                 // Send error reply from method
1201                 string strReply = JSONRPCReply(Value::null, JSONRPCError(-1, e.what()), id);
1202                 stream << HTTPReply(500, strReply) << std::flush;
1203             }
1204         }
1205         catch (Object& objError)
1206         {
1207             // Send error reply from json-rpc error object
1208             int nStatus = 500;
1209             int code = find_value(objError, "code").get_int();
1210             if (code == -32600) nStatus = 400;
1211             else if (code == -32601) nStatus = 404;
1212             string strReply = JSONRPCReply(Value::null, objError, id);
1213             stream << HTTPReply(nStatus, strReply) << std::flush;
1214         }
1215         catch (std::exception& e)
1216         {
1217             // Send error reply from other json-rpc parsing errors
1218             string strReply = JSONRPCReply(Value::null, JSONRPCError(-32700, e.what()), id);
1219             stream << HTTPReply(500, strReply) << std::flush;
1220         }
1221     }
1222 }
1223
1224
1225
1226
1227 Object CallRPC(const string& strMethod, const Array& params)
1228 {
1229     if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
1230         throw runtime_error(strprintf(
1231             _("You must set rpcpassword=<password> in the configuration file:\n%s\n"
1232               "If the file does not exist, create it with owner-readable-only file permissions."),
1233                 GetConfigFile().c_str()));
1234
1235     // Connect to localhost
1236     bool fUseSSL = (mapArgs.count("-rpcssl") > 0);
1237 #ifdef USE_SSL
1238     asio::io_service io_service;
1239     ssl::context context(io_service, ssl::context::sslv23);
1240     context.set_options(ssl::context::no_sslv2);
1241     SSLStream sslStream(io_service, context);
1242     SSLIOStreamDevice d(sslStream, fUseSSL);
1243     iostreams::stream<SSLIOStreamDevice> stream(d);
1244     if (!d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332")))
1245         throw runtime_error("couldn't connect to server");
1246 #else
1247     if (fUseSSL)
1248         throw runtime_error("-rpcssl=true, but bitcoin compiled without full openssl libraries.");
1249
1250     ip::tcp::iostream stream(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332"));
1251     if (stream.fail())
1252         throw runtime_error("couldn't connect to server");
1253 #endif
1254
1255
1256     // HTTP basic authentication
1257     string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
1258     map<string, string> mapRequestHeaders;
1259     mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64;
1260
1261     // Send request
1262     string strRequest = JSONRPCRequest(strMethod, params, 1);
1263     string strPost = HTTPPost(strRequest, mapRequestHeaders);
1264     stream << strPost << std::flush;
1265
1266     // Receive reply
1267     map<string, string> mapHeaders;
1268     string strReply;
1269     int nStatus = ReadHTTP(stream, mapHeaders, strReply);
1270     if (nStatus == 401)
1271         throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
1272     else if (nStatus >= 400 && nStatus != 400 && nStatus != 404 && nStatus != 500)
1273         throw runtime_error(strprintf("server returned HTTP error %d", nStatus));
1274     else if (strReply.empty())
1275         throw runtime_error("no response from server");
1276
1277     // Parse reply
1278     Value valReply;
1279     if (!read_string(strReply, valReply))
1280         throw runtime_error("couldn't parse reply from server");
1281     const Object& reply = valReply.get_obj();
1282     if (reply.empty())
1283         throw runtime_error("expected reply to have result, error and id properties");
1284
1285     return reply;
1286 }
1287
1288
1289
1290
1291 template<typename T>
1292 void ConvertTo(Value& value)
1293 {
1294     if (value.type() == str_type)
1295     {
1296         // reinterpret string as unquoted json value
1297         Value value2;
1298         if (!read_string(value.get_str(), value2))
1299             throw runtime_error("type mismatch");
1300         value = value2.get_value<T>();
1301     }
1302     else
1303     {
1304         value = value.get_value<T>();
1305     }
1306 }
1307
1308 int CommandLineRPC(int argc, char *argv[])
1309 {
1310     string strPrint;
1311     int nRet = 0;
1312     try
1313     {
1314         // Skip switches
1315         while (argc > 1 && IsSwitchChar(argv[1][0]))
1316         {
1317             argc--;
1318             argv++;
1319         }
1320
1321         // Method
1322         if (argc < 2)
1323             throw runtime_error("too few parameters");
1324         string strMethod = argv[1];
1325
1326         // Parameters default to strings
1327         Array params;
1328         for (int i = 2; i < argc; i++)
1329             params.push_back(argv[i]);
1330         int n = params.size();
1331
1332         //
1333         // Special case non-string parameter types
1334         //
1335         if (strMethod == "setgenerate"            && n > 0) ConvertTo<bool>(params[0]);
1336         if (strMethod == "setgenerate"            && n > 1) ConvertTo<boost::int64_t>(params[1]);
1337         if (strMethod == "sendtoaddress"          && n > 1) ConvertTo<double>(params[1]);
1338         if (strMethod == "listtransactions"       && n > 0) ConvertTo<boost::int64_t>(params[0]);
1339         if (strMethod == "listtransactions"       && n > 1) ConvertTo<bool>(params[1]);
1340         if (strMethod == "getamountreceived"      && n > 1) ConvertTo<boost::int64_t>(params[1]); // deprecated
1341         if (strMethod == "getreceivedbyaddress"   && n > 1) ConvertTo<boost::int64_t>(params[1]);
1342         if (strMethod == "getreceivedbylabel"     && n > 1) ConvertTo<boost::int64_t>(params[1]);
1343         if (strMethod == "getallreceived"         && n > 0) ConvertTo<boost::int64_t>(params[0]); // deprecated
1344         if (strMethod == "getallreceived"         && n > 1) ConvertTo<bool>(params[1]);
1345         if (strMethod == "listreceivedbyaddress"  && n > 0) ConvertTo<boost::int64_t>(params[0]);
1346         if (strMethod == "listreceivedbyaddress"  && n > 1) ConvertTo<bool>(params[1]);
1347         if (strMethod == "listreceivedbylabel"    && n > 0) ConvertTo<boost::int64_t>(params[0]);
1348         if (strMethod == "listreceivedbylabel"    && n > 1) ConvertTo<bool>(params[1]);
1349
1350         // Execute
1351         Object reply = CallRPC(strMethod, params);
1352
1353         // Parse reply
1354         const Value& result = find_value(reply, "result");
1355         const Value& error  = find_value(reply, "error");
1356         const Value& id     = find_value(reply, "id");
1357
1358         if (error.type() != null_type)
1359         {
1360             // Error
1361             strPrint = "error: " + write_string(error, false);
1362             int code = find_value(error.get_obj(), "code").get_int();
1363             nRet = abs(code);
1364         }
1365         else
1366         {
1367             // Result
1368             if (result.type() == null_type)
1369                 strPrint = "";
1370             else if (result.type() == str_type)
1371                 strPrint = result.get_str();
1372             else
1373                 strPrint = write_string(result, true);
1374         }
1375     }
1376     catch (std::exception& e)
1377     {
1378         strPrint = string("error: ") + e.what();
1379         nRet = 87;
1380     }
1381     catch (...)
1382     {
1383         PrintException(NULL, "CommandLineRPC()");
1384     }
1385
1386     if (strPrint != "")
1387     {
1388 #if defined(__WXMSW__) && defined(GUI)
1389         // Windows GUI apps can't print to command line,
1390         // so settle for a message box yuck
1391         MyMessageBox(strPrint, "Bitcoin", wxOK);
1392 #else
1393         fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
1394 #endif
1395     }
1396     return nRet;
1397 }
1398
1399
1400
1401
1402 #ifdef TEST
1403 int main(int argc, char *argv[])
1404 {
1405 #ifdef _MSC_VER
1406     // Turn off microsoft heap dump noise
1407     _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
1408     _CrtSetReportFile(_CRT_WARN, CreateFile("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0));
1409 #endif
1410     setbuf(stdin, NULL);
1411     setbuf(stdout, NULL);
1412     setbuf(stderr, NULL);
1413
1414     try
1415     {
1416         if (argc >= 2 && string(argv[1]) == "-server")
1417         {
1418             printf("server ready\n");
1419             ThreadRPCServer(NULL);
1420         }
1421         else
1422         {
1423             return CommandLineRPC(argc, argv);
1424         }
1425     }
1426     catch (std::exception& e) {
1427         PrintException(&e, "main()");
1428     } catch (...) {
1429         PrintException(NULL, "main()");
1430     }
1431     return 0;
1432 }
1433 #endif