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