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