Merge pull request #632 from mndrix/deprecate-getblocknumber
[novacoin.git] / src / bitcoinrpc.cpp
1 // Copyright (c) 2010 Satoshi Nakamoto
2 // Copyright (c) 2011 The Bitcoin developers
3 // Distributed under the MIT/X11 software license, see the accompanying
4 // file license.txt or http://www.opensource.org/licenses/mit-license.php.
5
6 #include "headers.h"
7 #include "db.h"
8 #include "net.h"
9 #include "init.h"
10 #undef printf
11 #include <boost/asio.hpp>
12 #include <boost/iostreams/concepts.hpp>
13 #include <boost/iostreams/stream.hpp>
14 #include <boost/algorithm/string.hpp>
15 #ifdef USE_SSL
16 #include <boost/asio/ssl.hpp> 
17 #include <boost/filesystem.hpp>
18 #include <boost/filesystem/fstream.hpp>
19 typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> SSLStream;
20 #endif
21 #include "json/json_spirit_reader_template.h"
22 #include "json/json_spirit_writer_template.h"
23 #include "json/json_spirit_utils.h"
24 #define printf OutputDebugStringF
25 // MinGW 3.4.5 gets "fatal error: had to relocate PCH" if the json headers are
26 // precompiled in headers.h.  The problem might be when the pch file goes over
27 // a certain size around 145MB.  If we need access to json_spirit outside this
28 // file, we could use the compiled json_spirit option.
29
30 using namespace std;
31 using namespace boost;
32 using namespace boost::asio;
33 using namespace json_spirit;
34
35 void ThreadRPCServer2(void* parg);
36 typedef Value(*rpcfn_type)(const Array& params, bool fHelp);
37 extern map<string, rpcfn_type> mapCallTable;
38
39 static int64 nWalletUnlockTime;
40 static CCriticalSection cs_nWalletUnlockTime;
41
42
43 Object JSONRPCError(int code, const string& message)
44 {
45     Object error;
46     error.push_back(Pair("code", code));
47     error.push_back(Pair("message", message));
48     return error;
49 }
50
51
52 void PrintConsole(const std::string &format, ...)
53 {
54     char buffer[50000];
55     int limit = sizeof(buffer);
56     va_list arg_ptr;
57     va_start(arg_ptr, format);
58     int ret = _vsnprintf(buffer, limit, format.c_str(), arg_ptr);
59     va_end(arg_ptr);
60     if (ret < 0 || ret >= limit)
61     {
62         ret = limit - 1;
63         buffer[limit-1] = 0;
64     }
65     printf("%s", buffer);
66     fprintf(stdout, "%s", buffer);
67 }
68
69
70 int64 AmountFromValue(const Value& value)
71 {
72     double dAmount = value.get_real();
73     if (dAmount <= 0.0 || dAmount > 21000000.0)
74         throw JSONRPCError(-3, "Invalid amount");
75     int64 nAmount = roundint64(dAmount * COIN);
76     if (!MoneyRange(nAmount))
77         throw JSONRPCError(-3, "Invalid amount");
78     return nAmount;
79 }
80
81 Value ValueFromAmount(int64 amount)
82 {
83     return (double)amount / (double)COIN;
84 }
85
86 void WalletTxToJSON(const CWalletTx& wtx, Object& entry)
87 {
88     entry.push_back(Pair("confirmations", wtx.GetDepthInMainChain()));
89     entry.push_back(Pair("txid", wtx.GetHash().GetHex()));
90     entry.push_back(Pair("time", (boost::int64_t)wtx.GetTxTime()));
91     BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue)
92         entry.push_back(Pair(item.first, item.second));
93 }
94
95 string AccountFromValue(const Value& value)
96 {
97     string strAccount = value.get_str();
98     if (strAccount == "*")
99         throw JSONRPCError(-11, "Invalid account name");
100     return strAccount;
101 }
102
103
104
105 ///
106 /// Note: This interface may still be subject to change.
107 ///
108
109
110 Value help(const Array& params, bool fHelp)
111 {
112     if (fHelp || params.size() > 1)
113         throw runtime_error(
114             "help [command]\n"
115             "List commands, or get help for a command.");
116
117     string strCommand;
118     if (params.size() > 0)
119         strCommand = params[0].get_str();
120
121     string strRet;
122     set<rpcfn_type> setDone;
123     for (map<string, rpcfn_type>::iterator mi = mapCallTable.begin(); mi != mapCallTable.end(); ++mi)
124     {
125         string strMethod = (*mi).first;
126         // We already filter duplicates, but these deprecated screw up the sort order
127         if (strMethod == "getamountreceived" ||
128             strMethod == "getallreceived" ||
129             strMethod == "getblocknumber" || // deprecated
130             (strMethod.find("label") != string::npos))
131             continue;
132         if (strCommand != "" && strMethod != strCommand)
133             continue;
134         try
135         {
136             Array params;
137             rpcfn_type pfn = (*mi).second;
138             if (setDone.insert(pfn).second)
139                 (*pfn)(params, true);
140         }
141         catch (std::exception& e)
142         {
143             // Help text is returned in an exception
144             string strHelp = string(e.what());
145             if (strCommand == "")
146                 if (strHelp.find('\n') != -1)
147                     strHelp = strHelp.substr(0, strHelp.find('\n'));
148             strRet += strHelp + "\n";
149         }
150     }
151     if (strRet == "")
152         strRet = strprintf("help: unknown command: %s\n", strCommand.c_str());
153     strRet = strRet.substr(0,strRet.size()-1);
154     return strRet;
155 }
156
157
158 Value stop(const Array& params, bool fHelp)
159 {
160     if (fHelp || params.size() != 0)
161         throw runtime_error(
162             "stop\n"
163             "Stop bitcoin server.");
164 #ifndef QT_GUI
165     // Shutdown will take long enough that the response should get back
166     CreateThread(Shutdown, NULL);
167     return "bitcoin server stopping";
168 #else
169     throw runtime_error("NYI: cannot shut down GUI with RPC command");
170 #endif
171 }
172
173
174 Value getblockcount(const Array& params, bool fHelp)
175 {
176     if (fHelp || params.size() != 0)
177         throw runtime_error(
178             "getblockcount\n"
179             "Returns the number of blocks in the longest block chain.");
180
181     return nBestHeight;
182 }
183
184
185 // deprecated
186 Value getblocknumber(const Array& params, bool fHelp)
187 {
188     if (fHelp || params.size() != 0)
189         throw runtime_error(
190             "getblocknumber\n"
191             "Deprecated.  Use getblockcount.");
192
193     return nBestHeight;
194 }
195
196
197 Value getconnectioncount(const Array& params, bool fHelp)
198 {
199     if (fHelp || params.size() != 0)
200         throw runtime_error(
201             "getconnectioncount\n"
202             "Returns the number of connections to other nodes.");
203
204     return (int)vNodes.size();
205 }
206
207
208 double GetDifficulty()
209 {
210     // Floating point number that is a multiple of the minimum difficulty,
211     // minimum difficulty = 1.0.
212
213     if (pindexBest == NULL)
214         return 1.0;
215     int nShift = (pindexBest->nBits >> 24) & 0xff;
216
217     double dDiff =
218         (double)0x0000ffff / (double)(pindexBest->nBits & 0x00ffffff);
219
220     while (nShift < 29)
221     {
222         dDiff *= 256.0;
223         nShift++;
224     }
225     while (nShift > 29)
226     {
227         dDiff /= 256.0;
228         nShift--;
229     }
230
231     return dDiff;
232 }
233
234 Value getdifficulty(const Array& params, bool fHelp)
235 {
236     if (fHelp || params.size() != 0)
237         throw runtime_error(
238             "getdifficulty\n"
239             "Returns the proof-of-work difficulty as a multiple of the minimum difficulty.");
240
241     return GetDifficulty();
242 }
243
244
245 Value getgenerate(const Array& params, bool fHelp)
246 {
247     if (fHelp || params.size() != 0)
248         throw runtime_error(
249             "getgenerate\n"
250             "Returns true or false.");
251
252     return (bool)fGenerateBitcoins;
253 }
254
255
256 Value setgenerate(const Array& params, bool fHelp)
257 {
258     if (fHelp || params.size() < 1 || params.size() > 2)
259         throw runtime_error(
260             "setgenerate <generate> [genproclimit]\n"
261             "<generate> is true or false to turn generation on or off.\n"
262             "Generation is limited to [genproclimit] processors, -1 is unlimited.");
263
264     bool fGenerate = true;
265     if (params.size() > 0)
266         fGenerate = params[0].get_bool();
267
268     if (params.size() > 1)
269     {
270         int nGenProcLimit = params[1].get_int();
271         fLimitProcessors = (nGenProcLimit != -1);
272         WriteSetting("fLimitProcessors", fLimitProcessors);
273         if (nGenProcLimit != -1)
274             WriteSetting("nLimitProcessors", nLimitProcessors = nGenProcLimit);
275         if (nGenProcLimit == 0)
276             fGenerate = false;
277     }
278
279     GenerateBitcoins(fGenerate, pwalletMain);
280     return Value::null;
281 }
282
283
284 Value gethashespersec(const Array& params, bool fHelp)
285 {
286     if (fHelp || params.size() != 0)
287         throw runtime_error(
288             "gethashespersec\n"
289             "Returns a recent hashes per second performance measurement while generating.");
290
291     if (GetTimeMillis() - nHPSTimerStart > 8000)
292         return (boost::int64_t)0;
293     return (boost::int64_t)dHashesPerSec;
294 }
295
296
297 Value getinfo(const Array& params, bool fHelp)
298 {
299     if (fHelp || params.size() != 0)
300         throw runtime_error(
301             "getinfo\n"
302             "Returns an object containing various state info.");
303
304     Object obj;
305     obj.push_back(Pair("version",       (int)VERSION));
306     obj.push_back(Pair("balance",       ValueFromAmount(pwalletMain->GetBalance())));
307     obj.push_back(Pair("blocks",        (int)nBestHeight));
308     obj.push_back(Pair("connections",   (int)vNodes.size()));
309     obj.push_back(Pair("proxy",         (fUseProxy ? addrProxy.ToStringIPPort() : string())));
310     obj.push_back(Pair("generate",      (bool)fGenerateBitcoins));
311     obj.push_back(Pair("genproclimit",  (int)(fLimitProcessors ? nLimitProcessors : -1)));
312     obj.push_back(Pair("difficulty",    (double)GetDifficulty()));
313     obj.push_back(Pair("hashespersec",  gethashespersec(params, false)));
314     obj.push_back(Pair("testnet",       fTestNet));
315     obj.push_back(Pair("keypoololdest", (boost::int64_t)pwalletMain->GetOldestKeyPoolTime()));
316     obj.push_back(Pair("keypoolsize",   pwalletMain->GetKeyPoolSize()));
317     obj.push_back(Pair("paytxfee",      ValueFromAmount(nTransactionFee)));
318     if (pwalletMain->IsCrypted())
319         obj.push_back(Pair("unlocked_until", (boost::int64_t)nWalletUnlockTime));
320     obj.push_back(Pair("errors",        GetWarnings("statusbar")));
321     return obj;
322 }
323
324
325 Value getnewaddress(const Array& params, bool fHelp)
326 {
327     if (fHelp || params.size() > 1)
328         throw runtime_error(
329             "getnewaddress [account]\n"
330             "Returns a new bitcoin address for receiving payments.  "
331             "If [account] is specified (recommended), it is added to the address book "
332             "so payments received with the address will be credited to [account].");
333
334     // Parse the account first so we don't generate a key if there's an error
335     string strAccount;
336     if (params.size() > 0)
337         strAccount = AccountFromValue(params[0]);
338
339     if (!pwalletMain->IsLocked())
340         pwalletMain->TopUpKeyPool();
341
342     // Generate a new key that is added to wallet
343     std::vector<unsigned char> newKey;
344     if (!pwalletMain->GetKeyFromPool(newKey, false))
345         throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
346     CBitcoinAddress address(newKey);
347
348     pwalletMain->SetAddressBookName(address, strAccount);
349
350     return address.ToString();
351 }
352
353
354 CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false)
355 {
356     CWalletDB walletdb(pwalletMain->strWalletFile);
357
358     CAccount account;
359     walletdb.ReadAccount(strAccount, account);
360
361     bool bKeyUsed = false;
362
363     // Check if the current key has been used
364     if (!account.vchPubKey.empty())
365     {
366         CScript scriptPubKey;
367         scriptPubKey.SetBitcoinAddress(account.vchPubKey);
368         for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
369              it != pwalletMain->mapWallet.end() && !account.vchPubKey.empty();
370              ++it)
371         {
372             const CWalletTx& wtx = (*it).second;
373             BOOST_FOREACH(const CTxOut& txout, wtx.vout)
374                 if (txout.scriptPubKey == scriptPubKey)
375                     bKeyUsed = true;
376         }
377     }
378
379     // Generate a new key
380     if (account.vchPubKey.empty() || bForceNew || bKeyUsed)
381     {
382         if (!pwalletMain->GetKeyFromPool(account.vchPubKey, false))
383             throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
384
385         pwalletMain->SetAddressBookName(CBitcoinAddress(account.vchPubKey), strAccount);
386         walletdb.WriteAccount(strAccount, account);
387     }
388
389     return CBitcoinAddress(account.vchPubKey);
390 }
391
392 Value getaccountaddress(const Array& params, bool fHelp)
393 {
394     if (fHelp || params.size() != 1)
395         throw runtime_error(
396             "getaccountaddress <account>\n"
397             "Returns the current bitcoin address for receiving payments to this account.");
398
399     // Parse the account first so we don't generate a key if there's an error
400     string strAccount = AccountFromValue(params[0]);
401
402     Value ret;
403
404     ret = GetAccountAddress(strAccount).ToString();
405
406     return ret;
407 }
408
409
410
411 Value setaccount(const Array& params, bool fHelp)
412 {
413     if (fHelp || params.size() < 1 || params.size() > 2)
414         throw runtime_error(
415             "setaccount <bitcoinaddress> <account>\n"
416             "Sets the account associated with the given address.");
417
418     CBitcoinAddress address(params[0].get_str());
419     if (!address.IsValid())
420         throw JSONRPCError(-5, "Invalid bitcoin address");
421
422
423     string strAccount;
424     if (params.size() > 1)
425         strAccount = AccountFromValue(params[1]);
426
427     // Detect when changing the account of an address that is the 'unused current key' of another account:
428     if (pwalletMain->mapAddressBook.count(address))
429     {
430         string strOldAccount = pwalletMain->mapAddressBook[address];
431         if (address == GetAccountAddress(strOldAccount))
432             GetAccountAddress(strOldAccount, true);
433     }
434
435     pwalletMain->SetAddressBookName(address, strAccount);
436
437     return Value::null;
438 }
439
440
441 Value getaccount(const Array& params, bool fHelp)
442 {
443     if (fHelp || params.size() != 1)
444         throw runtime_error(
445             "getaccount <bitcoinaddress>\n"
446             "Returns the account associated with the given address.");
447
448     CBitcoinAddress address(params[0].get_str());
449     if (!address.IsValid())
450         throw JSONRPCError(-5, "Invalid bitcoin address");
451
452     string strAccount;
453     map<CBitcoinAddress, string>::iterator mi = pwalletMain->mapAddressBook.find(address);
454     if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.empty())
455         strAccount = (*mi).second;
456     return strAccount;
457 }
458
459
460 Value getaddressesbyaccount(const Array& params, bool fHelp)
461 {
462     if (fHelp || params.size() != 1)
463         throw runtime_error(
464             "getaddressesbyaccount <account>\n"
465             "Returns the list of addresses for the given account.");
466
467     string strAccount = AccountFromValue(params[0]);
468
469     // Find all addresses that have the given account
470     Array ret;
471     BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
472     {
473         const CBitcoinAddress& address = item.first;
474         const string& strName = item.second;
475         if (strName == strAccount)
476             ret.push_back(address.ToString());
477     }
478     return ret;
479 }
480
481 Value settxfee(const Array& params, bool fHelp)
482 {
483     if (fHelp || params.size() < 1 || params.size() > 1)
484         throw runtime_error(
485             "settxfee <amount>\n"
486             "<amount> is a real and is rounded to the nearest 0.00000001");
487
488     // Amount
489     int64 nAmount = 0;
490     if (params[0].get_real() != 0.0)
491         nAmount = AmountFromValue(params[0]);        // rejects 0.0 amounts
492
493     nTransactionFee = nAmount;
494     return true;
495 }
496
497 Value sendtoaddress(const Array& params, bool fHelp)
498 {
499     if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
500         throw runtime_error(
501             "sendtoaddress <bitcoinaddress> <amount> [comment] [comment-to]\n"
502             "<amount> is a real and is rounded to the nearest 0.00000001\n"
503             "requires wallet passphrase to be set with walletpassphrase first");
504     if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
505         throw runtime_error(
506             "sendtoaddress <bitcoinaddress> <amount> [comment] [comment-to]\n"
507             "<amount> is a real and is rounded to the nearest 0.00000001");
508
509     CBitcoinAddress address(params[0].get_str());
510     if (!address.IsValid())
511         throw JSONRPCError(-5, "Invalid bitcoin address");
512
513     // Amount
514     int64 nAmount = AmountFromValue(params[1]);
515
516     // Wallet comments
517     CWalletTx wtx;
518     if (params.size() > 2 && params[2].type() != null_type && !params[2].get_str().empty())
519         wtx.mapValue["comment"] = params[2].get_str();
520     if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
521         wtx.mapValue["to"]      = params[3].get_str();
522
523     if (pwalletMain->IsLocked())
524         throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
525
526     string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
527     if (strError != "")
528         throw JSONRPCError(-4, strError);
529
530     return wtx.GetHash().GetHex();
531 }
532
533 static const string strMessageMagic = "Bitcoin Signed Message:\n";
534
535 Value signmessage(const Array& params, bool fHelp)
536 {
537     if (fHelp || params.size() != 2)
538         throw runtime_error(
539             "signmessage <bitcoinaddress> <message>\n"
540             "Sign a message with the private key of an address");
541
542     if (pwalletMain->IsLocked())
543         throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
544
545     string strAddress = params[0].get_str();
546     string strMessage = params[1].get_str();
547
548     CBitcoinAddress addr(strAddress);
549     if (!addr.IsValid())
550         throw JSONRPCError(-3, "Invalid address");
551
552     CKey key;
553     if (!pwalletMain->GetKey(addr, key))
554         throw JSONRPCError(-4, "Private key not available");
555
556     CDataStream ss(SER_GETHASH);
557     ss << strMessageMagic;
558     ss << strMessage;
559
560     vector<unsigned char> vchSig;
561     if (!key.SignCompact(Hash(ss.begin(), ss.end()), vchSig))
562         throw JSONRPCError(-5, "Sign failed");
563
564     return EncodeBase64(&vchSig[0], vchSig.size());
565 }
566
567 Value verifymessage(const Array& params, bool fHelp)
568 {
569     if (fHelp || params.size() != 3)
570         throw runtime_error(
571             "verifymessage <bitcoinaddress> <signature> <message>\n"
572             "Verify a signed message");
573
574     string strAddress  = params[0].get_str();
575     string strSign     = params[1].get_str();
576     string strMessage  = params[2].get_str();
577
578     CBitcoinAddress addr(strAddress);
579     if (!addr.IsValid())
580         throw JSONRPCError(-3, "Invalid address");
581
582     bool fInvalid = false;
583     vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid);
584
585     if (fInvalid)
586         throw JSONRPCError(-5, "Malformed base64 encoding");
587
588     CDataStream ss(SER_GETHASH);
589     ss << strMessageMagic;
590     ss << strMessage;
591
592     CKey key;
593     if (!key.SetCompactSignature(Hash(ss.begin(), ss.end()), vchSig))
594         return false;
595
596     return (key.GetAddress() == addr);
597 }
598
599
600 Value getreceivedbyaddress(const Array& params, bool fHelp)
601 {
602     if (fHelp || params.size() < 1 || params.size() > 2)
603         throw runtime_error(
604             "getreceivedbyaddress <bitcoinaddress> [minconf=1]\n"
605             "Returns the total amount received by <bitcoinaddress> in transactions with at least [minconf] confirmations.");
606
607     // Bitcoin address
608     CBitcoinAddress address = CBitcoinAddress(params[0].get_str());
609     CScript scriptPubKey;
610     if (!address.IsValid())
611         throw JSONRPCError(-5, "Invalid bitcoin address");
612     scriptPubKey.SetBitcoinAddress(address);
613     if (!IsMine(*pwalletMain,scriptPubKey))
614         return (double)0.0;
615
616     // Minimum confirmations
617     int nMinDepth = 1;
618     if (params.size() > 1)
619         nMinDepth = params[1].get_int();
620
621     // Tally
622     int64 nAmount = 0;
623     for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
624     {
625         const CWalletTx& wtx = (*it).second;
626         if (wtx.IsCoinBase() || !wtx.IsFinal())
627             continue;
628
629         BOOST_FOREACH(const CTxOut& txout, wtx.vout)
630             if (txout.scriptPubKey == scriptPubKey)
631                 if (wtx.GetDepthInMainChain() >= nMinDepth)
632                     nAmount += txout.nValue;
633     }
634
635     return  ValueFromAmount(nAmount);
636 }
637
638
639 void GetAccountAddresses(string strAccount, set<CBitcoinAddress>& setAddress)
640 {
641     BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
642     {
643         const CBitcoinAddress& address = item.first;
644         const string& strName = item.second;
645         if (strName == strAccount)
646             setAddress.insert(address);
647     }
648 }
649
650
651 Value getreceivedbyaccount(const Array& params, bool fHelp)
652 {
653     if (fHelp || params.size() < 1 || params.size() > 2)
654         throw runtime_error(
655             "getreceivedbyaccount <account> [minconf=1]\n"
656             "Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.");
657
658     // Minimum confirmations
659     int nMinDepth = 1;
660     if (params.size() > 1)
661         nMinDepth = params[1].get_int();
662
663     // Get the set of pub keys that have the label
664     string strAccount = AccountFromValue(params[0]);
665     set<CBitcoinAddress> setAddress;
666     GetAccountAddresses(strAccount, setAddress);
667
668     // Tally
669     int64 nAmount = 0;
670     for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
671     {
672         const CWalletTx& wtx = (*it).second;
673         if (wtx.IsCoinBase() || !wtx.IsFinal())
674             continue;
675
676         BOOST_FOREACH(const CTxOut& txout, wtx.vout)
677         {
678             CBitcoinAddress address;
679             if (ExtractAddress(txout.scriptPubKey, pwalletMain, address) && setAddress.count(address))
680                 if (wtx.GetDepthInMainChain() >= nMinDepth)
681                     nAmount += txout.nValue;
682         }
683     }
684
685     return (double)nAmount / (double)COIN;
686 }
687
688
689 int64 GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth)
690 {
691     int64 nBalance = 0;
692
693     // Tally wallet transactions
694     for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
695     {
696         const CWalletTx& wtx = (*it).second;
697         if (!wtx.IsFinal())
698             continue;
699
700         int64 nGenerated, nReceived, nSent, nFee;
701         wtx.GetAccountAmounts(strAccount, nGenerated, nReceived, nSent, nFee);
702
703         if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
704             nBalance += nReceived;
705         nBalance += nGenerated - nSent - nFee;
706     }
707
708     // Tally internal accounting entries
709     nBalance += walletdb.GetAccountCreditDebit(strAccount);
710
711     return nBalance;
712 }
713
714 int64 GetAccountBalance(const string& strAccount, int nMinDepth)
715 {
716     CWalletDB walletdb(pwalletMain->strWalletFile);
717     return GetAccountBalance(walletdb, strAccount, nMinDepth);
718 }
719
720
721 Value getbalance(const Array& params, bool fHelp)
722 {
723     if (fHelp || params.size() > 2)
724         throw runtime_error(
725             "getbalance [account] [minconf=1]\n"
726             "If [account] is not specified, returns the server's total available balance.\n"
727             "If [account] is specified, returns the balance in the account.");
728
729     if (params.size() == 0)
730         return  ValueFromAmount(pwalletMain->GetBalance());
731
732     int nMinDepth = 1;
733     if (params.size() > 1)
734         nMinDepth = params[1].get_int();
735
736     if (params[0].get_str() == "*") {
737         // Calculate total balance a different way from GetBalance()
738         // (GetBalance() sums up all unspent TxOuts)
739         // getbalance and getbalance '*' should always return the same number.
740         int64 nBalance = 0;
741         for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
742         {
743             const CWalletTx& wtx = (*it).second;
744             if (!wtx.IsFinal())
745                 continue;
746
747             int64 allGeneratedImmature, allGeneratedMature, allFee;
748             allGeneratedImmature = allGeneratedMature = allFee = 0;
749             string strSentAccount;
750             list<pair<CBitcoinAddress, int64> > listReceived;
751             list<pair<CBitcoinAddress, int64> > listSent;
752             wtx.GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount);
753             if (wtx.GetDepthInMainChain() >= nMinDepth)
754                 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listReceived)
755                     nBalance += r.second;
756             BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listSent)
757                 nBalance -= r.second;
758             nBalance -= allFee;
759             nBalance += allGeneratedMature;
760         }
761         return  ValueFromAmount(nBalance);
762     }
763
764     string strAccount = AccountFromValue(params[0]);
765
766     int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
767
768     return ValueFromAmount(nBalance);
769 }
770
771
772 Value movecmd(const Array& params, bool fHelp)
773 {
774     if (fHelp || params.size() < 3 || params.size() > 5)
775         throw runtime_error(
776             "move <fromaccount> <toaccount> <amount> [minconf=1] [comment]\n"
777             "Move from one account in your wallet to another.");
778
779     string strFrom = AccountFromValue(params[0]);
780     string strTo = AccountFromValue(params[1]);
781     int64 nAmount = AmountFromValue(params[2]);
782     if (params.size() > 3)
783         // unused parameter, used to be nMinDepth, keep type-checking it though
784         (void)params[3].get_int();
785     string strComment;
786     if (params.size() > 4)
787         strComment = params[4].get_str();
788
789     CWalletDB walletdb(pwalletMain->strWalletFile);
790     walletdb.TxnBegin();
791
792     int64 nNow = GetAdjustedTime();
793
794     // Debit
795     CAccountingEntry debit;
796     debit.strAccount = strFrom;
797     debit.nCreditDebit = -nAmount;
798     debit.nTime = nNow;
799     debit.strOtherAccount = strTo;
800     debit.strComment = strComment;
801     walletdb.WriteAccountingEntry(debit);
802
803     // Credit
804     CAccountingEntry credit;
805     credit.strAccount = strTo;
806     credit.nCreditDebit = nAmount;
807     credit.nTime = nNow;
808     credit.strOtherAccount = strFrom;
809     credit.strComment = strComment;
810     walletdb.WriteAccountingEntry(credit);
811
812     walletdb.TxnCommit();
813
814     return true;
815 }
816
817
818 Value sendfrom(const Array& params, bool fHelp)
819 {
820     if (pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
821         throw runtime_error(
822             "sendfrom <fromaccount> <tobitcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
823             "<amount> is a real and is rounded to the nearest 0.00000001\n"
824             "requires wallet passphrase to be set with walletpassphrase first");
825     if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
826         throw runtime_error(
827             "sendfrom <fromaccount> <tobitcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
828             "<amount> is a real and is rounded to the nearest 0.00000001");
829
830     string strAccount = AccountFromValue(params[0]);
831     CBitcoinAddress address(params[1].get_str());
832     if (!address.IsValid())
833         throw JSONRPCError(-5, "Invalid bitcoin address");
834     int64 nAmount = AmountFromValue(params[2]);
835     int nMinDepth = 1;
836     if (params.size() > 3)
837         nMinDepth = params[3].get_int();
838
839     CWalletTx wtx;
840     wtx.strFromAccount = strAccount;
841     if (params.size() > 4 && params[4].type() != null_type && !params[4].get_str().empty())
842         wtx.mapValue["comment"] = params[4].get_str();
843     if (params.size() > 5 && params[5].type() != null_type && !params[5].get_str().empty())
844         wtx.mapValue["to"]      = params[5].get_str();
845
846     if (pwalletMain->IsLocked())
847         throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
848
849     // Check funds
850     int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
851     if (nAmount > nBalance)
852         throw JSONRPCError(-6, "Account has insufficient funds");
853
854     // Send
855     string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
856     if (strError != "")
857         throw JSONRPCError(-4, strError);
858
859     return wtx.GetHash().GetHex();
860 }
861
862
863 Value sendmany(const Array& params, bool fHelp)
864 {
865     if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
866         throw runtime_error(
867             "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
868             "amounts are double-precision floating point numbers\n"
869             "requires wallet passphrase to be set with walletpassphrase first");
870     if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
871         throw runtime_error(
872             "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
873             "amounts are double-precision floating point numbers");
874
875     string strAccount = AccountFromValue(params[0]);
876     Object sendTo = params[1].get_obj();
877     int nMinDepth = 1;
878     if (params.size() > 2)
879         nMinDepth = params[2].get_int();
880
881     CWalletTx wtx;
882     wtx.strFromAccount = strAccount;
883     if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
884         wtx.mapValue["comment"] = params[3].get_str();
885
886     set<CBitcoinAddress> setAddress;
887     vector<pair<CScript, int64> > vecSend;
888
889     int64 totalAmount = 0;
890     BOOST_FOREACH(const Pair& s, sendTo)
891     {
892         CBitcoinAddress address(s.name_);
893         if (!address.IsValid())
894             throw JSONRPCError(-5, string("Invalid bitcoin address:")+s.name_);
895
896         if (setAddress.count(address))
897             throw JSONRPCError(-8, string("Invalid parameter, duplicated address: ")+s.name_);
898         setAddress.insert(address);
899
900         CScript scriptPubKey;
901         scriptPubKey.SetBitcoinAddress(address);
902         int64 nAmount = AmountFromValue(s.value_); 
903         totalAmount += nAmount;
904
905         vecSend.push_back(make_pair(scriptPubKey, nAmount));
906     }
907
908     if (pwalletMain->IsLocked())
909         throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
910
911     // Check funds
912     int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
913     if (totalAmount > nBalance)
914         throw JSONRPCError(-6, "Account has insufficient funds");
915
916     // Send
917     CReserveKey keyChange(pwalletMain);
918     int64 nFeeRequired = 0;
919     bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired);
920     if (!fCreated)
921     {
922         if (totalAmount + nFeeRequired > pwalletMain->GetBalance())
923             throw JSONRPCError(-6, "Insufficient funds");
924         throw JSONRPCError(-4, "Transaction creation failed");
925     }
926     if (!pwalletMain->CommitTransaction(wtx, keyChange))
927         throw JSONRPCError(-4, "Transaction commit failed");
928
929     return wtx.GetHash().GetHex();
930 }
931
932
933 struct tallyitem
934 {
935     int64 nAmount;
936     int nConf;
937     tallyitem()
938     {
939         nAmount = 0;
940         nConf = INT_MAX;
941     }
942 };
943
944 Value ListReceived(const Array& params, bool fByAccounts)
945 {
946     // Minimum confirmations
947     int nMinDepth = 1;
948     if (params.size() > 0)
949         nMinDepth = params[0].get_int();
950
951     // Whether to include empty accounts
952     bool fIncludeEmpty = false;
953     if (params.size() > 1)
954         fIncludeEmpty = params[1].get_bool();
955
956     // Tally
957     map<CBitcoinAddress, tallyitem> mapTally;
958     for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
959     {
960         const CWalletTx& wtx = (*it).second;
961         if (wtx.IsCoinBase() || !wtx.IsFinal())
962             continue;
963
964         int nDepth = wtx.GetDepthInMainChain();
965         if (nDepth < nMinDepth)
966             continue;
967
968         BOOST_FOREACH(const CTxOut& txout, wtx.vout)
969         {
970             CBitcoinAddress address;
971             if (!ExtractAddress(txout.scriptPubKey, pwalletMain, address) || !address.IsValid())
972                 continue;
973
974             tallyitem& item = mapTally[address];
975             item.nAmount += txout.nValue;
976             item.nConf = min(item.nConf, nDepth);
977         }
978     }
979
980     // Reply
981     Array ret;
982     map<string, tallyitem> mapAccountTally;
983     BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
984     {
985         const CBitcoinAddress& address = item.first;
986         const string& strAccount = item.second;
987         map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
988         if (it == mapTally.end() && !fIncludeEmpty)
989             continue;
990
991         int64 nAmount = 0;
992         int nConf = INT_MAX;
993         if (it != mapTally.end())
994         {
995             nAmount = (*it).second.nAmount;
996             nConf = (*it).second.nConf;
997         }
998
999         if (fByAccounts)
1000         {
1001             tallyitem& item = mapAccountTally[strAccount];
1002             item.nAmount += nAmount;
1003             item.nConf = min(item.nConf, nConf);
1004         }
1005         else
1006         {
1007             Object obj;
1008             obj.push_back(Pair("address",       address.ToString()));
1009             obj.push_back(Pair("account",       strAccount));
1010             obj.push_back(Pair("amount",        ValueFromAmount(nAmount)));
1011             obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf)));
1012             ret.push_back(obj);
1013         }
1014     }
1015
1016     if (fByAccounts)
1017     {
1018         for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
1019         {
1020             int64 nAmount = (*it).second.nAmount;
1021             int nConf = (*it).second.nConf;
1022             Object obj;
1023             obj.push_back(Pair("account",       (*it).first));
1024             obj.push_back(Pair("amount",        ValueFromAmount(nAmount)));
1025             obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf)));
1026             ret.push_back(obj);
1027         }
1028     }
1029
1030     return ret;
1031 }
1032
1033 Value listreceivedbyaddress(const Array& params, bool fHelp)
1034 {
1035     if (fHelp || params.size() > 2)
1036         throw runtime_error(
1037             "listreceivedbyaddress [minconf=1] [includeempty=false]\n"
1038             "[minconf] is the minimum number of confirmations before payments are included.\n"
1039             "[includeempty] whether to include addresses that haven't received any payments.\n"
1040             "Returns an array of objects containing:\n"
1041             "  \"address\" : receiving address\n"
1042             "  \"account\" : the account of the receiving address\n"
1043             "  \"amount\" : total amount received by the address\n"
1044             "  \"confirmations\" : number of confirmations of the most recent transaction included");
1045
1046     return ListReceived(params, false);
1047 }
1048
1049 Value listreceivedbyaccount(const Array& params, bool fHelp)
1050 {
1051     if (fHelp || params.size() > 2)
1052         throw runtime_error(
1053             "listreceivedbyaccount [minconf=1] [includeempty=false]\n"
1054             "[minconf] is the minimum number of confirmations before payments are included.\n"
1055             "[includeempty] whether to include accounts that haven't received any payments.\n"
1056             "Returns an array of objects containing:\n"
1057             "  \"account\" : the account of the receiving addresses\n"
1058             "  \"amount\" : total amount received by addresses with this account\n"
1059             "  \"confirmations\" : number of confirmations of the most recent transaction included");
1060
1061     return ListReceived(params, true);
1062 }
1063
1064 void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret)
1065 {
1066     int64 nGeneratedImmature, nGeneratedMature, nFee;
1067     string strSentAccount;
1068     list<pair<CBitcoinAddress, int64> > listReceived;
1069     list<pair<CBitcoinAddress, int64> > listSent;
1070     wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1071
1072     bool fAllAccounts = (strAccount == string("*"));
1073
1074     // Generated blocks assigned to account ""
1075     if ((nGeneratedMature+nGeneratedImmature) != 0 && (fAllAccounts || strAccount == ""))
1076     {
1077         Object entry;
1078         entry.push_back(Pair("account", string("")));
1079         if (nGeneratedImmature)
1080         {
1081             entry.push_back(Pair("category", wtx.GetDepthInMainChain() ? "immature" : "orphan"));
1082             entry.push_back(Pair("amount", ValueFromAmount(nGeneratedImmature)));
1083         }
1084         else
1085         {
1086             entry.push_back(Pair("category", "generate"));
1087             entry.push_back(Pair("amount", ValueFromAmount(nGeneratedMature)));
1088         }
1089         if (fLong)
1090             WalletTxToJSON(wtx, entry);
1091         ret.push_back(entry);
1092     }
1093
1094     // Sent
1095     if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
1096     {
1097         BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1098         {
1099             Object entry;
1100             entry.push_back(Pair("account", strSentAccount));
1101             entry.push_back(Pair("address", s.first.ToString()));
1102             entry.push_back(Pair("category", "send"));
1103             entry.push_back(Pair("amount", ValueFromAmount(-s.second)));
1104             entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
1105             if (fLong)
1106                 WalletTxToJSON(wtx, entry);
1107             ret.push_back(entry);
1108         }
1109     }
1110
1111     // Received
1112     if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
1113         BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1114         {
1115             string account;
1116             if (pwalletMain->mapAddressBook.count(r.first))
1117                 account = pwalletMain->mapAddressBook[r.first];
1118             if (fAllAccounts || (account == strAccount))
1119             {
1120                 Object entry;
1121                 entry.push_back(Pair("account", account));
1122                 entry.push_back(Pair("address", r.first.ToString()));
1123                 entry.push_back(Pair("category", "receive"));
1124                 entry.push_back(Pair("amount", ValueFromAmount(r.second)));
1125                 if (fLong)
1126                     WalletTxToJSON(wtx, entry);
1127                 ret.push_back(entry);
1128             }
1129         }
1130 }
1131
1132 void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret)
1133 {
1134     bool fAllAccounts = (strAccount == string("*"));
1135
1136     if (fAllAccounts || acentry.strAccount == strAccount)
1137     {
1138         Object entry;
1139         entry.push_back(Pair("account", acentry.strAccount));
1140         entry.push_back(Pair("category", "move"));
1141         entry.push_back(Pair("time", (boost::int64_t)acentry.nTime));
1142         entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
1143         entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
1144         entry.push_back(Pair("comment", acentry.strComment));
1145         ret.push_back(entry);
1146     }
1147 }
1148
1149 Value listtransactions(const Array& params, bool fHelp)
1150 {
1151     if (fHelp || params.size() > 3)
1152         throw runtime_error(
1153             "listtransactions [account] [count=10] [from=0]\n"
1154             "Returns up to [count] most recent transactions skipping the first [from] transactions for account [account].");
1155
1156     string strAccount = "*";
1157     if (params.size() > 0)
1158         strAccount = params[0].get_str();
1159     int nCount = 10;
1160     if (params.size() > 1)
1161         nCount = params[1].get_int();
1162     int nFrom = 0;
1163     if (params.size() > 2)
1164         nFrom = params[2].get_int();
1165
1166     Array ret;
1167     CWalletDB walletdb(pwalletMain->strWalletFile);
1168
1169     // Firs: get all CWalletTx and CAccountingEntry into a sorted-by-time multimap:
1170     typedef pair<CWalletTx*, CAccountingEntry*> TxPair;
1171     typedef multimap<int64, TxPair > TxItems;
1172     TxItems txByTime;
1173
1174     for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1175     {
1176         CWalletTx* wtx = &((*it).second);
1177         txByTime.insert(make_pair(wtx->GetTxTime(), TxPair(wtx, (CAccountingEntry*)0)));
1178     }
1179     list<CAccountingEntry> acentries;
1180     walletdb.ListAccountCreditDebit(strAccount, acentries);
1181     BOOST_FOREACH(CAccountingEntry& entry, acentries)
1182     {
1183         txByTime.insert(make_pair(entry.nTime, TxPair((CWalletTx*)0, &entry)));
1184     }
1185
1186     // Now: iterate backwards until we have nCount items to return:
1187     TxItems::reverse_iterator it = txByTime.rbegin();
1188     if (txByTime.size() > nFrom) std::advance(it, nFrom);
1189     for (; it != txByTime.rend(); ++it)
1190     {
1191         CWalletTx *const pwtx = (*it).second.first;
1192         if (pwtx != 0)
1193             ListTransactions(*pwtx, strAccount, 0, true, ret);
1194         CAccountingEntry *const pacentry = (*it).second.second;
1195         if (pacentry != 0)
1196             AcentryToJSON(*pacentry, strAccount, ret);
1197
1198         if (ret.size() >= nCount) break;
1199     }
1200     // ret is now newest to oldest
1201     
1202     // Make sure we return only last nCount items (sends-to-self might give us an extra):
1203     if (ret.size() > nCount)
1204     {
1205         Array::iterator last = ret.begin();
1206         std::advance(last, nCount);
1207         ret.erase(last, ret.end());
1208     }
1209     std::reverse(ret.begin(), ret.end()); // oldest to newest
1210
1211     return ret;
1212 }
1213
1214 Value listaccounts(const Array& params, bool fHelp)
1215 {
1216     if (fHelp || params.size() > 1)
1217         throw runtime_error(
1218             "listaccounts [minconf=1]\n"
1219             "Returns Object that has account names as keys, account balances as values.");
1220
1221     int nMinDepth = 1;
1222     if (params.size() > 0)
1223         nMinDepth = params[0].get_int();
1224
1225     map<string, int64> mapAccountBalances;
1226     BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& entry, pwalletMain->mapAddressBook) {
1227         if (pwalletMain->HaveKey(entry.first)) // This address belongs to me
1228             mapAccountBalances[entry.second] = 0;
1229     }
1230
1231     for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1232     {
1233         const CWalletTx& wtx = (*it).second;
1234         int64 nGeneratedImmature, nGeneratedMature, nFee;
1235         string strSentAccount;
1236         list<pair<CBitcoinAddress, int64> > listReceived;
1237         list<pair<CBitcoinAddress, int64> > listSent;
1238         wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1239         mapAccountBalances[strSentAccount] -= nFee;
1240         BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1241             mapAccountBalances[strSentAccount] -= s.second;
1242         if (wtx.GetDepthInMainChain() >= nMinDepth)
1243         {
1244             mapAccountBalances[""] += nGeneratedMature;
1245             BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1246                 if (pwalletMain->mapAddressBook.count(r.first))
1247                     mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second;
1248                 else
1249                     mapAccountBalances[""] += r.second;
1250         }
1251     }
1252
1253     list<CAccountingEntry> acentries;
1254     CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
1255     BOOST_FOREACH(const CAccountingEntry& entry, acentries)
1256         mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
1257
1258     Object ret;
1259     BOOST_FOREACH(const PAIRTYPE(string, int64)& accountBalance, mapAccountBalances) {
1260         ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
1261     }
1262     return ret;
1263 }
1264
1265 Value listsinceblock(const Array& params, bool fHelp)
1266 {
1267     if (fHelp)
1268         throw runtime_error(
1269             "listsinceblock [blockid] [target-confirmations]\n"
1270             "Get all transactions in blocks since block [blockid], or all transactions if omitted");
1271
1272     CBlockIndex *pindex = NULL;
1273     int target_confirms = 1;
1274
1275     if (params.size() > 0)
1276     {
1277         uint256 blockId = 0;
1278
1279         blockId.SetHex(params[0].get_str());
1280         pindex = CBlockLocator(blockId).GetBlockIndex();
1281     }
1282
1283     if (params.size() > 1)
1284     {
1285         target_confirms = params[1].get_int();
1286
1287         if (target_confirms < 1)
1288             throw JSONRPCError(-8, "Invalid parameter");
1289     }
1290
1291     int depth = pindex ? (1 + nBestHeight - pindex->nHeight) : -1;
1292
1293     Array transactions;
1294
1295     for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++)
1296     {
1297         CWalletTx tx = (*it).second;
1298
1299         if (depth == -1 || tx.GetDepthInMainChain() < depth)
1300             ListTransactions(tx, "*", 0, true, transactions);
1301     }
1302
1303     uint256 lastblock;
1304
1305     if (target_confirms == 1)
1306     {
1307         printf("oops!\n");
1308         lastblock = hashBestChain;
1309     }
1310     else
1311     {
1312         int target_height = pindexBest->nHeight + 1 - target_confirms;
1313
1314         CBlockIndex *block;
1315         for (block = pindexBest;
1316              block && block->nHeight > target_height;
1317              block = block->pprev);
1318
1319         lastblock = block ? block->GetBlockHash() : 0;
1320     }
1321
1322     Object ret;
1323     ret.push_back(Pair("transactions", transactions));
1324     ret.push_back(Pair("lastblock", lastblock.GetHex()));
1325
1326     return ret;
1327 }
1328
1329 Value gettransaction(const Array& params, bool fHelp)
1330 {
1331     if (fHelp || params.size() != 1)
1332         throw runtime_error(
1333             "gettransaction <txid>\n"
1334             "Get detailed information about <txid>");
1335
1336     uint256 hash;
1337     hash.SetHex(params[0].get_str());
1338
1339     Object entry;
1340
1341     if (!pwalletMain->mapWallet.count(hash))
1342         throw JSONRPCError(-5, "Invalid or non-wallet transaction id");
1343     const CWalletTx& wtx = pwalletMain->mapWallet[hash];
1344
1345     int64 nCredit = wtx.GetCredit();
1346     int64 nDebit = wtx.GetDebit();
1347     int64 nNet = nCredit - nDebit;
1348     int64 nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0);
1349
1350     entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
1351     if (wtx.IsFromMe())
1352         entry.push_back(Pair("fee", ValueFromAmount(nFee)));
1353
1354     WalletTxToJSON(pwalletMain->mapWallet[hash], entry);
1355
1356     Array details;
1357     ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details);
1358     entry.push_back(Pair("details", details));
1359
1360     return entry;
1361 }
1362
1363
1364 Value backupwallet(const Array& params, bool fHelp)
1365 {
1366     if (fHelp || params.size() != 1)
1367         throw runtime_error(
1368             "backupwallet <destination>\n"
1369             "Safely copies wallet.dat to destination, which can be a directory or a path with filename.");
1370
1371     string strDest = params[0].get_str();
1372     BackupWallet(*pwalletMain, strDest);
1373
1374     return Value::null;
1375 }
1376
1377
1378 Value keypoolrefill(const Array& params, bool fHelp)
1379 {
1380     if (pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1381         throw runtime_error(
1382             "keypoolrefill\n"
1383             "Fills the keypool, requires wallet passphrase to be set.");
1384     if (!pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1385         throw runtime_error(
1386             "keypoolrefill\n"
1387             "Fills the keypool.");
1388
1389     if (pwalletMain->IsLocked())
1390         throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
1391
1392     pwalletMain->TopUpKeyPool();
1393
1394     if (pwalletMain->GetKeyPoolSize() < GetArg("-keypool", 100))
1395         throw JSONRPCError(-4, "Error refreshing keypool.");
1396
1397     return Value::null;
1398 }
1399
1400
1401 void ThreadTopUpKeyPool(void* parg)
1402 {
1403     pwalletMain->TopUpKeyPool();
1404 }
1405
1406 void ThreadCleanWalletPassphrase(void* parg)
1407 {
1408     int64 nMyWakeTime = GetTime() + *((int*)parg);
1409
1410     if (nWalletUnlockTime == 0)
1411     {
1412         CRITICAL_BLOCK(cs_nWalletUnlockTime)
1413         {
1414             nWalletUnlockTime = nMyWakeTime;
1415         }
1416
1417         while (GetTime() < nWalletUnlockTime)
1418             Sleep(GetTime() - nWalletUnlockTime);
1419
1420         CRITICAL_BLOCK(cs_nWalletUnlockTime)
1421         {
1422             nWalletUnlockTime = 0;
1423         }
1424     }
1425     else
1426     {
1427         CRITICAL_BLOCK(cs_nWalletUnlockTime)
1428         {
1429             if (nWalletUnlockTime < nMyWakeTime)
1430                 nWalletUnlockTime = nMyWakeTime;
1431         }
1432         free(parg);
1433         return;
1434     }
1435
1436     pwalletMain->Lock();
1437
1438     delete (int*)parg;
1439 }
1440
1441 Value walletpassphrase(const Array& params, bool fHelp)
1442 {
1443     if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1444         throw runtime_error(
1445             "walletpassphrase <passphrase> <timeout>\n"
1446             "Stores the wallet decryption key in memory for <timeout> seconds.");
1447     if (fHelp)
1448         return true;
1449     if (!pwalletMain->IsCrypted())
1450         throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
1451
1452     if (!pwalletMain->IsLocked())
1453         throw JSONRPCError(-17, "Error: Wallet is already unlocked.");
1454
1455     // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
1456     string strWalletPass;
1457     strWalletPass.reserve(100);
1458     mlock(&strWalletPass[0], strWalletPass.capacity());
1459     strWalletPass = params[0].get_str();
1460
1461     if (strWalletPass.length() > 0)
1462     {
1463         if (!pwalletMain->Unlock(strWalletPass))
1464         {
1465             fill(strWalletPass.begin(), strWalletPass.end(), '\0');
1466             munlock(&strWalletPass[0], strWalletPass.capacity());
1467             throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1468         }
1469         fill(strWalletPass.begin(), strWalletPass.end(), '\0');
1470         munlock(&strWalletPass[0], strWalletPass.capacity());
1471     }
1472     else
1473         throw runtime_error(
1474             "walletpassphrase <passphrase> <timeout>\n"
1475             "Stores the wallet decryption key in memory for <timeout> seconds.");
1476
1477     CreateThread(ThreadTopUpKeyPool, NULL);
1478     int* pnSleepTime = new int(params[1].get_int());
1479     CreateThread(ThreadCleanWalletPassphrase, pnSleepTime);
1480
1481     return Value::null;
1482 }
1483
1484
1485 Value walletpassphrasechange(const Array& params, bool fHelp)
1486 {
1487     if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1488         throw runtime_error(
1489             "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1490             "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1491     if (fHelp)
1492         return true;
1493     if (!pwalletMain->IsCrypted())
1494         throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
1495
1496     string strOldWalletPass;
1497     strOldWalletPass.reserve(100);
1498     mlock(&strOldWalletPass[0], strOldWalletPass.capacity());
1499     strOldWalletPass = params[0].get_str();
1500
1501     string strNewWalletPass;
1502     strNewWalletPass.reserve(100);
1503     mlock(&strNewWalletPass[0], strNewWalletPass.capacity());
1504     strNewWalletPass = params[1].get_str();
1505
1506     if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
1507         throw runtime_error(
1508             "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1509             "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1510
1511     if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
1512     {
1513         fill(strOldWalletPass.begin(), strOldWalletPass.end(), '\0');
1514         fill(strNewWalletPass.begin(), strNewWalletPass.end(), '\0');
1515         munlock(&strOldWalletPass[0], strOldWalletPass.capacity());
1516         munlock(&strNewWalletPass[0], strNewWalletPass.capacity());
1517         throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1518     }
1519     fill(strNewWalletPass.begin(), strNewWalletPass.end(), '\0');
1520     fill(strOldWalletPass.begin(), strOldWalletPass.end(), '\0');
1521     munlock(&strOldWalletPass[0], strOldWalletPass.capacity());
1522     munlock(&strNewWalletPass[0], strNewWalletPass.capacity());
1523
1524     return Value::null;
1525 }
1526
1527
1528 Value walletlock(const Array& params, bool fHelp)
1529 {
1530     if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
1531         throw runtime_error(
1532             "walletlock\n"
1533             "Removes the wallet encryption key from memory, locking the wallet.\n"
1534             "After calling this method, you will need to call walletpassphrase again\n"
1535             "before being able to call any methods which require the wallet to be unlocked.");
1536     if (fHelp)
1537         return true;
1538     if (!pwalletMain->IsCrypted())
1539         throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletlock was called.");
1540
1541     pwalletMain->Lock();
1542     CRITICAL_BLOCK(cs_nWalletUnlockTime)
1543     {
1544         nWalletUnlockTime = 0;
1545     }
1546
1547     return Value::null;
1548 }
1549
1550
1551 Value encryptwallet(const Array& params, bool fHelp)
1552 {
1553     if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
1554         throw runtime_error(
1555             "encryptwallet <passphrase>\n"
1556             "Encrypts the wallet with <passphrase>.");
1557     if (fHelp)
1558         return true;
1559     if (pwalletMain->IsCrypted())
1560         throw JSONRPCError(-15, "Error: running with an encrypted wallet, but encryptwallet was called.");
1561
1562 #ifdef QT_GUI
1563     // shutting down via RPC while the GUI is running does not work (yet):
1564     throw runtime_error("Not Yet Implemented: use GUI to encrypt wallet, not RPC command");
1565 #endif
1566
1567     string strWalletPass;
1568     strWalletPass.reserve(100);
1569     mlock(&strWalletPass[0], strWalletPass.capacity());
1570     strWalletPass = params[0].get_str();
1571
1572     if (strWalletPass.length() < 1)
1573         throw runtime_error(
1574             "encryptwallet <passphrase>\n"
1575             "Encrypts the wallet with <passphrase>.");
1576
1577     if (!pwalletMain->EncryptWallet(strWalletPass))
1578     {
1579         fill(strWalletPass.begin(), strWalletPass.end(), '\0');
1580         munlock(&strWalletPass[0], strWalletPass.capacity());
1581         throw JSONRPCError(-16, "Error: Failed to encrypt the wallet.");
1582     }
1583     fill(strWalletPass.begin(), strWalletPass.end(), '\0');
1584     munlock(&strWalletPass[0], strWalletPass.capacity());
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->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
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->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
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     string::size_type nColon = strUserPass.find(":");
2047     if (nColon == string::npos)
2048         return false;
2049     string strUser = strUserPass.substr(0, nColon);
2050     string strPassword = strUserPass.substr(nColon+1);
2051     return (strUser == mapArgs["-rpcuser"] && strPassword == mapArgs["-rpcpassword"]);
2052 }
2053
2054 //
2055 // JSON-RPC protocol.  Bitcoin speaks version 1.0 for maximum compatibility,
2056 // but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
2057 // unspecified (HTTP errors and contents of 'error').
2058 //
2059 // 1.0 spec: http://json-rpc.org/wiki/specification
2060 // 1.2 spec: http://groups.google.com/group/json-rpc/web/json-rpc-over-http
2061 // http://www.codeproject.com/KB/recipes/JSON_Spirit.aspx
2062 //
2063
2064 string JSONRPCRequest(const string& strMethod, const Array& params, const Value& id)
2065 {
2066     Object request;
2067     request.push_back(Pair("method", strMethod));
2068     request.push_back(Pair("params", params));
2069     request.push_back(Pair("id", id));
2070     return write_string(Value(request), false) + "\n";
2071 }
2072
2073 string JSONRPCReply(const Value& result, const Value& error, const Value& id)
2074 {
2075     Object reply;
2076     if (error.type() != null_type)
2077         reply.push_back(Pair("result", Value::null));
2078     else
2079         reply.push_back(Pair("result", result));
2080     reply.push_back(Pair("error", error));
2081     reply.push_back(Pair("id", id));
2082     return write_string(Value(reply), false) + "\n";
2083 }
2084
2085 void ErrorReply(std::ostream& stream, const Object& objError, const Value& id)
2086 {
2087     // Send error reply from json-rpc error object
2088     int nStatus = 500;
2089     int code = find_value(objError, "code").get_int();
2090     if (code == -32600) nStatus = 400;
2091     else if (code == -32601) nStatus = 404;
2092     string strReply = JSONRPCReply(Value::null, objError, id);
2093     stream << HTTPReply(nStatus, strReply) << std::flush;
2094 }
2095
2096 bool ClientAllowed(const string& strAddress)
2097 {
2098     if (strAddress == asio::ip::address_v4::loopback().to_string())
2099         return true;
2100     const vector<string>& vAllow = mapMultiArgs["-rpcallowip"];
2101     BOOST_FOREACH(string strAllow, vAllow)
2102         if (WildcardMatch(strAddress, strAllow))
2103             return true;
2104     return false;
2105 }
2106
2107 #ifdef USE_SSL
2108 //
2109 // IOStream device that speaks SSL but can also speak non-SSL
2110 //
2111 class SSLIOStreamDevice : public iostreams::device<iostreams::bidirectional> {
2112 public:
2113     SSLIOStreamDevice(SSLStream &streamIn, bool fUseSSLIn) : stream(streamIn)
2114     {
2115         fUseSSL = fUseSSLIn;
2116         fNeedHandshake = fUseSSLIn;
2117     }
2118
2119     void handshake(ssl::stream_base::handshake_type role)
2120     {
2121         if (!fNeedHandshake) return;
2122         fNeedHandshake = false;
2123         stream.handshake(role);
2124     }
2125     std::streamsize read(char* s, std::streamsize n)
2126     {
2127         handshake(ssl::stream_base::server); // HTTPS servers read first
2128         if (fUseSSL) return stream.read_some(asio::buffer(s, n));
2129         return stream.next_layer().read_some(asio::buffer(s, n));
2130     }
2131     std::streamsize write(const char* s, std::streamsize n)
2132     {
2133         handshake(ssl::stream_base::client); // HTTPS clients write first
2134         if (fUseSSL) return asio::write(stream, asio::buffer(s, n));
2135         return asio::write(stream.next_layer(), asio::buffer(s, n));
2136     }
2137     bool connect(const std::string& server, const std::string& port)
2138     {
2139         ip::tcp::resolver resolver(stream.get_io_service());
2140         ip::tcp::resolver::query query(server.c_str(), port.c_str());
2141         ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
2142         ip::tcp::resolver::iterator end;
2143         boost::system::error_code error = asio::error::host_not_found;
2144         while (error && endpoint_iterator != end)
2145         {
2146             stream.lowest_layer().close();
2147             stream.lowest_layer().connect(*endpoint_iterator++, error);
2148         }
2149         if (error)
2150             return false;
2151         return true;
2152     }
2153
2154 private:
2155     bool fNeedHandshake;
2156     bool fUseSSL;
2157     SSLStream& stream;
2158 };
2159 #endif
2160
2161 void ThreadRPCServer(void* parg)
2162 {
2163     IMPLEMENT_RANDOMIZE_STACK(ThreadRPCServer(parg));
2164     try
2165     {
2166         vnThreadsRunning[4]++;
2167         ThreadRPCServer2(parg);
2168         vnThreadsRunning[4]--;
2169     }
2170     catch (std::exception& e) {
2171         vnThreadsRunning[4]--;
2172         PrintException(&e, "ThreadRPCServer()");
2173     } catch (...) {
2174         vnThreadsRunning[4]--;
2175         PrintException(NULL, "ThreadRPCServer()");
2176     }
2177     printf("ThreadRPCServer exiting\n");
2178 }
2179
2180 void ThreadRPCServer2(void* parg)
2181 {
2182     printf("ThreadRPCServer started\n");
2183
2184     if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
2185     {
2186         string strWhatAmI = "To use bitcoind";
2187         if (mapArgs.count("-server"))
2188             strWhatAmI = strprintf(_("To use the %s option"), "\"-server\"");
2189         else if (mapArgs.count("-daemon"))
2190             strWhatAmI = strprintf(_("To use the %s option"), "\"-daemon\"");
2191         PrintConsole(
2192             _("Error: %s, you must set rpcpassword=<password>\nin the configuration file: %s\n"
2193               "If the file does not exist, create it with owner-readable-only file permissions.\n"),
2194                 strWhatAmI.c_str(),
2195                 GetConfigFile().c_str());
2196 #ifndef QT_GUI
2197         CreateThread(Shutdown, NULL);
2198 #endif
2199         return;
2200     }
2201
2202     bool fUseSSL = GetBoolArg("-rpcssl");
2203     asio::ip::address bindAddress = mapArgs.count("-rpcallowip") ? asio::ip::address_v4::any() : asio::ip::address_v4::loopback();
2204
2205     asio::io_service io_service;
2206     ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", 8332));
2207     ip::tcp::acceptor acceptor(io_service, endpoint);
2208
2209     acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
2210
2211 #ifdef USE_SSL
2212     ssl::context context(io_service, ssl::context::sslv23);
2213     if (fUseSSL)
2214     {
2215         context.set_options(ssl::context::no_sslv2);
2216         filesystem::path certfile = GetArg("-rpcsslcertificatechainfile", "server.cert");
2217         if (!certfile.is_complete()) certfile = filesystem::path(GetDataDir()) / certfile;
2218         if (filesystem::exists(certfile)) context.use_certificate_chain_file(certfile.string().c_str());
2219         else printf("ThreadRPCServer ERROR: missing server certificate file %s\n", certfile.string().c_str());
2220         filesystem::path pkfile = GetArg("-rpcsslprivatekeyfile", "server.pem");
2221         if (!pkfile.is_complete()) pkfile = filesystem::path(GetDataDir()) / pkfile;
2222         if (filesystem::exists(pkfile)) context.use_private_key_file(pkfile.string().c_str(), ssl::context::pem);
2223         else printf("ThreadRPCServer ERROR: missing server private key file %s\n", pkfile.string().c_str());
2224
2225         string ciphers = GetArg("-rpcsslciphers",
2226                                          "TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH");
2227         SSL_CTX_set_cipher_list(context.impl(), ciphers.c_str());
2228     }
2229 #else
2230     if (fUseSSL)
2231         throw runtime_error("-rpcssl=1, but bitcoin compiled without full openssl libraries.");
2232 #endif
2233
2234     loop
2235     {
2236         // Accept connection
2237 #ifdef USE_SSL
2238         SSLStream sslStream(io_service, context);
2239         SSLIOStreamDevice d(sslStream, fUseSSL);
2240         iostreams::stream<SSLIOStreamDevice> stream(d);
2241 #else
2242         ip::tcp::iostream stream;
2243 #endif
2244
2245         ip::tcp::endpoint peer;
2246         vnThreadsRunning[4]--;
2247 #ifdef USE_SSL
2248         acceptor.accept(sslStream.lowest_layer(), peer);
2249 #else
2250         acceptor.accept(*stream.rdbuf(), peer);
2251 #endif
2252         vnThreadsRunning[4]++;
2253         if (fShutdown)
2254             return;
2255
2256         // Restrict callers by IP
2257         if (!ClientAllowed(peer.address().to_string()))
2258         {
2259             // Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake.
2260             if (!fUseSSL)
2261                 stream << HTTPReply(403, "") << std::flush;
2262             continue;
2263         }
2264
2265         map<string, string> mapHeaders;
2266         string strRequest;
2267
2268         boost::thread api_caller(ReadHTTP, boost::ref(stream), boost::ref(mapHeaders), boost::ref(strRequest));
2269         if (!api_caller.timed_join(boost::posix_time::seconds(GetArg("-rpctimeout", 30))))
2270         {   // Timed out:
2271             acceptor.cancel();
2272             printf("ThreadRPCServer ReadHTTP timeout\n");
2273             continue;
2274         }
2275
2276         // Check authorization
2277         if (mapHeaders.count("authorization") == 0)
2278         {
2279             stream << HTTPReply(401, "") << std::flush;
2280             continue;
2281         }
2282         if (!HTTPAuthorized(mapHeaders))
2283         {
2284             // Deter brute-forcing short passwords
2285             if (mapArgs["-rpcpassword"].size() < 15)
2286                 Sleep(50);
2287
2288             stream << HTTPReply(401, "") << std::flush;
2289             printf("ThreadRPCServer incorrect password attempt\n");
2290             continue;
2291         }
2292
2293         Value id = Value::null;
2294         try
2295         {
2296             // Parse request
2297             Value valRequest;
2298             if (!read_string(strRequest, valRequest) || valRequest.type() != obj_type)
2299                 throw JSONRPCError(-32700, "Parse error");
2300             const Object& request = valRequest.get_obj();
2301
2302             // Parse id now so errors from here on will have the id
2303             id = find_value(request, "id");
2304
2305             // Parse method
2306             Value valMethod = find_value(request, "method");
2307             if (valMethod.type() == null_type)
2308                 throw JSONRPCError(-32600, "Missing method");
2309             if (valMethod.type() != str_type)
2310                 throw JSONRPCError(-32600, "Method must be a string");
2311             string strMethod = valMethod.get_str();
2312             if (strMethod != "getwork" && strMethod != "getmemorypool")
2313                 printf("ThreadRPCServer method=%s\n", strMethod.c_str());
2314
2315             // Parse params
2316             Value valParams = find_value(request, "params");
2317             Array params;
2318             if (valParams.type() == array_type)
2319                 params = valParams.get_array();
2320             else if (valParams.type() == null_type)
2321                 params = Array();
2322             else
2323                 throw JSONRPCError(-32600, "Params must be an array");
2324
2325             // Find method
2326             map<string, rpcfn_type>::iterator mi = mapCallTable.find(strMethod);
2327             if (mi == mapCallTable.end())
2328                 throw JSONRPCError(-32601, "Method not found");
2329
2330             // Observe safe mode
2331             string strWarning = GetWarnings("rpc");
2332             if (strWarning != "" && !GetBoolArg("-disablesafemode") && !setAllowInSafeMode.count(strMethod))
2333                 throw JSONRPCError(-2, string("Safe mode: ") + strWarning);
2334
2335             try
2336             {
2337                 // Execute
2338                 Value result;
2339                 CRITICAL_BLOCK(cs_main)
2340                 CRITICAL_BLOCK(pwalletMain->cs_wallet)
2341                     result = (*(*mi).second)(params, false);
2342
2343                 // Send reply
2344                 string strReply = JSONRPCReply(result, Value::null, id);
2345                 stream << HTTPReply(200, strReply) << std::flush;
2346             }
2347             catch (std::exception& e)
2348             {
2349                 ErrorReply(stream, JSONRPCError(-1, e.what()), id);
2350             }
2351         }
2352         catch (Object& objError)
2353         {
2354             ErrorReply(stream, objError, id);
2355         }
2356         catch (std::exception& e)
2357         {
2358             ErrorReply(stream, JSONRPCError(-32700, e.what()), id);
2359         }
2360     }
2361 }
2362
2363
2364
2365
2366 Object CallRPC(const string& strMethod, const Array& params)
2367 {
2368     if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
2369         throw runtime_error(strprintf(
2370             _("You must set rpcpassword=<password> in the configuration file:\n%s\n"
2371               "If the file does not exist, create it with owner-readable-only file permissions."),
2372                 GetConfigFile().c_str()));
2373
2374     // Connect to localhost
2375     bool fUseSSL = GetBoolArg("-rpcssl");
2376 #ifdef USE_SSL
2377     asio::io_service io_service;
2378     ssl::context context(io_service, ssl::context::sslv23);
2379     context.set_options(ssl::context::no_sslv2);
2380     SSLStream sslStream(io_service, context);
2381     SSLIOStreamDevice d(sslStream, fUseSSL);
2382     iostreams::stream<SSLIOStreamDevice> stream(d);
2383     if (!d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332")))
2384         throw runtime_error("couldn't connect to server");
2385 #else
2386     if (fUseSSL)
2387         throw runtime_error("-rpcssl=1, but bitcoin compiled without full openssl libraries.");
2388
2389     ip::tcp::iostream stream(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332"));
2390     if (stream.fail())
2391         throw runtime_error("couldn't connect to server");
2392 #endif
2393
2394
2395     // HTTP basic authentication
2396     string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
2397     map<string, string> mapRequestHeaders;
2398     mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64;
2399
2400     // Send request
2401     string strRequest = JSONRPCRequest(strMethod, params, 1);
2402     string strPost = HTTPPost(strRequest, mapRequestHeaders);
2403     stream << strPost << std::flush;
2404
2405     // Receive reply
2406     map<string, string> mapHeaders;
2407     string strReply;
2408     int nStatus = ReadHTTP(stream, mapHeaders, strReply);
2409     if (nStatus == 401)
2410         throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
2411     else if (nStatus >= 400 && nStatus != 400 && nStatus != 404 && nStatus != 500)
2412         throw runtime_error(strprintf("server returned HTTP error %d", nStatus));
2413     else if (strReply.empty())
2414         throw runtime_error("no response from server");
2415
2416     // Parse reply
2417     Value valReply;
2418     if (!read_string(strReply, valReply))
2419         throw runtime_error("couldn't parse reply from server");
2420     const Object& reply = valReply.get_obj();
2421     if (reply.empty())
2422         throw runtime_error("expected reply to have result, error and id properties");
2423
2424     return reply;
2425 }
2426
2427
2428
2429
2430 template<typename T>
2431 void ConvertTo(Value& value)
2432 {
2433     if (value.type() == str_type)
2434     {
2435         // reinterpret string as unquoted json value
2436         Value value2;
2437         if (!read_string(value.get_str(), value2))
2438             throw runtime_error("type mismatch");
2439         value = value2.get_value<T>();
2440     }
2441     else
2442     {
2443         value = value.get_value<T>();
2444     }
2445 }
2446
2447 int CommandLineRPC(int argc, char *argv[])
2448 {
2449     string strPrint;
2450     int nRet = 0;
2451     try
2452     {
2453         // Skip switches
2454         while (argc > 1 && IsSwitchChar(argv[1][0]))
2455         {
2456             argc--;
2457             argv++;
2458         }
2459
2460         // Method
2461         if (argc < 2)
2462             throw runtime_error("too few parameters");
2463         string strMethod = argv[1];
2464
2465         // Parameters default to strings
2466         Array params;
2467         for (int i = 2; i < argc; i++)
2468             params.push_back(argv[i]);
2469         int n = params.size();
2470
2471         //
2472         // Special case non-string parameter types
2473         //
2474         if (strMethod == "setgenerate"            && n > 0) ConvertTo<bool>(params[0]);
2475         if (strMethod == "setgenerate"            && n > 1) ConvertTo<boost::int64_t>(params[1]);
2476         if (strMethod == "sendtoaddress"          && n > 1) ConvertTo<double>(params[1]);
2477         if (strMethod == "settxfee"               && n > 0) ConvertTo<double>(params[0]);
2478         if (strMethod == "getreceivedbyaddress"   && n > 1) ConvertTo<boost::int64_t>(params[1]);
2479         if (strMethod == "getreceivedbyaccount"   && n > 1) ConvertTo<boost::int64_t>(params[1]);
2480         if (strMethod == "listreceivedbyaddress"  && n > 0) ConvertTo<boost::int64_t>(params[0]);
2481         if (strMethod == "listreceivedbyaddress"  && n > 1) ConvertTo<bool>(params[1]);
2482         if (strMethod == "listreceivedbyaccount"  && n > 0) ConvertTo<boost::int64_t>(params[0]);
2483         if (strMethod == "listreceivedbyaccount"  && n > 1) ConvertTo<bool>(params[1]);
2484         if (strMethod == "getbalance"             && n > 1) ConvertTo<boost::int64_t>(params[1]);
2485         if (strMethod == "move"                   && n > 2) ConvertTo<double>(params[2]);
2486         if (strMethod == "move"                   && n > 3) ConvertTo<boost::int64_t>(params[3]);
2487         if (strMethod == "sendfrom"               && n > 2) ConvertTo<double>(params[2]);
2488         if (strMethod == "sendfrom"               && n > 3) ConvertTo<boost::int64_t>(params[3]);
2489         if (strMethod == "listtransactions"       && n > 1) ConvertTo<boost::int64_t>(params[1]);
2490         if (strMethod == "listtransactions"       && n > 2) ConvertTo<boost::int64_t>(params[2]);
2491         if (strMethod == "listaccounts"           && n > 0) ConvertTo<boost::int64_t>(params[0]);
2492         if (strMethod == "walletpassphrase"       && n > 1) ConvertTo<boost::int64_t>(params[1]);
2493         if (strMethod == "listsinceblock"         && n > 1) ConvertTo<boost::int64_t>(params[1]);
2494         if (strMethod == "sendmany"               && n > 1)
2495         {
2496             string s = params[1].get_str();
2497             Value v;
2498             if (!read_string(s, v) || v.type() != obj_type)
2499                 throw runtime_error("type mismatch");
2500             params[1] = v.get_obj();
2501         }
2502         if (strMethod == "sendmany"                && n > 2) ConvertTo<boost::int64_t>(params[2]);
2503
2504         // Execute
2505         Object reply = CallRPC(strMethod, params);
2506
2507         // Parse reply
2508         const Value& result = find_value(reply, "result");
2509         const Value& error  = find_value(reply, "error");
2510
2511         if (error.type() != null_type)
2512         {
2513             // Error
2514             strPrint = "error: " + write_string(error, false);
2515             int code = find_value(error.get_obj(), "code").get_int();
2516             nRet = abs(code);
2517         }
2518         else
2519         {
2520             // Result
2521             if (result.type() == null_type)
2522                 strPrint = "";
2523             else if (result.type() == str_type)
2524                 strPrint = result.get_str();
2525             else
2526                 strPrint = write_string(result, true);
2527         }
2528     }
2529     catch (std::exception& e)
2530     {
2531         strPrint = string("error: ") + e.what();
2532         nRet = 87;
2533     }
2534     catch (...)
2535     {
2536         PrintException(NULL, "CommandLineRPC()");
2537     }
2538
2539     if (strPrint != "")
2540     {
2541         fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
2542     }
2543     return nRet;
2544 }
2545
2546
2547
2548
2549 #ifdef TEST
2550 int main(int argc, char *argv[])
2551 {
2552 #ifdef _MSC_VER
2553     // Turn off microsoft heap dump noise
2554     _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
2555     _CrtSetReportFile(_CRT_WARN, CreateFile("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0));
2556 #endif
2557     setbuf(stdin, NULL);
2558     setbuf(stdout, NULL);
2559     setbuf(stderr, NULL);
2560
2561     try
2562     {
2563         if (argc >= 2 && string(argv[1]) == "-server")
2564         {
2565             printf("server ready\n");
2566             ThreadRPCServer(NULL);
2567         }
2568         else
2569         {
2570             return CommandLineRPC(argc, argv);
2571         }
2572     }
2573     catch (std::exception& e) {
2574         PrintException(&e, "main()");
2575     } catch (...) {
2576         PrintException(NULL, "main()");
2577     }
2578     return 0;
2579 }
2580 #endif