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