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