1f05fa8628518953865aeadd30b954e7fc725ac7
[novacoin.git] / src / bitcoinrpc.cpp
1 // Copyright (c) 2010 Satoshi Nakamoto
2 // Copyright (c) 2011 The Bitcoin developers
3 // Distributed under the MIT/X11 software license, see the accompanying
4 // file license.txt or http://www.opensource.org/licenses/mit-license.php.
5
6 #include "headers.h"
7 #include "db.h"
8 #include "net.h"
9 #include "init.h"
10 #undef printf
11 #include <boost/asio.hpp>
12 #include <boost/filesystem.hpp>
13 #include <boost/iostreams/concepts.hpp>
14 #include <boost/iostreams/stream.hpp>
15 #include <boost/algorithm/string.hpp>
16 #include <boost/lexical_cast.hpp>
17 #ifdef USE_SSL
18 #include <boost/asio/ssl.hpp> 
19 #include <boost/filesystem.hpp>
20 #include <boost/filesystem/fstream.hpp>
21 typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> SSLStream;
22 #endif
23 #include "json/json_spirit_reader_template.h"
24 #include "json/json_spirit_writer_template.h"
25 #include "json/json_spirit_utils.h"
26 #define printf OutputDebugStringF
27 // MinGW 3.4.5 gets "fatal error: had to relocate PCH" if the json headers are
28 // precompiled in headers.h.  The problem might be when the pch file goes over
29 // a certain size around 145MB.  If we need access to json_spirit outside this
30 // file, we could use the compiled json_spirit option.
31
32 using namespace std;
33 using namespace boost;
34 using namespace boost::asio;
35 using namespace json_spirit;
36
37 void ThreadRPCServer2(void* parg);
38 typedef Value(*rpcfn_type)(const Array& params, bool fHelp);
39 extern map<string, rpcfn_type> mapCallTable;
40
41 static std::string strRPCUserColonPass;
42
43 static int64 nWalletUnlockTime;
44 static CCriticalSection cs_nWalletUnlockTime;
45
46 extern Value dumpprivkey(const Array& params, bool fHelp);
47 extern Value importprivkey(const Array& params, bool fHelp);
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
58 void PrintConsole(const std::string &format, ...)
59 {
60     char buffer[50000];
61     int limit = sizeof(buffer);
62     va_list arg_ptr;
63     va_start(arg_ptr, format);
64     int ret = _vsnprintf(buffer, limit, format.c_str(), arg_ptr);
65     va_end(arg_ptr);
66     if (ret < 0 || ret >= limit)
67     {
68         ret = limit - 1;
69         buffer[limit-1] = 0;
70     }
71     printf("%s", buffer);
72     fprintf(stdout, "%s", buffer);
73 }
74
75
76 int64 AmountFromValue(const Value& value)
77 {
78     double dAmount = value.get_real();
79     if (dAmount <= 0.0 || dAmount > 21000000.0)
80         throw JSONRPCError(-3, "Invalid amount");
81     int64 nAmount = roundint64(dAmount * COIN);
82     if (!MoneyRange(nAmount))
83         throw JSONRPCError(-3, "Invalid amount");
84     return nAmount;
85 }
86
87 Value ValueFromAmount(int64 amount)
88 {
89     return (double)amount / (double)COIN;
90 }
91
92 void WalletTxToJSON(const CWalletTx& wtx, Object& entry)
93 {
94     entry.push_back(Pair("confirmations", wtx.GetDepthInMainChain()));
95     entry.push_back(Pair("txid", wtx.GetHash().GetHex()));
96     entry.push_back(Pair("time", (boost::int64_t)wtx.GetTxTime()));
97     BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue)
98         entry.push_back(Pair(item.first, item.second));
99 }
100
101 string AccountFromValue(const Value& value)
102 {
103     string strAccount = value.get_str();
104     if (strAccount == "*")
105         throw JSONRPCError(-11, "Invalid account name");
106     return strAccount;
107 }
108
109
110
111 ///
112 /// Note: This interface may still be subject to change.
113 ///
114
115
116 Value help(const Array& params, bool fHelp)
117 {
118     if (fHelp || params.size() > 1)
119         throw runtime_error(
120             "help [command]\n"
121             "List commands, or get help for a command.");
122
123     string strCommand;
124     if (params.size() > 0)
125         strCommand = params[0].get_str();
126
127     string strRet;
128     set<rpcfn_type> setDone;
129     for (map<string, rpcfn_type>::iterator mi = mapCallTable.begin(); mi != mapCallTable.end(); ++mi)
130     {
131         string strMethod = (*mi).first;
132         // We already filter duplicates, but these deprecated screw up the sort order
133         if (strMethod == "getamountreceived" ||
134             strMethod == "getallreceived" ||
135             strMethod == "getblocknumber" || // deprecated
136             (strMethod.find("label") != string::npos))
137             continue;
138         if (strCommand != "" && strMethod != strCommand)
139             continue;
140         try
141         {
142             Array params;
143             rpcfn_type pfn = (*mi).second;
144             if (setDone.insert(pfn).second)
145                 (*pfn)(params, true);
146         }
147         catch (std::exception& e)
148         {
149             // Help text is returned in an exception
150             string strHelp = string(e.what());
151             if (strCommand == "")
152                 if (strHelp.find('\n') != -1)
153                     strHelp = strHelp.substr(0, strHelp.find('\n'));
154             strRet += strHelp + "\n";
155         }
156     }
157     if (strRet == "")
158         strRet = strprintf("help: unknown command: %s\n", strCommand.c_str());
159     strRet = strRet.substr(0,strRet.size()-1);
160     return strRet;
161 }
162
163
164 Value stop(const Array& params, bool fHelp)
165 {
166     if (fHelp || params.size() != 0)
167         throw runtime_error(
168             "stop\n"
169             "Stop bitcoin server.");
170 #ifndef QT_GUI
171     // Shutdown will take long enough that the response should get back
172     CreateThread(Shutdown, NULL);
173     return "bitcoin server stopping";
174 #else
175     throw runtime_error("NYI: cannot shut down GUI with RPC command");
176 #endif
177 }
178
179
180 Value getblockcount(const Array& params, bool fHelp)
181 {
182     if (fHelp || params.size() != 0)
183         throw runtime_error(
184             "getblockcount\n"
185             "Returns the number of blocks in the longest block chain.");
186
187     return nBestHeight;
188 }
189
190
191 // deprecated
192 Value getblocknumber(const Array& params, bool fHelp)
193 {
194     if (fHelp || params.size() != 0)
195         throw runtime_error(
196             "getblocknumber\n"
197             "Deprecated.  Use getblockcount.");
198
199     return nBestHeight;
200 }
201
202
203 Value getconnectioncount(const Array& params, bool fHelp)
204 {
205     if (fHelp || params.size() != 0)
206         throw runtime_error(
207             "getconnectioncount\n"
208             "Returns the number of connections to other nodes.");
209
210     return (int)vNodes.size();
211 }
212
213
214 double GetDifficulty()
215 {
216     // Floating point number that is a multiple of the minimum difficulty,
217     // minimum difficulty = 1.0.
218
219     if (pindexBest == NULL)
220         return 1.0;
221     int nShift = (pindexBest->nBits >> 24) & 0xff;
222
223     double dDiff =
224         (double)0x0000ffff / (double)(pindexBest->nBits & 0x00ffffff);
225
226     while (nShift < 29)
227     {
228         dDiff *= 256.0;
229         nShift++;
230     }
231     while (nShift > 29)
232     {
233         dDiff /= 256.0;
234         nShift--;
235     }
236
237     return dDiff;
238 }
239
240 Value getdifficulty(const Array& params, bool fHelp)
241 {
242     if (fHelp || params.size() != 0)
243         throw runtime_error(
244             "getdifficulty\n"
245             "Returns the proof-of-work difficulty as a multiple of the minimum difficulty.");
246
247     return GetDifficulty();
248 }
249
250
251 Value getgenerate(const Array& params, bool fHelp)
252 {
253     if (fHelp || params.size() != 0)
254         throw runtime_error(
255             "getgenerate\n"
256             "Returns true or false.");
257
258     return (bool)fGenerateBitcoins;
259 }
260
261
262 Value setgenerate(const Array& params, bool fHelp)
263 {
264     if (fHelp || params.size() < 1 || params.size() > 2)
265         throw runtime_error(
266             "setgenerate <generate> [genproclimit]\n"
267             "<generate> is true or false to turn generation on or off.\n"
268             "Generation is limited to [genproclimit] processors, -1 is unlimited.");
269
270     bool fGenerate = true;
271     if (params.size() > 0)
272         fGenerate = params[0].get_bool();
273
274     if (params.size() > 1)
275     {
276         int nGenProcLimit = params[1].get_int();
277         fLimitProcessors = (nGenProcLimit != -1);
278         WriteSetting("fLimitProcessors", fLimitProcessors);
279         if (nGenProcLimit != -1)
280             WriteSetting("nLimitProcessors", nLimitProcessors = nGenProcLimit);
281         if (nGenProcLimit == 0)
282             fGenerate = false;
283     }
284
285     GenerateBitcoins(fGenerate, pwalletMain);
286     return Value::null;
287 }
288
289
290 Value gethashespersec(const Array& params, bool fHelp)
291 {
292     if (fHelp || params.size() != 0)
293         throw runtime_error(
294             "gethashespersec\n"
295             "Returns a recent hashes per second performance measurement while generating.");
296
297     if (GetTimeMillis() - nHPSTimerStart > 8000)
298         return (boost::int64_t)0;
299     return (boost::int64_t)dHashesPerSec;
300 }
301
302
303 Value getinfo(const Array& params, bool fHelp)
304 {
305     if (fHelp || params.size() != 0)
306         throw runtime_error(
307             "getinfo\n"
308             "Returns an object containing various state info.");
309
310     Object obj;
311     obj.push_back(Pair("version",       (int)CLIENT_VERSION));
312     obj.push_back(Pair("protocolversion",(int)PROTOCOL_VERSION));
313     obj.push_back(Pair("balance",       ValueFromAmount(pwalletMain->GetBalance())));
314     obj.push_back(Pair("blocks",        (int)nBestHeight));
315     obj.push_back(Pair("connections",   (int)vNodes.size()));
316     obj.push_back(Pair("proxy",         (fUseProxy ? addrProxy.ToStringIPPort() : string())));
317     obj.push_back(Pair("generate",      (bool)fGenerateBitcoins));
318     obj.push_back(Pair("genproclimit",  (int)(fLimitProcessors ? nLimitProcessors : -1)));
319     obj.push_back(Pair("difficulty",    (double)GetDifficulty()));
320     obj.push_back(Pair("hashespersec",  gethashespersec(params, false)));
321     obj.push_back(Pair("testnet",       fTestNet));
322     obj.push_back(Pair("keypoololdest", (boost::int64_t)pwalletMain->GetOldestKeyPoolTime()));
323     obj.push_back(Pair("keypoolsize",   pwalletMain->GetKeyPoolSize()));
324     obj.push_back(Pair("paytxfee",      ValueFromAmount(nTransactionFee)));
325     if (pwalletMain->IsCrypted())
326         obj.push_back(Pair("unlocked_until", (boost::int64_t)nWalletUnlockTime));
327     obj.push_back(Pair("errors",        GetWarnings("statusbar")));
328     return obj;
329 }
330
331
332 Value getnewaddress(const Array& params, bool fHelp)
333 {
334     if (fHelp || params.size() > 1)
335         throw runtime_error(
336             "getnewaddress [account]\n"
337             "Returns a new bitcoin address for receiving payments.  "
338             "If [account] is specified (recommended), it is added to the address book "
339             "so payments received with the address will be credited to [account].");
340
341     // Parse the account first so we don't generate a key if there's an error
342     string strAccount;
343     if (params.size() > 0)
344         strAccount = AccountFromValue(params[0]);
345
346     if (!pwalletMain->IsLocked())
347         pwalletMain->TopUpKeyPool();
348
349     // Generate a new key that is added to wallet
350     std::vector<unsigned char> newKey;
351     if (!pwalletMain->GetKeyFromPool(newKey, false))
352         throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
353     CBitcoinAddress address(newKey);
354
355     pwalletMain->SetAddressBookName(address, strAccount);
356
357     return address.ToString();
358 }
359
360
361 CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false)
362 {
363     CWalletDB walletdb(pwalletMain->strWalletFile);
364
365     CAccount account;
366     walletdb.ReadAccount(strAccount, account);
367
368     bool bKeyUsed = false;
369
370     // Check if the current key has been used
371     if (!account.vchPubKey.empty())
372     {
373         CScript scriptPubKey;
374         scriptPubKey.SetBitcoinAddress(account.vchPubKey);
375         for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
376              it != pwalletMain->mapWallet.end() && !account.vchPubKey.empty();
377              ++it)
378         {
379             const CWalletTx& wtx = (*it).second;
380             BOOST_FOREACH(const CTxOut& txout, wtx.vout)
381                 if (txout.scriptPubKey == scriptPubKey)
382                     bKeyUsed = true;
383         }
384     }
385
386     // Generate a new key
387     if (account.vchPubKey.empty() || bForceNew || bKeyUsed)
388     {
389         if (!pwalletMain->GetKeyFromPool(account.vchPubKey, false))
390             throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
391
392         pwalletMain->SetAddressBookName(CBitcoinAddress(account.vchPubKey), strAccount);
393         walletdb.WriteAccount(strAccount, account);
394     }
395
396     return CBitcoinAddress(account.vchPubKey);
397 }
398
399 Value getaccountaddress(const Array& params, bool fHelp)
400 {
401     if (fHelp || params.size() != 1)
402         throw runtime_error(
403             "getaccountaddress <account>\n"
404             "Returns the current bitcoin address for receiving payments to this account.");
405
406     // Parse the account first so we don't generate a key if there's an error
407     string strAccount = AccountFromValue(params[0]);
408
409     Value ret;
410
411     ret = GetAccountAddress(strAccount).ToString();
412
413     return ret;
414 }
415
416
417
418 Value setaccount(const Array& params, bool fHelp)
419 {
420     if (fHelp || params.size() < 1 || params.size() > 2)
421         throw runtime_error(
422             "setaccount <bitcoinaddress> <account>\n"
423             "Sets the account associated with the given address.");
424
425     CBitcoinAddress address(params[0].get_str());
426     if (!address.IsValid())
427         throw JSONRPCError(-5, "Invalid bitcoin address");
428
429
430     string strAccount;
431     if (params.size() > 1)
432         strAccount = AccountFromValue(params[1]);
433
434     // Detect when changing the account of an address that is the 'unused current key' of another account:
435     if (pwalletMain->mapAddressBook.count(address))
436     {
437         string strOldAccount = pwalletMain->mapAddressBook[address];
438         if (address == GetAccountAddress(strOldAccount))
439             GetAccountAddress(strOldAccount, true);
440     }
441
442     pwalletMain->SetAddressBookName(address, strAccount);
443
444     return Value::null;
445 }
446
447
448 Value getaccount(const Array& params, bool fHelp)
449 {
450     if (fHelp || params.size() != 1)
451         throw runtime_error(
452             "getaccount <bitcoinaddress>\n"
453             "Returns the account associated with the given address.");
454
455     CBitcoinAddress address(params[0].get_str());
456     if (!address.IsValid())
457         throw JSONRPCError(-5, "Invalid bitcoin address");
458
459     string strAccount;
460     map<CBitcoinAddress, string>::iterator mi = pwalletMain->mapAddressBook.find(address);
461     if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.empty())
462         strAccount = (*mi).second;
463     return strAccount;
464 }
465
466
467 Value getaddressesbyaccount(const Array& params, bool fHelp)
468 {
469     if (fHelp || params.size() != 1)
470         throw runtime_error(
471             "getaddressesbyaccount <account>\n"
472             "Returns the list of addresses for the given account.");
473
474     string strAccount = AccountFromValue(params[0]);
475
476     // Find all addresses that have the given account
477     Array ret;
478     BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
479     {
480         const CBitcoinAddress& address = item.first;
481         const string& strName = item.second;
482         if (strName == strAccount)
483             ret.push_back(address.ToString());
484     }
485     return ret;
486 }
487
488 Value settxfee(const Array& params, bool fHelp)
489 {
490     if (fHelp || params.size() < 1 || params.size() > 1)
491         throw runtime_error(
492             "settxfee <amount>\n"
493             "<amount> is a real and is rounded to the nearest 0.00000001");
494
495     // Amount
496     int64 nAmount = 0;
497     if (params[0].get_real() != 0.0)
498         nAmount = AmountFromValue(params[0]);        // rejects 0.0 amounts
499
500     nTransactionFee = nAmount;
501     return true;
502 }
503
504 Value sendtoaddress(const Array& params, bool fHelp)
505 {
506     if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
507         throw runtime_error(
508             "sendtoaddress <bitcoinaddress> <amount> [comment] [comment-to]\n"
509             "<amount> is a real and is rounded to the nearest 0.00000001\n"
510             "requires wallet passphrase to be set with walletpassphrase first");
511     if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
512         throw runtime_error(
513             "sendtoaddress <bitcoinaddress> <amount> [comment] [comment-to]\n"
514             "<amount> is a real and is rounded to the nearest 0.00000001");
515
516     CBitcoinAddress address(params[0].get_str());
517     if (!address.IsValid())
518         throw JSONRPCError(-5, "Invalid bitcoin address");
519
520     // Amount
521     int64 nAmount = AmountFromValue(params[1]);
522
523     // Wallet comments
524     CWalletTx wtx;
525     if (params.size() > 2 && params[2].type() != null_type && !params[2].get_str().empty())
526         wtx.mapValue["comment"] = params[2].get_str();
527     if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
528         wtx.mapValue["to"]      = params[3].get_str();
529
530     if (pwalletMain->IsLocked())
531         throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
532
533     string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
534     if (strError != "")
535         throw JSONRPCError(-4, strError);
536
537     return wtx.GetHash().GetHex();
538 }
539
540 static const string strMessageMagic = "Bitcoin Signed Message:\n";
541
542 Value signmessage(const Array& params, bool fHelp)
543 {
544     if (fHelp || params.size() != 2)
545         throw runtime_error(
546             "signmessage <bitcoinaddress> <message>\n"
547             "Sign a message with the private key of an address");
548
549     if (pwalletMain->IsLocked())
550         throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
551
552     string strAddress = params[0].get_str();
553     string strMessage = params[1].get_str();
554
555     CBitcoinAddress addr(strAddress);
556     if (!addr.IsValid())
557         throw JSONRPCError(-3, "Invalid address");
558
559     CKey key;
560     if (!pwalletMain->GetKey(addr, key))
561         throw JSONRPCError(-4, "Private key not available");
562
563     CDataStream ss(SER_GETHASH);
564     ss << strMessageMagic;
565     ss << strMessage;
566
567     vector<unsigned char> vchSig;
568     if (!key.SignCompact(Hash(ss.begin(), ss.end()), vchSig))
569         throw JSONRPCError(-5, "Sign failed");
570
571     return EncodeBase64(&vchSig[0], vchSig.size());
572 }
573
574 Value verifymessage(const Array& params, bool fHelp)
575 {
576     if (fHelp || params.size() != 3)
577         throw runtime_error(
578             "verifymessage <bitcoinaddress> <signature> <message>\n"
579             "Verify a signed message");
580
581     string strAddress  = params[0].get_str();
582     string strSign     = params[1].get_str();
583     string strMessage  = params[2].get_str();
584
585     CBitcoinAddress addr(strAddress);
586     if (!addr.IsValid())
587         throw JSONRPCError(-3, "Invalid address");
588
589     bool fInvalid = false;
590     vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid);
591
592     if (fInvalid)
593         throw JSONRPCError(-5, "Malformed base64 encoding");
594
595     CDataStream ss(SER_GETHASH);
596     ss << strMessageMagic;
597     ss << strMessage;
598
599     CKey key;
600     if (!key.SetCompactSignature(Hash(ss.begin(), ss.end()), vchSig))
601         return false;
602
603     return (CBitcoinAddress(key.GetPubKey()) == addr);
604 }
605
606
607 Value getreceivedbyaddress(const Array& params, bool fHelp)
608 {
609     if (fHelp || params.size() < 1 || params.size() > 2)
610         throw runtime_error(
611             "getreceivedbyaddress <bitcoinaddress> [minconf=1]\n"
612             "Returns the total amount received by <bitcoinaddress> in transactions with at least [minconf] confirmations.");
613
614     // Bitcoin address
615     CBitcoinAddress address = CBitcoinAddress(params[0].get_str());
616     CScript scriptPubKey;
617     if (!address.IsValid())
618         throw JSONRPCError(-5, "Invalid bitcoin address");
619     scriptPubKey.SetBitcoinAddress(address);
620     if (!IsMine(*pwalletMain,scriptPubKey))
621         return (double)0.0;
622
623     // Minimum confirmations
624     int nMinDepth = 1;
625     if (params.size() > 1)
626         nMinDepth = params[1].get_int();
627
628     // Tally
629     int64 nAmount = 0;
630     for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
631     {
632         const CWalletTx& wtx = (*it).second;
633         if (wtx.IsCoinBase() || !wtx.IsFinal())
634             continue;
635
636         BOOST_FOREACH(const CTxOut& txout, wtx.vout)
637             if (txout.scriptPubKey == scriptPubKey)
638                 if (wtx.GetDepthInMainChain() >= nMinDepth)
639                     nAmount += txout.nValue;
640     }
641
642     return  ValueFromAmount(nAmount);
643 }
644
645
646 void GetAccountAddresses(string strAccount, set<CBitcoinAddress>& setAddress)
647 {
648     BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
649     {
650         const CBitcoinAddress& address = item.first;
651         const string& strName = item.second;
652         if (strName == strAccount)
653             setAddress.insert(address);
654     }
655 }
656
657
658 Value getreceivedbyaccount(const Array& params, bool fHelp)
659 {
660     if (fHelp || params.size() < 1 || params.size() > 2)
661         throw runtime_error(
662             "getreceivedbyaccount <account> [minconf=1]\n"
663             "Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.");
664
665     // Minimum confirmations
666     int nMinDepth = 1;
667     if (params.size() > 1)
668         nMinDepth = params[1].get_int();
669
670     // Get the set of pub keys that have the label
671     string strAccount = AccountFromValue(params[0]);
672     set<CBitcoinAddress> setAddress;
673     GetAccountAddresses(strAccount, setAddress);
674
675     // Tally
676     int64 nAmount = 0;
677     for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
678     {
679         const CWalletTx& wtx = (*it).second;
680         if (wtx.IsCoinBase() || !wtx.IsFinal())
681             continue;
682
683         BOOST_FOREACH(const CTxOut& txout, wtx.vout)
684         {
685             CBitcoinAddress address;
686             if (ExtractAddress(txout.scriptPubKey, pwalletMain, address) && setAddress.count(address))
687                 if (wtx.GetDepthInMainChain() >= nMinDepth)
688                     nAmount += txout.nValue;
689         }
690     }
691
692     return (double)nAmount / (double)COIN;
693 }
694
695
696 int64 GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth)
697 {
698     int64 nBalance = 0;
699
700     // Tally wallet transactions
701     for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
702     {
703         const CWalletTx& wtx = (*it).second;
704         if (!wtx.IsFinal())
705             continue;
706
707         int64 nGenerated, nReceived, nSent, nFee;
708         wtx.GetAccountAmounts(strAccount, nGenerated, nReceived, nSent, nFee);
709
710         if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
711             nBalance += nReceived;
712         nBalance += nGenerated - nSent - nFee;
713     }
714
715     // Tally internal accounting entries
716     nBalance += walletdb.GetAccountCreditDebit(strAccount);
717
718     return nBalance;
719 }
720
721 int64 GetAccountBalance(const string& strAccount, int nMinDepth)
722 {
723     CWalletDB walletdb(pwalletMain->strWalletFile);
724     return GetAccountBalance(walletdb, strAccount, nMinDepth);
725 }
726
727
728 Value getbalance(const Array& params, bool fHelp)
729 {
730     if (fHelp || params.size() > 2)
731         throw runtime_error(
732             "getbalance [account] [minconf=1]\n"
733             "If [account] is not specified, returns the server's total available balance.\n"
734             "If [account] is specified, returns the balance in the account.");
735
736     if (params.size() == 0)
737         return  ValueFromAmount(pwalletMain->GetBalance());
738
739     int nMinDepth = 1;
740     if (params.size() > 1)
741         nMinDepth = params[1].get_int();
742
743     if (params[0].get_str() == "*") {
744         // Calculate total balance a different way from GetBalance()
745         // (GetBalance() sums up all unspent TxOuts)
746         // getbalance and getbalance '*' should always return the same number.
747         int64 nBalance = 0;
748         for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
749         {
750             const CWalletTx& wtx = (*it).second;
751             if (!wtx.IsFinal())
752                 continue;
753
754             int64 allGeneratedImmature, allGeneratedMature, allFee;
755             allGeneratedImmature = allGeneratedMature = allFee = 0;
756             string strSentAccount;
757             list<pair<CBitcoinAddress, int64> > listReceived;
758             list<pair<CBitcoinAddress, int64> > listSent;
759             wtx.GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount);
760             if (wtx.GetDepthInMainChain() >= nMinDepth)
761                 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listReceived)
762                     nBalance += r.second;
763             BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listSent)
764                 nBalance -= r.second;
765             nBalance -= allFee;
766             nBalance += allGeneratedMature;
767         }
768         return  ValueFromAmount(nBalance);
769     }
770
771     string strAccount = AccountFromValue(params[0]);
772
773     int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
774
775     return ValueFromAmount(nBalance);
776 }
777
778
779 Value movecmd(const Array& params, bool fHelp)
780 {
781     if (fHelp || params.size() < 3 || params.size() > 5)
782         throw runtime_error(
783             "move <fromaccount> <toaccount> <amount> [minconf=1] [comment]\n"
784             "Move from one account in your wallet to another.");
785
786     string strFrom = AccountFromValue(params[0]);
787     string strTo = AccountFromValue(params[1]);
788     int64 nAmount = AmountFromValue(params[2]);
789     if (params.size() > 3)
790         // unused parameter, used to be nMinDepth, keep type-checking it though
791         (void)params[3].get_int();
792     string strComment;
793     if (params.size() > 4)
794         strComment = params[4].get_str();
795
796     CWalletDB walletdb(pwalletMain->strWalletFile);
797     walletdb.TxnBegin();
798
799     int64 nNow = GetAdjustedTime();
800
801     // Debit
802     CAccountingEntry debit;
803     debit.strAccount = strFrom;
804     debit.nCreditDebit = -nAmount;
805     debit.nTime = nNow;
806     debit.strOtherAccount = strTo;
807     debit.strComment = strComment;
808     walletdb.WriteAccountingEntry(debit);
809
810     // Credit
811     CAccountingEntry credit;
812     credit.strAccount = strTo;
813     credit.nCreditDebit = nAmount;
814     credit.nTime = nNow;
815     credit.strOtherAccount = strFrom;
816     credit.strComment = strComment;
817     walletdb.WriteAccountingEntry(credit);
818
819     walletdb.TxnCommit();
820
821     return true;
822 }
823
824
825 Value sendfrom(const Array& params, bool fHelp)
826 {
827     if (pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
828         throw runtime_error(
829             "sendfrom <fromaccount> <tobitcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
830             "<amount> is a real and is rounded to the nearest 0.00000001\n"
831             "requires wallet passphrase to be set with walletpassphrase first");
832     if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
833         throw runtime_error(
834             "sendfrom <fromaccount> <tobitcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
835             "<amount> is a real and is rounded to the nearest 0.00000001");
836
837     string strAccount = AccountFromValue(params[0]);
838     CBitcoinAddress address(params[1].get_str());
839     if (!address.IsValid())
840         throw JSONRPCError(-5, "Invalid bitcoin address");
841     int64 nAmount = AmountFromValue(params[2]);
842     int nMinDepth = 1;
843     if (params.size() > 3)
844         nMinDepth = params[3].get_int();
845
846     CWalletTx wtx;
847     wtx.strFromAccount = strAccount;
848     if (params.size() > 4 && params[4].type() != null_type && !params[4].get_str().empty())
849         wtx.mapValue["comment"] = params[4].get_str();
850     if (params.size() > 5 && params[5].type() != null_type && !params[5].get_str().empty())
851         wtx.mapValue["to"]      = params[5].get_str();
852
853     if (pwalletMain->IsLocked())
854         throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
855
856     // Check funds
857     int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
858     if (nAmount > nBalance)
859         throw JSONRPCError(-6, "Account has insufficient funds");
860
861     // Send
862     string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
863     if (strError != "")
864         throw JSONRPCError(-4, strError);
865
866     return wtx.GetHash().GetHex();
867 }
868
869
870 Value sendmany(const Array& params, bool fHelp)
871 {
872     if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
873         throw runtime_error(
874             "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
875             "amounts are double-precision floating point numbers\n"
876             "requires wallet passphrase to be set with walletpassphrase first");
877     if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
878         throw runtime_error(
879             "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
880             "amounts are double-precision floating point numbers");
881
882     string strAccount = AccountFromValue(params[0]);
883     Object sendTo = params[1].get_obj();
884     int nMinDepth = 1;
885     if (params.size() > 2)
886         nMinDepth = params[2].get_int();
887
888     CWalletTx wtx;
889     wtx.strFromAccount = strAccount;
890     if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
891         wtx.mapValue["comment"] = params[3].get_str();
892
893     set<CBitcoinAddress> setAddress;
894     vector<pair<CScript, int64> > vecSend;
895
896     int64 totalAmount = 0;
897     BOOST_FOREACH(const Pair& s, sendTo)
898     {
899         CBitcoinAddress address(s.name_);
900         if (!address.IsValid())
901             throw JSONRPCError(-5, string("Invalid bitcoin address:")+s.name_);
902
903         if (setAddress.count(address))
904             throw JSONRPCError(-8, string("Invalid parameter, duplicated address: ")+s.name_);
905         setAddress.insert(address);
906
907         CScript scriptPubKey;
908         scriptPubKey.SetBitcoinAddress(address);
909         int64 nAmount = AmountFromValue(s.value_); 
910         totalAmount += nAmount;
911
912         vecSend.push_back(make_pair(scriptPubKey, nAmount));
913     }
914
915     if (pwalletMain->IsLocked())
916         throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
917
918     // Check funds
919     int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
920     if (totalAmount > nBalance)
921         throw JSONRPCError(-6, "Account has insufficient funds");
922
923     // Send
924     CReserveKey keyChange(pwalletMain);
925     int64 nFeeRequired = 0;
926     bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired);
927     if (!fCreated)
928     {
929         if (totalAmount + nFeeRequired > pwalletMain->GetBalance())
930             throw JSONRPCError(-6, "Insufficient funds");
931         throw JSONRPCError(-4, "Transaction creation failed");
932     }
933     if (!pwalletMain->CommitTransaction(wtx, keyChange))
934         throw JSONRPCError(-4, "Transaction commit failed");
935
936     return wtx.GetHash().GetHex();
937 }
938
939
940 struct tallyitem
941 {
942     int64 nAmount;
943     int nConf;
944     tallyitem()
945     {
946         nAmount = 0;
947         nConf = INT_MAX;
948     }
949 };
950
951 Value ListReceived(const Array& params, bool fByAccounts)
952 {
953     // Minimum confirmations
954     int nMinDepth = 1;
955     if (params.size() > 0)
956         nMinDepth = params[0].get_int();
957
958     // Whether to include empty accounts
959     bool fIncludeEmpty = false;
960     if (params.size() > 1)
961         fIncludeEmpty = params[1].get_bool();
962
963     // Tally
964     map<CBitcoinAddress, tallyitem> mapTally;
965     for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
966     {
967         const CWalletTx& wtx = (*it).second;
968         if (wtx.IsCoinBase() || !wtx.IsFinal())
969             continue;
970
971         int nDepth = wtx.GetDepthInMainChain();
972         if (nDepth < nMinDepth)
973             continue;
974
975         BOOST_FOREACH(const CTxOut& txout, wtx.vout)
976         {
977             CBitcoinAddress address;
978             if (!ExtractAddress(txout.scriptPubKey, pwalletMain, address) || !address.IsValid())
979                 continue;
980
981             tallyitem& item = mapTally[address];
982             item.nAmount += txout.nValue;
983             item.nConf = min(item.nConf, nDepth);
984         }
985     }
986
987     // Reply
988     Array ret;
989     map<string, tallyitem> mapAccountTally;
990     BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
991     {
992         const CBitcoinAddress& address = item.first;
993         const string& strAccount = item.second;
994         map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
995         if (it == mapTally.end() && !fIncludeEmpty)
996             continue;
997
998         int64 nAmount = 0;
999         int nConf = INT_MAX;
1000         if (it != mapTally.end())
1001         {
1002             nAmount = (*it).second.nAmount;
1003             nConf = (*it).second.nConf;
1004         }
1005
1006         if (fByAccounts)
1007         {
1008             tallyitem& item = mapAccountTally[strAccount];
1009             item.nAmount += nAmount;
1010             item.nConf = min(item.nConf, nConf);
1011         }
1012         else
1013         {
1014             Object obj;
1015             obj.push_back(Pair("address",       address.ToString()));
1016             obj.push_back(Pair("account",       strAccount));
1017             obj.push_back(Pair("amount",        ValueFromAmount(nAmount)));
1018             obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf)));
1019             ret.push_back(obj);
1020         }
1021     }
1022
1023     if (fByAccounts)
1024     {
1025         for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
1026         {
1027             int64 nAmount = (*it).second.nAmount;
1028             int nConf = (*it).second.nConf;
1029             Object obj;
1030             obj.push_back(Pair("account",       (*it).first));
1031             obj.push_back(Pair("amount",        ValueFromAmount(nAmount)));
1032             obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf)));
1033             ret.push_back(obj);
1034         }
1035     }
1036
1037     return ret;
1038 }
1039
1040 Value listreceivedbyaddress(const Array& params, bool fHelp)
1041 {
1042     if (fHelp || params.size() > 2)
1043         throw runtime_error(
1044             "listreceivedbyaddress [minconf=1] [includeempty=false]\n"
1045             "[minconf] is the minimum number of confirmations before payments are included.\n"
1046             "[includeempty] whether to include addresses that haven't received any payments.\n"
1047             "Returns an array of objects containing:\n"
1048             "  \"address\" : receiving address\n"
1049             "  \"account\" : the account of the receiving address\n"
1050             "  \"amount\" : total amount received by the address\n"
1051             "  \"confirmations\" : number of confirmations of the most recent transaction included");
1052
1053     return ListReceived(params, false);
1054 }
1055
1056 Value listreceivedbyaccount(const Array& params, bool fHelp)
1057 {
1058     if (fHelp || params.size() > 2)
1059         throw runtime_error(
1060             "listreceivedbyaccount [minconf=1] [includeempty=false]\n"
1061             "[minconf] is the minimum number of confirmations before payments are included.\n"
1062             "[includeempty] whether to include accounts that haven't received any payments.\n"
1063             "Returns an array of objects containing:\n"
1064             "  \"account\" : the account of the receiving addresses\n"
1065             "  \"amount\" : total amount received by addresses with this account\n"
1066             "  \"confirmations\" : number of confirmations of the most recent transaction included");
1067
1068     return ListReceived(params, true);
1069 }
1070
1071 void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret)
1072 {
1073     int64 nGeneratedImmature, nGeneratedMature, nFee;
1074     string strSentAccount;
1075     list<pair<CBitcoinAddress, int64> > listReceived;
1076     list<pair<CBitcoinAddress, int64> > listSent;
1077     wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1078
1079     bool fAllAccounts = (strAccount == string("*"));
1080
1081     // Generated blocks assigned to account ""
1082     if ((nGeneratedMature+nGeneratedImmature) != 0 && (fAllAccounts || strAccount == ""))
1083     {
1084         Object entry;
1085         entry.push_back(Pair("account", string("")));
1086         if (nGeneratedImmature)
1087         {
1088             entry.push_back(Pair("category", wtx.GetDepthInMainChain() ? "immature" : "orphan"));
1089             entry.push_back(Pair("amount", ValueFromAmount(nGeneratedImmature)));
1090         }
1091         else
1092         {
1093             entry.push_back(Pair("category", "generate"));
1094             entry.push_back(Pair("amount", ValueFromAmount(nGeneratedMature)));
1095         }
1096         if (fLong)
1097             WalletTxToJSON(wtx, entry);
1098         ret.push_back(entry);
1099     }
1100
1101     // Sent
1102     if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
1103     {
1104         BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1105         {
1106             Object entry;
1107             entry.push_back(Pair("account", strSentAccount));
1108             entry.push_back(Pair("address", s.first.ToString()));
1109             entry.push_back(Pair("category", "send"));
1110             entry.push_back(Pair("amount", ValueFromAmount(-s.second)));
1111             entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
1112             if (fLong)
1113                 WalletTxToJSON(wtx, entry);
1114             ret.push_back(entry);
1115         }
1116     }
1117
1118     // Received
1119     if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
1120         BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1121         {
1122             string account;
1123             if (pwalletMain->mapAddressBook.count(r.first))
1124                 account = pwalletMain->mapAddressBook[r.first];
1125             if (fAllAccounts || (account == strAccount))
1126             {
1127                 Object entry;
1128                 entry.push_back(Pair("account", account));
1129                 entry.push_back(Pair("address", r.first.ToString()));
1130                 entry.push_back(Pair("category", "receive"));
1131                 entry.push_back(Pair("amount", ValueFromAmount(r.second)));
1132                 if (fLong)
1133                     WalletTxToJSON(wtx, entry);
1134                 ret.push_back(entry);
1135             }
1136         }
1137 }
1138
1139 void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret)
1140 {
1141     bool fAllAccounts = (strAccount == string("*"));
1142
1143     if (fAllAccounts || acentry.strAccount == strAccount)
1144     {
1145         Object entry;
1146         entry.push_back(Pair("account", acentry.strAccount));
1147         entry.push_back(Pair("category", "move"));
1148         entry.push_back(Pair("time", (boost::int64_t)acentry.nTime));
1149         entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
1150         entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
1151         entry.push_back(Pair("comment", acentry.strComment));
1152         ret.push_back(entry);
1153     }
1154 }
1155
1156 Value listtransactions(const Array& params, bool fHelp)
1157 {
1158     if (fHelp || params.size() > 3)
1159         throw runtime_error(
1160             "listtransactions [account] [count=10] [from=0]\n"
1161             "Returns up to [count] most recent transactions skipping the first [from] transactions for account [account].");
1162
1163     string strAccount = "*";
1164     if (params.size() > 0)
1165         strAccount = params[0].get_str();
1166     int nCount = 10;
1167     if (params.size() > 1)
1168         nCount = params[1].get_int();
1169     int nFrom = 0;
1170     if (params.size() > 2)
1171         nFrom = params[2].get_int();
1172
1173     Array ret;
1174     CWalletDB walletdb(pwalletMain->strWalletFile);
1175
1176     // Firs: get all CWalletTx and CAccountingEntry into a sorted-by-time multimap:
1177     typedef pair<CWalletTx*, CAccountingEntry*> TxPair;
1178     typedef multimap<int64, TxPair > TxItems;
1179     TxItems txByTime;
1180
1181     for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1182     {
1183         CWalletTx* wtx = &((*it).second);
1184         txByTime.insert(make_pair(wtx->GetTxTime(), TxPair(wtx, (CAccountingEntry*)0)));
1185     }
1186     list<CAccountingEntry> acentries;
1187     walletdb.ListAccountCreditDebit(strAccount, acentries);
1188     BOOST_FOREACH(CAccountingEntry& entry, acentries)
1189     {
1190         txByTime.insert(make_pair(entry.nTime, TxPair((CWalletTx*)0, &entry)));
1191     }
1192
1193     // Now: iterate backwards until we have nCount items to return:
1194     TxItems::reverse_iterator it = txByTime.rbegin();
1195     if (txByTime.size() > nFrom) std::advance(it, nFrom);
1196     for (; it != txByTime.rend(); ++it)
1197     {
1198         CWalletTx *const pwtx = (*it).second.first;
1199         if (pwtx != 0)
1200             ListTransactions(*pwtx, strAccount, 0, true, ret);
1201         CAccountingEntry *const pacentry = (*it).second.second;
1202         if (pacentry != 0)
1203             AcentryToJSON(*pacentry, strAccount, ret);
1204
1205         if (ret.size() >= nCount) break;
1206     }
1207     // ret is now newest to oldest
1208     
1209     // Make sure we return only last nCount items (sends-to-self might give us an extra):
1210     if (ret.size() > nCount)
1211     {
1212         Array::iterator last = ret.begin();
1213         std::advance(last, nCount);
1214         ret.erase(last, ret.end());
1215     }
1216     std::reverse(ret.begin(), ret.end()); // oldest to newest
1217
1218     return ret;
1219 }
1220
1221 Value listaccounts(const Array& params, bool fHelp)
1222 {
1223     if (fHelp || params.size() > 1)
1224         throw runtime_error(
1225             "listaccounts [minconf=1]\n"
1226             "Returns Object that has account names as keys, account balances as values.");
1227
1228     int nMinDepth = 1;
1229     if (params.size() > 0)
1230         nMinDepth = params[0].get_int();
1231
1232     map<string, int64> mapAccountBalances;
1233     BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& entry, pwalletMain->mapAddressBook) {
1234         if (pwalletMain->HaveKey(entry.first)) // This address belongs to me
1235             mapAccountBalances[entry.second] = 0;
1236     }
1237
1238     for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1239     {
1240         const CWalletTx& wtx = (*it).second;
1241         int64 nGeneratedImmature, nGeneratedMature, nFee;
1242         string strSentAccount;
1243         list<pair<CBitcoinAddress, int64> > listReceived;
1244         list<pair<CBitcoinAddress, int64> > listSent;
1245         wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1246         mapAccountBalances[strSentAccount] -= nFee;
1247         BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1248             mapAccountBalances[strSentAccount] -= s.second;
1249         if (wtx.GetDepthInMainChain() >= nMinDepth)
1250         {
1251             mapAccountBalances[""] += nGeneratedMature;
1252             BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1253                 if (pwalletMain->mapAddressBook.count(r.first))
1254                     mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second;
1255                 else
1256                     mapAccountBalances[""] += r.second;
1257         }
1258     }
1259
1260     list<CAccountingEntry> acentries;
1261     CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
1262     BOOST_FOREACH(const CAccountingEntry& entry, acentries)
1263         mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
1264
1265     Object ret;
1266     BOOST_FOREACH(const PAIRTYPE(string, int64)& accountBalance, mapAccountBalances) {
1267         ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
1268     }
1269     return ret;
1270 }
1271
1272 Value listsinceblock(const Array& params, bool fHelp)
1273 {
1274     if (fHelp)
1275         throw runtime_error(
1276             "listsinceblock [blockid] [target-confirmations]\n"
1277             "Get all transactions in blocks since block [blockid], or all transactions if omitted");
1278
1279     CBlockIndex *pindex = NULL;
1280     int target_confirms = 1;
1281
1282     if (params.size() > 0)
1283     {
1284         uint256 blockId = 0;
1285
1286         blockId.SetHex(params[0].get_str());
1287         pindex = CBlockLocator(blockId).GetBlockIndex();
1288     }
1289
1290     if (params.size() > 1)
1291     {
1292         target_confirms = params[1].get_int();
1293
1294         if (target_confirms < 1)
1295             throw JSONRPCError(-8, "Invalid parameter");
1296     }
1297
1298     int depth = pindex ? (1 + nBestHeight - pindex->nHeight) : -1;
1299
1300     Array transactions;
1301
1302     for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++)
1303     {
1304         CWalletTx tx = (*it).second;
1305
1306         if (depth == -1 || tx.GetDepthInMainChain() < depth)
1307             ListTransactions(tx, "*", 0, true, transactions);
1308     }
1309
1310     uint256 lastblock;
1311
1312     if (target_confirms == 1)
1313     {
1314         printf("oops!\n");
1315         lastblock = hashBestChain;
1316     }
1317     else
1318     {
1319         int target_height = pindexBest->nHeight + 1 - target_confirms;
1320
1321         CBlockIndex *block;
1322         for (block = pindexBest;
1323              block && block->nHeight > target_height;
1324              block = block->pprev);
1325
1326         lastblock = block ? block->GetBlockHash() : 0;
1327     }
1328
1329     Object ret;
1330     ret.push_back(Pair("transactions", transactions));
1331     ret.push_back(Pair("lastblock", lastblock.GetHex()));
1332
1333     return ret;
1334 }
1335
1336 Value gettransaction(const Array& params, bool fHelp)
1337 {
1338     if (fHelp || params.size() != 1)
1339         throw runtime_error(
1340             "gettransaction <txid>\n"
1341             "Get detailed information about <txid>");
1342
1343     uint256 hash;
1344     hash.SetHex(params[0].get_str());
1345
1346     Object entry;
1347
1348     if (!pwalletMain->mapWallet.count(hash))
1349         throw JSONRPCError(-5, "Invalid or non-wallet transaction id");
1350     const CWalletTx& wtx = pwalletMain->mapWallet[hash];
1351
1352     int64 nCredit = wtx.GetCredit();
1353     int64 nDebit = wtx.GetDebit();
1354     int64 nNet = nCredit - nDebit;
1355     int64 nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0);
1356
1357     entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
1358     if (wtx.IsFromMe())
1359         entry.push_back(Pair("fee", ValueFromAmount(nFee)));
1360
1361     WalletTxToJSON(pwalletMain->mapWallet[hash], entry);
1362
1363     Array details;
1364     ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details);
1365     entry.push_back(Pair("details", details));
1366
1367     return entry;
1368 }
1369
1370
1371 Value backupwallet(const Array& params, bool fHelp)
1372 {
1373     if (fHelp || params.size() != 1)
1374         throw runtime_error(
1375             "backupwallet <destination>\n"
1376             "Safely copies wallet.dat to destination, which can be a directory or a path with filename.");
1377
1378     string strDest = params[0].get_str();
1379     BackupWallet(*pwalletMain, strDest);
1380
1381     return Value::null;
1382 }
1383
1384
1385 Value keypoolrefill(const Array& params, bool fHelp)
1386 {
1387     if (pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1388         throw runtime_error(
1389             "keypoolrefill\n"
1390             "Fills the keypool, requires wallet passphrase to be set.");
1391     if (!pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1392         throw runtime_error(
1393             "keypoolrefill\n"
1394             "Fills the keypool.");
1395
1396     if (pwalletMain->IsLocked())
1397         throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
1398
1399     pwalletMain->TopUpKeyPool();
1400
1401     if (pwalletMain->GetKeyPoolSize() < GetArg("-keypool", 100))
1402         throw JSONRPCError(-4, "Error refreshing keypool.");
1403
1404     return Value::null;
1405 }
1406
1407
1408 void ThreadTopUpKeyPool(void* parg)
1409 {
1410     pwalletMain->TopUpKeyPool();
1411 }
1412
1413 void ThreadCleanWalletPassphrase(void* parg)
1414 {
1415     int64 nMyWakeTime = GetTime() + *((int*)parg);
1416
1417     if (nWalletUnlockTime == 0)
1418     {
1419         CRITICAL_BLOCK(cs_nWalletUnlockTime)
1420         {
1421             nWalletUnlockTime = nMyWakeTime;
1422         }
1423
1424         while (GetTime() < nWalletUnlockTime)
1425             Sleep(GetTime() - nWalletUnlockTime);
1426
1427         CRITICAL_BLOCK(cs_nWalletUnlockTime)
1428         {
1429             nWalletUnlockTime = 0;
1430         }
1431     }
1432     else
1433     {
1434         CRITICAL_BLOCK(cs_nWalletUnlockTime)
1435         {
1436             if (nWalletUnlockTime < nMyWakeTime)
1437                 nWalletUnlockTime = nMyWakeTime;
1438         }
1439         free(parg);
1440         return;
1441     }
1442
1443     pwalletMain->Lock();
1444
1445     delete (int*)parg;
1446 }
1447
1448 Value walletpassphrase(const Array& params, bool fHelp)
1449 {
1450     if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1451         throw runtime_error(
1452             "walletpassphrase <passphrase> <timeout>\n"
1453             "Stores the wallet decryption key in memory for <timeout> seconds.");
1454     if (fHelp)
1455         return true;
1456     if (!pwalletMain->IsCrypted())
1457         throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
1458
1459     if (!pwalletMain->IsLocked())
1460         throw JSONRPCError(-17, "Error: Wallet is already unlocked.");
1461
1462     // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
1463     SecureString strWalletPass;
1464     strWalletPass.reserve(100);
1465     // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1466     // Alternately, find a way to make params[0] mlock()'d to begin with.
1467     strWalletPass = params[0].get_str().c_str();
1468
1469     if (strWalletPass.length() > 0)
1470     {
1471         if (!pwalletMain->Unlock(strWalletPass))
1472             throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1473     }
1474     else
1475         throw runtime_error(
1476             "walletpassphrase <passphrase> <timeout>\n"
1477             "Stores the wallet decryption key in memory for <timeout> seconds.");
1478
1479     CreateThread(ThreadTopUpKeyPool, NULL);
1480     int* pnSleepTime = new int(params[1].get_int());
1481     CreateThread(ThreadCleanWalletPassphrase, pnSleepTime);
1482
1483     return Value::null;
1484 }
1485
1486
1487 Value walletpassphrasechange(const Array& params, bool fHelp)
1488 {
1489     if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1490         throw runtime_error(
1491             "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1492             "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1493     if (fHelp)
1494         return true;
1495     if (!pwalletMain->IsCrypted())
1496         throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
1497
1498     // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
1499     // Alternately, find a way to make params[0] mlock()'d to begin with.
1500     SecureString strOldWalletPass;
1501     strOldWalletPass.reserve(100);
1502     strOldWalletPass = params[0].get_str().c_str();
1503
1504     SecureString strNewWalletPass;
1505     strNewWalletPass.reserve(100);
1506     strNewWalletPass = params[1].get_str().c_str();
1507
1508     if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
1509         throw runtime_error(
1510             "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1511             "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1512
1513     if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
1514         throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1515
1516     return Value::null;
1517 }
1518
1519
1520 Value walletlock(const Array& params, bool fHelp)
1521 {
1522     if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
1523         throw runtime_error(
1524             "walletlock\n"
1525             "Removes the wallet encryption key from memory, locking the wallet.\n"
1526             "After calling this method, you will need to call walletpassphrase again\n"
1527             "before being able to call any methods which require the wallet to be unlocked.");
1528     if (fHelp)
1529         return true;
1530     if (!pwalletMain->IsCrypted())
1531         throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletlock was called.");
1532
1533     pwalletMain->Lock();
1534     CRITICAL_BLOCK(cs_nWalletUnlockTime)
1535     {
1536         nWalletUnlockTime = 0;
1537     }
1538
1539     return Value::null;
1540 }
1541
1542
1543 Value encryptwallet(const Array& params, bool fHelp)
1544 {
1545     if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
1546         throw runtime_error(
1547             "encryptwallet <passphrase>\n"
1548             "Encrypts the wallet with <passphrase>.");
1549     if (fHelp)
1550         return true;
1551     if (pwalletMain->IsCrypted())
1552         throw JSONRPCError(-15, "Error: running with an encrypted wallet, but encryptwallet was called.");
1553
1554 #ifdef QT_GUI
1555     // shutting down via RPC while the GUI is running does not work (yet):
1556     throw runtime_error("Not Yet Implemented: use GUI to encrypt wallet, not RPC command");
1557 #endif
1558
1559     // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1560     // Alternately, find a way to make params[0] mlock()'d to begin with.
1561     SecureString strWalletPass;
1562     strWalletPass.reserve(100);
1563     strWalletPass = params[0].get_str().c_str();
1564
1565     if (strWalletPass.length() < 1)
1566         throw runtime_error(
1567             "encryptwallet <passphrase>\n"
1568             "Encrypts the wallet with <passphrase>.");
1569
1570     if (!pwalletMain->EncryptWallet(strWalletPass))
1571         throw JSONRPCError(-16, "Error: Failed to encrypt the wallet.");
1572
1573     // BDB seems to have a bad habit of writing old data into
1574     // slack space in .dat files; that is bad if the old data is
1575     // unencrypted private keys.  So:
1576     CreateThread(Shutdown, NULL);
1577     return "wallet encrypted; bitcoin server stopping, restart to run with encrypted wallet";
1578 }
1579
1580
1581 Value validateaddress(const Array& params, bool fHelp)
1582 {
1583     if (fHelp || params.size() != 1)
1584         throw runtime_error(
1585             "validateaddress <bitcoinaddress>\n"
1586             "Return information about <bitcoinaddress>.");
1587
1588     CBitcoinAddress address(params[0].get_str());
1589     bool isValid = address.IsValid();
1590
1591     Object ret;
1592     ret.push_back(Pair("isvalid", isValid));
1593     if (isValid)
1594     {
1595         // Call Hash160ToAddress() so we always return current ADDRESSVERSION
1596         // version of the address:
1597         string currentAddress = address.ToString();
1598         ret.push_back(Pair("address", currentAddress));
1599         ret.push_back(Pair("ismine", (pwalletMain->HaveKey(address) > 0)));
1600         if (pwalletMain->mapAddressBook.count(address))
1601             ret.push_back(Pair("account", pwalletMain->mapAddressBook[address]));
1602     }
1603     return ret;
1604 }
1605
1606 Value getwork(const Array& params, bool fHelp)
1607 {
1608     if (fHelp || params.size() > 1)
1609         throw runtime_error(
1610             "getwork [data]\n"
1611             "If [data] is not specified, returns formatted hash data to work on:\n"
1612             "  \"midstate\" : precomputed hash state after hashing the first half of the data (DEPRECATED)\n" // deprecated
1613             "  \"data\" : block data\n"
1614             "  \"hash1\" : formatted hash buffer for second hash (DEPRECATED)\n" // deprecated
1615             "  \"target\" : little endian hash target\n"
1616             "If [data] is specified, tries to solve the block and returns true if it was successful.");
1617
1618     if (vNodes.empty())
1619         throw JSONRPCError(-9, "Bitcoin is not connected!");
1620
1621     if (IsInitialBlockDownload())
1622         throw JSONRPCError(-10, "Bitcoin is downloading blocks...");
1623
1624     typedef map<uint256, pair<CBlock*, CScript> > mapNewBlock_t;
1625     static mapNewBlock_t mapNewBlock;
1626     static vector<CBlock*> vNewBlock;
1627     static CReserveKey reservekey(pwalletMain);
1628
1629     if (params.size() == 0)
1630     {
1631         // Update block
1632         static unsigned int nTransactionsUpdatedLast;
1633         static CBlockIndex* pindexPrev;
1634         static int64 nStart;
1635         static CBlock* pblock;
1636         if (pindexPrev != pindexBest ||
1637             (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60))
1638         {
1639             if (pindexPrev != pindexBest)
1640             {
1641                 // Deallocate old blocks since they're obsolete now
1642                 mapNewBlock.clear();
1643                 BOOST_FOREACH(CBlock* pblock, vNewBlock)
1644                     delete pblock;
1645                 vNewBlock.clear();
1646             }
1647             nTransactionsUpdatedLast = nTransactionsUpdated;
1648             pindexPrev = pindexBest;
1649             nStart = GetTime();
1650
1651             // Create new block
1652             pblock = CreateNewBlock(reservekey);
1653             if (!pblock)
1654                 throw JSONRPCError(-7, "Out of memory");
1655             vNewBlock.push_back(pblock);
1656         }
1657
1658         // Update nTime
1659         pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
1660         pblock->nNonce = 0;
1661
1662         // Update nExtraNonce
1663         static unsigned int nExtraNonce = 0;
1664         IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
1665
1666         // Save
1667         mapNewBlock[pblock->hashMerkleRoot] = make_pair(pblock, pblock->vtx[0].vin[0].scriptSig);
1668
1669         // Prebuild hash buffers
1670         char pmidstate[32];
1671         char pdata[128];
1672         char phash1[64];
1673         FormatHashBuffers(pblock, pmidstate, pdata, phash1);
1674
1675         uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
1676
1677         Object result;
1678         result.push_back(Pair("midstate", HexStr(BEGIN(pmidstate), END(pmidstate)))); // deprecated
1679         result.push_back(Pair("data",     HexStr(BEGIN(pdata), END(pdata))));
1680         result.push_back(Pair("hash1",    HexStr(BEGIN(phash1), END(phash1)))); // deprecated
1681         result.push_back(Pair("target",   HexStr(BEGIN(hashTarget), END(hashTarget))));
1682         return result;
1683     }
1684     else
1685     {
1686         // Parse parameters
1687         vector<unsigned char> vchData = ParseHex(params[0].get_str());
1688         if (vchData.size() != 128)
1689             throw JSONRPCError(-8, "Invalid parameter");
1690         CBlock* pdata = (CBlock*)&vchData[0];
1691
1692         // Byte reverse
1693         for (int i = 0; i < 128/4; i++)
1694             ((unsigned int*)pdata)[i] = ByteReverse(((unsigned int*)pdata)[i]);
1695
1696         // Get saved block
1697         if (!mapNewBlock.count(pdata->hashMerkleRoot))
1698             return false;
1699         CBlock* pblock = mapNewBlock[pdata->hashMerkleRoot].first;
1700
1701         pblock->nTime = pdata->nTime;
1702         pblock->nNonce = pdata->nNonce;
1703         pblock->vtx[0].vin[0].scriptSig = mapNewBlock[pdata->hashMerkleRoot].second;
1704         pblock->hashMerkleRoot = pblock->BuildMerkleTree();
1705
1706         return CheckWork(pblock, *pwalletMain, reservekey);
1707     }
1708 }
1709
1710
1711 Value getmemorypool(const Array& params, bool fHelp)
1712 {
1713     if (fHelp || params.size() > 1)
1714         throw runtime_error(
1715             "getmemorypool [data]\n"
1716             "If [data] is not specified, returns data needed to construct a block to work on:\n"
1717             "  \"version\" : block version\n"
1718             "  \"previousblockhash\" : hash of current highest block\n"
1719             "  \"transactions\" : contents of non-coinbase transactions that should be included in the next block\n"
1720             "  \"coinbasevalue\" : maximum allowable input to coinbase transaction, including the generation award and transaction fees\n"
1721             "  \"time\" : timestamp appropriate for next block\n"
1722             "  \"bits\" : compressed target of next block\n"
1723             "If [data] is specified, tries to solve the block and returns true if it was successful.");
1724
1725     if (params.size() == 0)
1726     {
1727         if (vNodes.empty())
1728             throw JSONRPCError(-9, "Bitcoin is not connected!");
1729
1730         if (IsInitialBlockDownload())
1731             throw JSONRPCError(-10, "Bitcoin is downloading blocks...");
1732
1733         static CReserveKey reservekey(pwalletMain);
1734
1735         // Update block
1736         static unsigned int nTransactionsUpdatedLast;
1737         static CBlockIndex* pindexPrev;
1738         static int64 nStart;
1739         static CBlock* pblock;
1740         if (pindexPrev != pindexBest ||
1741             (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 5))
1742         {
1743             nTransactionsUpdatedLast = nTransactionsUpdated;
1744             pindexPrev = pindexBest;
1745             nStart = GetTime();
1746
1747             // Create new block
1748             if(pblock)
1749                 delete pblock;
1750             pblock = CreateNewBlock(reservekey);
1751             if (!pblock)
1752                 throw JSONRPCError(-7, "Out of memory");
1753         }
1754
1755         // Update nTime
1756         pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
1757         pblock->nNonce = 0;
1758
1759         Array transactions;
1760         BOOST_FOREACH(CTransaction tx, pblock->vtx) {
1761             if(tx.IsCoinBase())
1762                 continue;
1763
1764             CDataStream ssTx;
1765             ssTx << tx;
1766
1767             transactions.push_back(HexStr(ssTx.begin(), ssTx.end()));
1768         }
1769
1770         Object result;
1771         result.push_back(Pair("version", pblock->nVersion));
1772         result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex()));
1773         result.push_back(Pair("transactions", transactions));
1774         result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue));
1775         result.push_back(Pair("time", (int64_t)pblock->nTime));
1776
1777         union {
1778             int32_t nBits;
1779             char cBits[4];
1780         } uBits;
1781         uBits.nBits = htonl((int32_t)pblock->nBits);
1782         result.push_back(Pair("bits", HexStr(BEGIN(uBits.cBits), END(uBits.cBits))));
1783
1784         return result;
1785     }
1786     else
1787     {
1788         // Parse parameters
1789         CDataStream ssBlock(ParseHex(params[0].get_str()));
1790         CBlock pblock;
1791         ssBlock >> pblock;
1792
1793         return ProcessBlock(NULL, &pblock);
1794     }
1795 }
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807 //
1808 // Call Table
1809 //
1810
1811 pair<string, rpcfn_type> pCallTable[] =
1812 {
1813     make_pair("help",                   &help),
1814     make_pair("stop",                   &stop),
1815     make_pair("getblockcount",          &getblockcount),
1816     make_pair("getblocknumber",         &getblocknumber),
1817     make_pair("getconnectioncount",     &getconnectioncount),
1818     make_pair("getdifficulty",          &getdifficulty),
1819     make_pair("getgenerate",            &getgenerate),
1820     make_pair("setgenerate",            &setgenerate),
1821     make_pair("gethashespersec",        &gethashespersec),
1822     make_pair("getinfo",                &getinfo),
1823     make_pair("getnewaddress",          &getnewaddress),
1824     make_pair("getaccountaddress",      &getaccountaddress),
1825     make_pair("setaccount",             &setaccount),
1826     make_pair("getaccount",             &getaccount),
1827     make_pair("getaddressesbyaccount",  &getaddressesbyaccount),
1828     make_pair("sendtoaddress",          &sendtoaddress),
1829     make_pair("getreceivedbyaddress",   &getreceivedbyaddress),
1830     make_pair("getreceivedbyaccount",   &getreceivedbyaccount),
1831     make_pair("listreceivedbyaddress",  &listreceivedbyaddress),
1832     make_pair("listreceivedbyaccount",  &listreceivedbyaccount),
1833     make_pair("backupwallet",           &backupwallet),
1834     make_pair("keypoolrefill",          &keypoolrefill),
1835     make_pair("walletpassphrase",       &walletpassphrase),
1836     make_pair("walletpassphrasechange", &walletpassphrasechange),
1837     make_pair("walletlock",             &walletlock),
1838     make_pair("encryptwallet",          &encryptwallet),
1839     make_pair("validateaddress",        &validateaddress),
1840     make_pair("getbalance",             &getbalance),
1841     make_pair("move",                   &movecmd),
1842     make_pair("sendfrom",               &sendfrom),
1843     make_pair("sendmany",               &sendmany),
1844     make_pair("gettransaction",         &gettransaction),
1845     make_pair("listtransactions",       &listtransactions),
1846     make_pair("signmessage",            &signmessage),
1847     make_pair("verifymessage",          &verifymessage),
1848     make_pair("getwork",                &getwork),
1849     make_pair("listaccounts",           &listaccounts),
1850     make_pair("settxfee",               &settxfee),
1851     make_pair("getmemorypool",          &getmemorypool),
1852     make_pair("listsinceblock",         &listsinceblock),
1853     make_pair("dumpprivkey",            &dumpprivkey),
1854     make_pair("importprivkey",          &importprivkey)
1855 };
1856 map<string, rpcfn_type> mapCallTable(pCallTable, pCallTable + sizeof(pCallTable)/sizeof(pCallTable[0]));
1857
1858 string pAllowInSafeMode[] =
1859 {
1860     "help",
1861     "stop",
1862     "getblockcount",
1863     "getblocknumber",  // deprecated
1864     "getconnectioncount",
1865     "getdifficulty",
1866     "getgenerate",
1867     "setgenerate",
1868     "gethashespersec",
1869     "getinfo",
1870     "getnewaddress",
1871     "getaccountaddress",
1872     "getaccount",
1873     "getaddressesbyaccount",
1874     "backupwallet",
1875     "keypoolrefill",
1876     "walletpassphrase",
1877     "walletlock",
1878     "validateaddress",
1879     "getwork",
1880     "getmemorypool",
1881 };
1882 set<string> setAllowInSafeMode(pAllowInSafeMode, pAllowInSafeMode + sizeof(pAllowInSafeMode)/sizeof(pAllowInSafeMode[0]));
1883
1884
1885
1886
1887 //
1888 // HTTP protocol
1889 //
1890 // This ain't Apache.  We're just using HTTP header for the length field
1891 // and to be compatible with other JSON-RPC implementations.
1892 //
1893
1894 string HTTPPost(const string& strMsg, const map<string,string>& mapRequestHeaders)
1895 {
1896     ostringstream s;
1897     s << "POST / HTTP/1.1\r\n"
1898       << "User-Agent: bitcoin-json-rpc/" << FormatFullVersion() << "\r\n"
1899       << "Host: 127.0.0.1\r\n"
1900       << "Content-Type: application/json\r\n"
1901       << "Content-Length: " << strMsg.size() << "\r\n"
1902       << "Connection: close\r\n"
1903       << "Accept: application/json\r\n";
1904     BOOST_FOREACH(const PAIRTYPE(string, string)& item, mapRequestHeaders)
1905         s << item.first << ": " << item.second << "\r\n";
1906     s << "\r\n" << strMsg;
1907
1908     return s.str();
1909 }
1910
1911 string rfc1123Time()
1912 {
1913     char buffer[64];
1914     time_t now;
1915     time(&now);
1916     struct tm* now_gmt = gmtime(&now);
1917     string locale(setlocale(LC_TIME, NULL));
1918     setlocale(LC_TIME, "C"); // we want posix (aka "C") weekday/month strings
1919     strftime(buffer, sizeof(buffer), "%a, %d %b %Y %H:%M:%S +0000", now_gmt);
1920     setlocale(LC_TIME, locale.c_str());
1921     return string(buffer);
1922 }
1923
1924 static string HTTPReply(int nStatus, const string& strMsg)
1925 {
1926     if (nStatus == 401)
1927         return strprintf("HTTP/1.0 401 Authorization Required\r\n"
1928             "Date: %s\r\n"
1929             "Server: bitcoin-json-rpc/%s\r\n"
1930             "WWW-Authenticate: Basic realm=\"jsonrpc\"\r\n"
1931             "Content-Type: text/html\r\n"
1932             "Content-Length: 296\r\n"
1933             "\r\n"
1934             "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\r\n"
1935             "\"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd\">\r\n"
1936             "<HTML>\r\n"
1937             "<HEAD>\r\n"
1938             "<TITLE>Error</TITLE>\r\n"
1939             "<META HTTP-EQUIV='Content-Type' CONTENT='text/html; charset=ISO-8859-1'>\r\n"
1940             "</HEAD>\r\n"
1941             "<BODY><H1>401 Unauthorized.</H1></BODY>\r\n"
1942             "</HTML>\r\n", rfc1123Time().c_str(), FormatFullVersion().c_str());
1943     const char *cStatus;
1944          if (nStatus == 200) cStatus = "OK";
1945     else if (nStatus == 400) cStatus = "Bad Request";
1946     else if (nStatus == 403) cStatus = "Forbidden";
1947     else if (nStatus == 404) cStatus = "Not Found";
1948     else if (nStatus == 500) cStatus = "Internal Server Error";
1949     else cStatus = "";
1950     return strprintf(
1951             "HTTP/1.1 %d %s\r\n"
1952             "Date: %s\r\n"
1953             "Connection: close\r\n"
1954             "Content-Length: %d\r\n"
1955             "Content-Type: application/json\r\n"
1956             "Server: bitcoin-json-rpc/%s\r\n"
1957             "\r\n"
1958             "%s",
1959         nStatus,
1960         cStatus,
1961         rfc1123Time().c_str(),
1962         strMsg.size(),
1963         FormatFullVersion().c_str(),
1964         strMsg.c_str());
1965 }
1966
1967 int ReadHTTPStatus(std::basic_istream<char>& stream)
1968 {
1969     string str;
1970     getline(stream, str);
1971     vector<string> vWords;
1972     boost::split(vWords, str, boost::is_any_of(" "));
1973     if (vWords.size() < 2)
1974         return 500;
1975     return atoi(vWords[1].c_str());
1976 }
1977
1978 int ReadHTTPHeader(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet)
1979 {
1980     int nLen = 0;
1981     loop
1982     {
1983         string str;
1984         std::getline(stream, str);
1985         if (str.empty() || str == "\r")
1986             break;
1987         string::size_type nColon = str.find(":");
1988         if (nColon != string::npos)
1989         {
1990             string strHeader = str.substr(0, nColon);
1991             boost::trim(strHeader);
1992             boost::to_lower(strHeader);
1993             string strValue = str.substr(nColon+1);
1994             boost::trim(strValue);
1995             mapHeadersRet[strHeader] = strValue;
1996             if (strHeader == "content-length")
1997                 nLen = atoi(strValue.c_str());
1998         }
1999     }
2000     return nLen;
2001 }
2002
2003 int ReadHTTP(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet, string& strMessageRet)
2004 {
2005     mapHeadersRet.clear();
2006     strMessageRet = "";
2007
2008     // Read status
2009     int nStatus = ReadHTTPStatus(stream);
2010
2011     // Read header
2012     int nLen = ReadHTTPHeader(stream, mapHeadersRet);
2013     if (nLen < 0 || nLen > MAX_SIZE)
2014         return 500;
2015
2016     // Read message
2017     if (nLen > 0)
2018     {
2019         vector<char> vch(nLen);
2020         stream.read(&vch[0], nLen);
2021         strMessageRet = string(vch.begin(), vch.end());
2022     }
2023
2024     return nStatus;
2025 }
2026
2027 bool HTTPAuthorized(map<string, string>& mapHeaders)
2028 {
2029     string strAuth = mapHeaders["authorization"];
2030     if (strAuth.substr(0,6) != "Basic ")
2031         return false;
2032     string strUserPass64 = strAuth.substr(6); boost::trim(strUserPass64);
2033     string strUserPass = DecodeBase64(strUserPass64);
2034     return strUserPass == strRPCUserColonPass;
2035 }
2036
2037 //
2038 // JSON-RPC protocol.  Bitcoin speaks version 1.0 for maximum compatibility,
2039 // but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
2040 // unspecified (HTTP errors and contents of 'error').
2041 //
2042 // 1.0 spec: http://json-rpc.org/wiki/specification
2043 // 1.2 spec: http://groups.google.com/group/json-rpc/web/json-rpc-over-http
2044 // http://www.codeproject.com/KB/recipes/JSON_Spirit.aspx
2045 //
2046
2047 string JSONRPCRequest(const string& strMethod, const Array& params, const Value& id)
2048 {
2049     Object request;
2050     request.push_back(Pair("method", strMethod));
2051     request.push_back(Pair("params", params));
2052     request.push_back(Pair("id", id));
2053     return write_string(Value(request), false) + "\n";
2054 }
2055
2056 string JSONRPCReply(const Value& result, const Value& error, const Value& id)
2057 {
2058     Object reply;
2059     if (error.type() != null_type)
2060         reply.push_back(Pair("result", Value::null));
2061     else
2062         reply.push_back(Pair("result", result));
2063     reply.push_back(Pair("error", error));
2064     reply.push_back(Pair("id", id));
2065     return write_string(Value(reply), false) + "\n";
2066 }
2067
2068 void ErrorReply(std::ostream& stream, const Object& objError, const Value& id)
2069 {
2070     // Send error reply from json-rpc error object
2071     int nStatus = 500;
2072     int code = find_value(objError, "code").get_int();
2073     if (code == -32600) nStatus = 400;
2074     else if (code == -32601) nStatus = 404;
2075     string strReply = JSONRPCReply(Value::null, objError, id);
2076     stream << HTTPReply(nStatus, strReply) << std::flush;
2077 }
2078
2079 bool ClientAllowed(const string& strAddress)
2080 {
2081     if (strAddress == asio::ip::address_v4::loopback().to_string())
2082         return true;
2083     const vector<string>& vAllow = mapMultiArgs["-rpcallowip"];
2084     BOOST_FOREACH(string strAllow, vAllow)
2085         if (WildcardMatch(strAddress, strAllow))
2086             return true;
2087     return false;
2088 }
2089
2090 #ifdef USE_SSL
2091 //
2092 // IOStream device that speaks SSL but can also speak non-SSL
2093 //
2094 class SSLIOStreamDevice : public iostreams::device<iostreams::bidirectional> {
2095 public:
2096     SSLIOStreamDevice(SSLStream &streamIn, bool fUseSSLIn) : stream(streamIn)
2097     {
2098         fUseSSL = fUseSSLIn;
2099         fNeedHandshake = fUseSSLIn;
2100     }
2101
2102     void handshake(ssl::stream_base::handshake_type role)
2103     {
2104         if (!fNeedHandshake) return;
2105         fNeedHandshake = false;
2106         stream.handshake(role);
2107     }
2108     std::streamsize read(char* s, std::streamsize n)
2109     {
2110         handshake(ssl::stream_base::server); // HTTPS servers read first
2111         if (fUseSSL) return stream.read_some(asio::buffer(s, n));
2112         return stream.next_layer().read_some(asio::buffer(s, n));
2113     }
2114     std::streamsize write(const char* s, std::streamsize n)
2115     {
2116         handshake(ssl::stream_base::client); // HTTPS clients write first
2117         if (fUseSSL) return asio::write(stream, asio::buffer(s, n));
2118         return asio::write(stream.next_layer(), asio::buffer(s, n));
2119     }
2120     bool connect(const std::string& server, const std::string& port)
2121     {
2122         ip::tcp::resolver resolver(stream.get_io_service());
2123         ip::tcp::resolver::query query(server.c_str(), port.c_str());
2124         ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
2125         ip::tcp::resolver::iterator end;
2126         boost::system::error_code error = asio::error::host_not_found;
2127         while (error && endpoint_iterator != end)
2128         {
2129             stream.lowest_layer().close();
2130             stream.lowest_layer().connect(*endpoint_iterator++, error);
2131         }
2132         if (error)
2133             return false;
2134         return true;
2135     }
2136
2137 private:
2138     bool fNeedHandshake;
2139     bool fUseSSL;
2140     SSLStream& stream;
2141 };
2142 #endif
2143
2144 void ThreadRPCServer(void* parg)
2145 {
2146     IMPLEMENT_RANDOMIZE_STACK(ThreadRPCServer(parg));
2147     try
2148     {
2149         vnThreadsRunning[4]++;
2150         ThreadRPCServer2(parg);
2151         vnThreadsRunning[4]--;
2152     }
2153     catch (std::exception& e) {
2154         vnThreadsRunning[4]--;
2155         PrintException(&e, "ThreadRPCServer()");
2156     } catch (...) {
2157         vnThreadsRunning[4]--;
2158         PrintException(NULL, "ThreadRPCServer()");
2159     }
2160     printf("ThreadRPCServer exiting\n");
2161 }
2162
2163 void ThreadRPCServer2(void* parg)
2164 {
2165     printf("ThreadRPCServer started\n");
2166
2167     strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"];
2168     if (strRPCUserColonPass == ":")
2169     {
2170         string strWhatAmI = "To use bitcoind";
2171         if (mapArgs.count("-server"))
2172             strWhatAmI = strprintf(_("To use the %s option"), "\"-server\"");
2173         else if (mapArgs.count("-daemon"))
2174             strWhatAmI = strprintf(_("To use the %s option"), "\"-daemon\"");
2175         PrintConsole(
2176             _("Error: %s, you must set rpcpassword=<password>\nin the configuration file: %s\n"
2177               "If the file does not exist, create it with owner-readable-only file permissions.\n"),
2178                 strWhatAmI.c_str(),
2179                 GetConfigFile().c_str());
2180 #ifndef QT_GUI
2181         CreateThread(Shutdown, NULL);
2182 #endif
2183         return;
2184     }
2185
2186     bool fUseSSL = GetBoolArg("-rpcssl");
2187     asio::ip::address bindAddress = mapArgs.count("-rpcallowip") ? asio::ip::address_v4::any() : asio::ip::address_v4::loopback();
2188
2189     asio::io_service io_service;
2190     ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", 8332));
2191     ip::tcp::acceptor acceptor(io_service, endpoint);
2192
2193     acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
2194
2195 #ifdef USE_SSL
2196     ssl::context context(io_service, ssl::context::sslv23);
2197     if (fUseSSL)
2198     {
2199         context.set_options(ssl::context::no_sslv2);
2200         filesystem::path certfile = GetArg("-rpcsslcertificatechainfile", "server.cert");
2201         if (!certfile.is_complete()) certfile = filesystem::path(GetDataDir()) / certfile;
2202         if (filesystem::exists(certfile)) context.use_certificate_chain_file(certfile.string().c_str());
2203         else printf("ThreadRPCServer ERROR: missing server certificate file %s\n", certfile.string().c_str());
2204         filesystem::path pkfile = GetArg("-rpcsslprivatekeyfile", "server.pem");
2205         if (!pkfile.is_complete()) pkfile = filesystem::path(GetDataDir()) / pkfile;
2206         if (filesystem::exists(pkfile)) context.use_private_key_file(pkfile.string().c_str(), ssl::context::pem);
2207         else printf("ThreadRPCServer ERROR: missing server private key file %s\n", pkfile.string().c_str());
2208
2209         string ciphers = GetArg("-rpcsslciphers",
2210                                          "TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH");
2211         SSL_CTX_set_cipher_list(context.impl(), ciphers.c_str());
2212     }
2213 #else
2214     if (fUseSSL)
2215         throw runtime_error("-rpcssl=1, but bitcoin compiled without full openssl libraries.");
2216 #endif
2217
2218     loop
2219     {
2220         // Accept connection
2221 #ifdef USE_SSL
2222         SSLStream sslStream(io_service, context);
2223         SSLIOStreamDevice d(sslStream, fUseSSL);
2224         iostreams::stream<SSLIOStreamDevice> stream(d);
2225 #else
2226         ip::tcp::iostream stream;
2227 #endif
2228
2229         ip::tcp::endpoint peer;
2230         vnThreadsRunning[4]--;
2231 #ifdef USE_SSL
2232         acceptor.accept(sslStream.lowest_layer(), peer);
2233 #else
2234         acceptor.accept(*stream.rdbuf(), peer);
2235 #endif
2236         vnThreadsRunning[4]++;
2237         if (fShutdown)
2238             return;
2239
2240         // Restrict callers by IP
2241         if (!ClientAllowed(peer.address().to_string()))
2242         {
2243             // Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake.
2244             if (!fUseSSL)
2245                 stream << HTTPReply(403, "") << std::flush;
2246             continue;
2247         }
2248
2249         map<string, string> mapHeaders;
2250         string strRequest;
2251
2252         boost::thread api_caller(ReadHTTP, boost::ref(stream), boost::ref(mapHeaders), boost::ref(strRequest));
2253         if (!api_caller.timed_join(boost::posix_time::seconds(GetArg("-rpctimeout", 30))))
2254         {   // Timed out:
2255             acceptor.cancel();
2256             printf("ThreadRPCServer ReadHTTP timeout\n");
2257             continue;
2258         }
2259
2260         // Check authorization
2261         if (mapHeaders.count("authorization") == 0)
2262         {
2263             stream << HTTPReply(401, "") << std::flush;
2264             continue;
2265         }
2266         if (!HTTPAuthorized(mapHeaders))
2267         {
2268             // Deter brute-forcing short passwords
2269             if (mapArgs["-rpcpassword"].size() < 15)
2270                 Sleep(50);
2271
2272             stream << HTTPReply(401, "") << std::flush;
2273             printf("ThreadRPCServer incorrect password attempt\n");
2274             continue;
2275         }
2276
2277         Value id = Value::null;
2278         try
2279         {
2280             // Parse request
2281             Value valRequest;
2282             if (!read_string(strRequest, valRequest) || valRequest.type() != obj_type)
2283                 throw JSONRPCError(-32700, "Parse error");
2284             const Object& request = valRequest.get_obj();
2285
2286             // Parse id now so errors from here on will have the id
2287             id = find_value(request, "id");
2288
2289             // Parse method
2290             Value valMethod = find_value(request, "method");
2291             if (valMethod.type() == null_type)
2292                 throw JSONRPCError(-32600, "Missing method");
2293             if (valMethod.type() != str_type)
2294                 throw JSONRPCError(-32600, "Method must be a string");
2295             string strMethod = valMethod.get_str();
2296             if (strMethod != "getwork" && strMethod != "getmemorypool")
2297                 printf("ThreadRPCServer method=%s\n", strMethod.c_str());
2298
2299             // Parse params
2300             Value valParams = find_value(request, "params");
2301             Array params;
2302             if (valParams.type() == array_type)
2303                 params = valParams.get_array();
2304             else if (valParams.type() == null_type)
2305                 params = Array();
2306             else
2307                 throw JSONRPCError(-32600, "Params must be an array");
2308
2309             // Find method
2310             map<string, rpcfn_type>::iterator mi = mapCallTable.find(strMethod);
2311             if (mi == mapCallTable.end())
2312                 throw JSONRPCError(-32601, "Method not found");
2313
2314             // Observe safe mode
2315             string strWarning = GetWarnings("rpc");
2316             if (strWarning != "" && !GetBoolArg("-disablesafemode") && !setAllowInSafeMode.count(strMethod))
2317                 throw JSONRPCError(-2, string("Safe mode: ") + strWarning);
2318
2319             try
2320             {
2321                 // Execute
2322                 Value result;
2323                 CRITICAL_BLOCK(cs_main)
2324                 CRITICAL_BLOCK(pwalletMain->cs_wallet)
2325                     result = (*(*mi).second)(params, false);
2326
2327                 // Send reply
2328                 string strReply = JSONRPCReply(result, Value::null, id);
2329                 stream << HTTPReply(200, strReply) << std::flush;
2330             }
2331             catch (std::exception& e)
2332             {
2333                 ErrorReply(stream, JSONRPCError(-1, e.what()), id);
2334             }
2335         }
2336         catch (Object& objError)
2337         {
2338             ErrorReply(stream, objError, id);
2339         }
2340         catch (std::exception& e)
2341         {
2342             ErrorReply(stream, JSONRPCError(-32700, e.what()), id);
2343         }
2344     }
2345 }
2346
2347
2348
2349
2350 Object CallRPC(const string& strMethod, const Array& params)
2351 {
2352     if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
2353         throw runtime_error(strprintf(
2354             _("You must set rpcpassword=<password> in the configuration file:\n%s\n"
2355               "If the file does not exist, create it with owner-readable-only file permissions."),
2356                 GetConfigFile().c_str()));
2357
2358     // Connect to localhost
2359     bool fUseSSL = GetBoolArg("-rpcssl");
2360 #ifdef USE_SSL
2361     asio::io_service io_service;
2362     ssl::context context(io_service, ssl::context::sslv23);
2363     context.set_options(ssl::context::no_sslv2);
2364     SSLStream sslStream(io_service, context);
2365     SSLIOStreamDevice d(sslStream, fUseSSL);
2366     iostreams::stream<SSLIOStreamDevice> stream(d);
2367     if (!d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332")))
2368         throw runtime_error("couldn't connect to server");
2369 #else
2370     if (fUseSSL)
2371         throw runtime_error("-rpcssl=1, but bitcoin compiled without full openssl libraries.");
2372
2373     ip::tcp::iostream stream(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332"));
2374     if (stream.fail())
2375         throw runtime_error("couldn't connect to server");
2376 #endif
2377
2378
2379     // HTTP basic authentication
2380     string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
2381     map<string, string> mapRequestHeaders;
2382     mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64;
2383
2384     // Send request
2385     string strRequest = JSONRPCRequest(strMethod, params, 1);
2386     string strPost = HTTPPost(strRequest, mapRequestHeaders);
2387     stream << strPost << std::flush;
2388
2389     // Receive reply
2390     map<string, string> mapHeaders;
2391     string strReply;
2392     int nStatus = ReadHTTP(stream, mapHeaders, strReply);
2393     if (nStatus == 401)
2394         throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
2395     else if (nStatus >= 400 && nStatus != 400 && nStatus != 404 && nStatus != 500)
2396         throw runtime_error(strprintf("server returned HTTP error %d", nStatus));
2397     else if (strReply.empty())
2398         throw runtime_error("no response from server");
2399
2400     // Parse reply
2401     Value valReply;
2402     if (!read_string(strReply, valReply))
2403         throw runtime_error("couldn't parse reply from server");
2404     const Object& reply = valReply.get_obj();
2405     if (reply.empty())
2406         throw runtime_error("expected reply to have result, error and id properties");
2407
2408     return reply;
2409 }
2410
2411
2412
2413
2414 template<typename T>
2415 void ConvertTo(Value& value)
2416 {
2417     if (value.type() == str_type)
2418     {
2419         // reinterpret string as unquoted json value
2420         Value value2;
2421         if (!read_string(value.get_str(), value2))
2422             throw runtime_error("type mismatch");
2423         value = value2.get_value<T>();
2424     }
2425     else
2426     {
2427         value = value.get_value<T>();
2428     }
2429 }
2430
2431 int CommandLineRPC(int argc, char *argv[])
2432 {
2433     string strPrint;
2434     int nRet = 0;
2435     try
2436     {
2437         // Skip switches
2438         while (argc > 1 && IsSwitchChar(argv[1][0]))
2439         {
2440             argc--;
2441             argv++;
2442         }
2443
2444         // Method
2445         if (argc < 2)
2446             throw runtime_error("too few parameters");
2447         string strMethod = argv[1];
2448
2449         // Parameters default to strings
2450         Array params;
2451         for (int i = 2; i < argc; i++)
2452             params.push_back(argv[i]);
2453         int n = params.size();
2454
2455         //
2456         // Special case non-string parameter types
2457         //
2458         if (strMethod == "setgenerate"            && n > 0) ConvertTo<bool>(params[0]);
2459         if (strMethod == "setgenerate"            && n > 1) ConvertTo<boost::int64_t>(params[1]);
2460         if (strMethod == "sendtoaddress"          && n > 1) ConvertTo<double>(params[1]);
2461         if (strMethod == "settxfee"               && n > 0) ConvertTo<double>(params[0]);
2462         if (strMethod == "getreceivedbyaddress"   && n > 1) ConvertTo<boost::int64_t>(params[1]);
2463         if (strMethod == "getreceivedbyaccount"   && n > 1) ConvertTo<boost::int64_t>(params[1]);
2464         if (strMethod == "listreceivedbyaddress"  && n > 0) ConvertTo<boost::int64_t>(params[0]);
2465         if (strMethod == "listreceivedbyaddress"  && n > 1) ConvertTo<bool>(params[1]);
2466         if (strMethod == "listreceivedbyaccount"  && n > 0) ConvertTo<boost::int64_t>(params[0]);
2467         if (strMethod == "listreceivedbyaccount"  && n > 1) ConvertTo<bool>(params[1]);
2468         if (strMethod == "getbalance"             && n > 1) ConvertTo<boost::int64_t>(params[1]);
2469         if (strMethod == "move"                   && n > 2) ConvertTo<double>(params[2]);
2470         if (strMethod == "move"                   && n > 3) ConvertTo<boost::int64_t>(params[3]);
2471         if (strMethod == "sendfrom"               && n > 2) ConvertTo<double>(params[2]);
2472         if (strMethod == "sendfrom"               && n > 3) ConvertTo<boost::int64_t>(params[3]);
2473         if (strMethod == "listtransactions"       && n > 1) ConvertTo<boost::int64_t>(params[1]);
2474         if (strMethod == "listtransactions"       && n > 2) ConvertTo<boost::int64_t>(params[2]);
2475         if (strMethod == "listaccounts"           && n > 0) ConvertTo<boost::int64_t>(params[0]);
2476         if (strMethod == "walletpassphrase"       && n > 1) ConvertTo<boost::int64_t>(params[1]);
2477         if (strMethod == "listsinceblock"         && n > 1) ConvertTo<boost::int64_t>(params[1]);
2478         if (strMethod == "sendmany"               && n > 1)
2479         {
2480             string s = params[1].get_str();
2481             Value v;
2482             if (!read_string(s, v) || v.type() != obj_type)
2483                 throw runtime_error("type mismatch");
2484             params[1] = v.get_obj();
2485         }
2486         if (strMethod == "sendmany"                && n > 2) ConvertTo<boost::int64_t>(params[2]);
2487
2488         // Execute
2489         Object reply = CallRPC(strMethod, params);
2490
2491         // Parse reply
2492         const Value& result = find_value(reply, "result");
2493         const Value& error  = find_value(reply, "error");
2494
2495         if (error.type() != null_type)
2496         {
2497             // Error
2498             strPrint = "error: " + write_string(error, false);
2499             int code = find_value(error.get_obj(), "code").get_int();
2500             nRet = abs(code);
2501         }
2502         else
2503         {
2504             // Result
2505             if (result.type() == null_type)
2506                 strPrint = "";
2507             else if (result.type() == str_type)
2508                 strPrint = result.get_str();
2509             else
2510                 strPrint = write_string(result, true);
2511         }
2512     }
2513     catch (std::exception& e)
2514     {
2515         strPrint = string("error: ") + e.what();
2516         nRet = 87;
2517     }
2518     catch (...)
2519     {
2520         PrintException(NULL, "CommandLineRPC()");
2521     }
2522
2523     if (strPrint != "")
2524     {
2525         fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
2526     }
2527     return nRet;
2528 }
2529
2530
2531
2532
2533 #ifdef TEST
2534 int main(int argc, char *argv[])
2535 {
2536 #ifdef _MSC_VER
2537     // Turn off microsoft heap dump noise
2538     _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
2539     _CrtSetReportFile(_CRT_WARN, CreateFile("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0));
2540 #endif
2541     setbuf(stdin, NULL);
2542     setbuf(stdout, NULL);
2543     setbuf(stderr, NULL);
2544
2545     try
2546     {
2547         if (argc >= 2 && string(argv[1]) == "-server")
2548         {
2549             printf("server ready\n");
2550             ThreadRPCServer(NULL);
2551         }
2552         else
2553         {
2554             return CommandLineRPC(argc, argv);
2555         }
2556     }
2557     catch (std::exception& e) {
2558         PrintException(&e, "main()");
2559     } catch (...) {
2560         PrintException(NULL, "main()");
2561     }
2562     return 0;
2563 }
2564 #endif