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