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