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