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