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