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