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