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