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