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