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