PPCoin: RPC 'makekeypair' limits loop to avoid hang
[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",       FormatFullVersion()));
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, true);
1661             if (!pblock)
1662                 throw JSONRPCError(-7, "Out of memory");
1663             vNewBlock.push_back(pblock);
1664         }
1665
1666         // Update nTime
1667         pblock->nTime = max(pblock->GetBlockTime(), 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         if (!pblock->SignBlock(*pwalletMain))
1714             throw JSONRPCError(-100, "Unable to sign block");
1715
1716         return CheckWork(pblock, *pwalletMain, reservekey);
1717     }
1718 }
1719
1720
1721 Value getmemorypool(const Array& params, bool fHelp)
1722 {
1723     if (fHelp || params.size() > 1)
1724         throw runtime_error(
1725             "getmemorypool [data]\n"
1726             "If [data] is not specified, returns data needed to construct a block to work on:\n"
1727             "  \"version\" : block version\n"
1728             "  \"previousblockhash\" : hash of current highest block\n"
1729             "  \"transactions\" : contents of non-coinbase transactions that should be included in the next block\n"
1730             "  \"coinbasevalue\" : maximum allowable input to coinbase transaction, including the generation award and transaction fees\n"
1731             "  \"time\" : timestamp appropriate for next block\n"
1732             "  \"bits\" : compressed target of next block\n"
1733             "If [data] is specified, tries to solve the block and returns true if it was successful.");
1734
1735     if (params.size() == 0)
1736     {
1737         if (vNodes.empty())
1738             throw JSONRPCError(-9, "PPCoin is not connected!");
1739
1740         if (IsInitialBlockDownload())
1741             throw JSONRPCError(-10, "PPCoin is downloading blocks...");
1742
1743         static CReserveKey reservekey(pwalletMain);
1744
1745         // Update block
1746         static unsigned int nTransactionsUpdatedLast;
1747         static CBlockIndex* pindexPrev;
1748         static int64 nStart;
1749         static CBlock* pblock;
1750         if (pindexPrev != pindexBest ||
1751             (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 5))
1752         {
1753             nTransactionsUpdatedLast = nTransactionsUpdated;
1754             pindexPrev = pindexBest;
1755             nStart = GetTime();
1756
1757             // Create new block
1758             if(pblock)
1759                 delete pblock;
1760             pblock = CreateNewBlock(pwalletMain);
1761             if (!pblock)
1762                 throw JSONRPCError(-7, "Out of memory");
1763         }
1764
1765         // Update nTime
1766         pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
1767         pblock->nNonce = 0;
1768
1769         Array transactions;
1770         BOOST_FOREACH(CTransaction tx, pblock->vtx) {
1771             if(tx.IsCoinBase() || tx.IsCoinStake())
1772                 continue;
1773
1774             CDataStream ssTx;
1775             ssTx << tx;
1776
1777             transactions.push_back(HexStr(ssTx.begin(), ssTx.end()));
1778         }
1779
1780         Object result;
1781         result.push_back(Pair("version", pblock->nVersion));
1782         result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex()));
1783         result.push_back(Pair("transactions", transactions));
1784         result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue));
1785         result.push_back(Pair("time", (int64_t)pblock->nTime));
1786
1787         union {
1788             int32_t nBits;
1789             char cBits[4];
1790         } uBits;
1791         uBits.nBits = htonl((int32_t)pblock->nBits);
1792         result.push_back(Pair("bits", HexStr(BEGIN(uBits.cBits), END(uBits.cBits))));
1793
1794         return result;
1795     }
1796     else
1797     {
1798         // Parse parameters
1799         CDataStream ssBlock(ParseHex(params[0].get_str()));
1800         CBlock pblock;
1801         ssBlock >> pblock;
1802
1803         return ProcessBlock(NULL, &pblock);
1804     }
1805 }
1806
1807
1808 // ppcoin: get information of sync-checkpoint
1809 Value getcheckpoint(const Array& params, bool fHelp)
1810 {
1811     if (fHelp || params.size() != 0)
1812         throw runtime_error(
1813             "getcheckpoint\n"
1814             "Show info of synchronized checkpoint.\n");
1815
1816     Object result;
1817     CBlockIndex* pindexCheckpoint;
1818     
1819     result.push_back(Pair("synccheckpoint", Checkpoints::hashSyncCheckpoint.ToString().c_str()));
1820     pindexCheckpoint = mapBlockIndex[Checkpoints::hashSyncCheckpoint];        
1821     result.push_back(Pair("height", pindexCheckpoint->nHeight));
1822     result.push_back(Pair("timestamp", DateTimeStrFormat("%x %H:%M:%S", pindexCheckpoint->GetBlockTime()).c_str()));
1823     
1824     return result;
1825 }
1826
1827
1828 // ppcoin: reserve balance from being staked for network protection
1829 Value reservebalance(const Array& params, bool fHelp)
1830 {
1831     if (fHelp || params.size() > 2)
1832         throw runtime_error(
1833             "reservebalance [<reserve> [amount]]\n"
1834             "<reserve> is true or false to turn balance reserve on or off.\n"
1835             "<amount> is a real and rounded to cent.\n"
1836             "Set reserve amount not participating in network protection.\n"
1837             "If no parameters provided current setting is printed.\n");
1838
1839     if (params.size() > 0)
1840     {
1841         bool fReserve = params[0].get_bool();
1842         if (fReserve)
1843         {
1844             if (params.size() == 1)
1845                 throw runtime_error("must provide amount to reserve balance.\n");
1846             int64 nAmount = AmountFromValue(params[1]);
1847             nAmount = (nAmount / CENT) * CENT;  // round to cent
1848             if (nAmount < 0)
1849                 throw runtime_error("amount cannot be negative.\n");
1850             WriteSetting("nBalanceReserve", nBalanceReserve = nAmount);
1851         }
1852         else
1853         {
1854             if (params.size() > 1)
1855                 throw runtime_error("cannot specify amount to turn off reserve.\n");
1856             WriteSetting("nBalanceReserve", nBalanceReserve = 0);
1857         }
1858     }
1859
1860     Object result;
1861     result.push_back(Pair("reserve", (nBalanceReserve > 0)));
1862     result.push_back(Pair("amount", ValueFromAmount(nBalanceReserve)));
1863     return result;
1864 }
1865
1866
1867 // ppcoin: check wallet integrity
1868 Value checkwallet(const Array& params, bool fHelp)
1869 {
1870     if (fHelp || params.size() > 0)
1871         throw runtime_error(
1872             "checkwallet\n"
1873             "Check wallet for integrity.\n");
1874
1875     int nMismatchSpent;
1876     int64 nBalanceInQuestion;
1877     if (!pwalletMain->CheckSpentCoins(nMismatchSpent, nBalanceInQuestion))
1878     {
1879         Object result;
1880         result.push_back(Pair("mismatched spent coins", nMismatchSpent));
1881         result.push_back(Pair("amount in question", ValueFromAmount(nBalanceInQuestion)));
1882         return result;
1883     }
1884     return Value::null;
1885 }
1886
1887
1888 // ppcoin: repair wallet
1889 Value repairwallet(const Array& params, bool fHelp)
1890 {
1891     if (fHelp || params.size() > 0)
1892         throw runtime_error(
1893             "repairwallet\n"
1894             "Repair wallet if checkwallet reports any problem.\n");
1895
1896     int nMismatchSpent;
1897     int64 nBalanceInQuestion;
1898     pwalletMain->FixSpentCoins(nMismatchSpent, nBalanceInQuestion);
1899     Object result;
1900     if (nMismatchSpent == 0)
1901     {
1902         result.push_back(Pair("wallet check passed", true));
1903     }
1904     else
1905     {
1906         result.push_back(Pair("mismatched spent coins", nMismatchSpent));
1907         result.push_back(Pair("amount affected by repair", ValueFromAmount(nBalanceInQuestion)));
1908     }
1909     return result;
1910 }
1911
1912 // ppcoin: make a public-private key pair
1913 Value makekeypair(const Array& params, bool fHelp)
1914 {
1915     if (fHelp || params.size() > 1)
1916         throw runtime_error(
1917             "makekeypair [prefix]\n"
1918             "Make a public/private key pair.\n"
1919             "[prefix] is optional preferred prefix for the public key.\n");
1920
1921     string strPrefix = "";
1922     if (params.size() > 0)
1923         strPrefix = params[0].get_str();
1924  
1925     CKey key;
1926     int nCount = 0;
1927     do
1928     {
1929         key.MakeNewKey();
1930         nCount++;
1931     } while (nCount < 10000 && strPrefix != HexStr(key.GetPubKey()).substr(0, strPrefix.size()));
1932
1933     if (strPrefix != HexStr(key.GetPubKey()).substr(0, strPrefix.size()))
1934         return Value::null;
1935
1936     CPrivKey vchPrivKey = key.GetPrivKey();
1937     Object result;
1938     result.push_back(Pair("PrivateKey", HexStr<CPrivKey::iterator>(vchPrivKey.begin(), vchPrivKey.end())));
1939     result.push_back(Pair("PublicKey", HexStr(key.GetPubKey())));
1940     return result;
1941 }
1942
1943 extern CCriticalSection cs_mapAlerts;
1944 extern map<uint256, CAlert> mapAlerts;
1945
1946 // ppcoin: send alert.  
1947 // There is a known deadlock situation with ThreadMessageHandler
1948 // ThreadMessageHandler: holds cs_vSend and acquiring cs_main in SendMessages()
1949 // ThreadRPCServer: holds cs_main and acquiring cs_vSend in alert.RelayTo()/PushMessage()/BeginMessage()
1950 Value sendalert(const Array& params, bool fHelp)
1951 {
1952     if (fHelp || params.size() < 5)
1953         throw runtime_error(
1954             "sendalert <message> <privatekey> <minver> <maxver> <id> [cancelupto]\n"
1955             "<message> is the alert text message\n"
1956             "<privatekey> is hex string of alert master private key\n"
1957             "<minver> is the minimum applicable client version\n"
1958             "<maxver> is the maximum applicable client version\n"
1959             "<id> is the alert id\n"
1960             "[cancelupto] cancels all alert id's up to this number\n"
1961             "Returns true or false.");    
1962
1963     CAlert alert;
1964     CKey key;
1965
1966     alert.strStatusBar = params[0].get_str();
1967     alert.nMinVer = params[2].get_int();
1968     alert.nMaxVer = params[3].get_int();
1969     alert.nID = params[4].get_int();
1970     if (params.size() > 5)
1971         alert.nCancel = params[5].get_int();
1972     alert.nVersion = VERSION;
1973     alert.nRelayUntil = GetAdjustedTime() + 365*24*60*60;
1974     alert.nExpiration = GetAdjustedTime() + 365*24*60*60;
1975     alert.nPriority = 1;
1976
1977     CDataStream sMsg;
1978     sMsg << (CUnsignedAlert)alert;
1979     alert.vchMsg = vector<unsigned char>(sMsg.begin(), sMsg.end());
1980     
1981     vector<unsigned char> vchPrivKey = ParseHex(params[1].get_str());
1982     key.SetPrivKey(CPrivKey(vchPrivKey.begin(), vchPrivKey.end())); // if key is not correct openssl may crash
1983     if (!key.Sign(Hash(alert.vchMsg.begin(), alert.vchMsg.end()), alert.vchSig))
1984         throw runtime_error(
1985             "Unable to sign alert, check private key?\n");  
1986     if(!alert.ProcessAlert()) 
1987         throw runtime_error(
1988             "Failed to process alert.\n");
1989     // Relay alert
1990     CRITICAL_BLOCK(cs_vNodes)
1991         BOOST_FOREACH(CNode* pnode, vNodes)
1992             alert.RelayTo(pnode);
1993
1994     Object result;
1995     result.push_back(Pair("strStatusBar", alert.strStatusBar));
1996     result.push_back(Pair("nVersion", alert.nVersion));
1997     result.push_back(Pair("nMinVer", alert.nMinVer));
1998     result.push_back(Pair("nMaxVer", alert.nMaxVer));
1999     result.push_back(Pair("nID", alert.nID));
2000     if (alert.nCancel > 0)
2001         result.push_back(Pair("nCancel", alert.nCancel));
2002     return result;
2003 }
2004
2005 // ppcoin: send checkpoint
2006 Value sendcheckpoint(const Array& params, bool fHelp)
2007 {
2008     if (fHelp || params.size() > 2 || params.size() < 1 )
2009         throw runtime_error(
2010             "sendcheckpoint <privatekey> [checkpointhash]\n"
2011             "<privatekey> is hex string of checkpoint master private key\n"
2012             "<checkpointhash> is the hash of checkpoint block\n");
2013
2014     CSyncCheckpoint checkpoint;
2015     CKey key;
2016
2017     // TODO: omit checkpointhash parameter
2018     if (params.size() > 1)
2019     {
2020         checkpoint.hashCheckpoint = uint256(params[1].get_str());
2021         if (!mapBlockIndex.count(checkpoint.hashCheckpoint))
2022             throw runtime_error(
2023                 "Provided checkpoint block is not on main chain\n");
2024     }
2025     else
2026     {
2027         checkpoint.hashCheckpoint = Checkpoints::AutoSelectSyncCheckpoint();
2028         if (checkpoint.hashCheckpoint == Checkpoints::hashSyncCheckpoint)
2029             throw runtime_error(
2030                 "Unable to select a more recent sync-checkpoint");
2031     }
2032
2033     CDataStream sMsg;
2034     sMsg << (CUnsignedSyncCheckpoint)checkpoint;
2035     checkpoint.vchMsg = vector<unsigned char>(sMsg.begin(), sMsg.end());
2036
2037     vector<unsigned char> vchPrivKey = ParseHex(params[0].get_str());
2038     key.SetPrivKey(CPrivKey(vchPrivKey.begin(), vchPrivKey.end())); // if key is not correct openssl may crash
2039     if (!key.Sign(Hash(checkpoint.vchMsg.begin(), checkpoint.vchMsg.end()), checkpoint.vchSig))
2040         throw runtime_error(
2041             "Unable to sign checkpoint, check private key?\n");
2042
2043     if(!checkpoint.ProcessSyncCheckpoint(NULL))
2044         throw runtime_error(
2045             "Failed to process checkpoint.\n");
2046     // Relay checkpoint
2047     CRITICAL_BLOCK(cs_vNodes)
2048         BOOST_FOREACH(CNode* pnode, vNodes)
2049             checkpoint.RelayTo(pnode);
2050
2051     Object result;
2052     result.push_back(Pair("checkpoint", Checkpoints::hashSyncCheckpoint.ToString().c_str()));
2053     result.push_back(Pair("height", mapBlockIndex[Checkpoints::hashSyncCheckpoint]->nHeight));
2054     result.push_back(Pair("timestamp", DateTimeStrFormat("%x %H:%M:%S", mapBlockIndex[Checkpoints::hashSyncCheckpoint]->GetBlockTime()).c_str()));
2055     return result;
2056 }
2057
2058
2059 //
2060 // Call Table
2061 //
2062
2063 pair<string, rpcfn_type> pCallTable[] =
2064 {
2065     make_pair("help",                   &help),
2066     make_pair("stop",                   &stop),
2067     make_pair("getblockcount",          &getblockcount),
2068     make_pair("getblocknumber",         &getblocknumber),
2069     make_pair("getconnectioncount",     &getconnectioncount),
2070     make_pair("getdifficulty",          &getdifficulty),
2071     make_pair("getgenerate",            &getgenerate),
2072     make_pair("setgenerate",            &setgenerate),
2073     make_pair("gethashespersec",        &gethashespersec),
2074     make_pair("getinfo",                &getinfo),
2075     make_pair("getnewaddress",          &getnewaddress),
2076     make_pair("getaccountaddress",      &getaccountaddress),
2077     make_pair("setaccount",             &setaccount),
2078     make_pair("getaccount",             &getaccount),
2079     make_pair("getaddressesbyaccount",  &getaddressesbyaccount),
2080     make_pair("sendtoaddress",          &sendtoaddress),
2081     make_pair("getreceivedbyaddress",   &getreceivedbyaddress),
2082     make_pair("getreceivedbyaccount",   &getreceivedbyaccount),
2083     make_pair("listreceivedbyaddress",  &listreceivedbyaddress),
2084     make_pair("listreceivedbyaccount",  &listreceivedbyaccount),
2085     make_pair("backupwallet",           &backupwallet),
2086     make_pair("keypoolrefill",          &keypoolrefill),
2087     make_pair("walletpassphrase",       &walletpassphrase),
2088     make_pair("walletpassphrasechange", &walletpassphrasechange),
2089     make_pair("walletlock",             &walletlock),
2090     make_pair("encryptwallet",          &encryptwallet),
2091     make_pair("validateaddress",        &validateaddress),
2092     make_pair("getbalance",             &getbalance),
2093     make_pair("move",                   &movecmd),
2094     make_pair("sendfrom",               &sendfrom),
2095     make_pair("sendmany",               &sendmany),
2096     make_pair("gettransaction",         &gettransaction),
2097     make_pair("listtransactions",       &listtransactions),
2098     make_pair("signmessage",           &signmessage),
2099     make_pair("verifymessage",         &verifymessage),
2100     make_pair("getwork",                &getwork),
2101     make_pair("listaccounts",           &listaccounts),
2102     make_pair("settxfee",               &settxfee),
2103     make_pair("getmemorypool",          &getmemorypool),
2104     make_pair("listsinceblock",        &listsinceblock),
2105     make_pair("getcheckpoint",         &getcheckpoint),
2106     make_pair("reservebalance",         &reservebalance),
2107     make_pair("checkwallet",            &checkwallet),
2108     make_pair("repairwallet",           &repairwallet),
2109     make_pair("makekeypair",            &makekeypair),
2110     make_pair("sendalert",              &sendalert),
2111     make_pair("sendcheckpoint",         &sendcheckpoint),
2112 };
2113 map<string, rpcfn_type> mapCallTable(pCallTable, pCallTable + sizeof(pCallTable)/sizeof(pCallTable[0]));
2114
2115 string pAllowInSafeMode[] =
2116 {
2117     "help",
2118     "stop",
2119     "getblockcount",
2120     "getblocknumber",  // deprecated
2121     "getconnectioncount",
2122     "getdifficulty",
2123     "getgenerate",
2124     "setgenerate",
2125     "gethashespersec",
2126     "getinfo",
2127     "getnewaddress",
2128     "getaccountaddress",
2129     "getaccount",
2130     "getaddressesbyaccount",
2131     "backupwallet",
2132     "keypoolrefill",
2133     "walletpassphrase",
2134     "walletlock",
2135     "validateaddress",
2136     "getwork",
2137     "getmemorypool",
2138     "getcheckpoint",
2139 };
2140 set<string> setAllowInSafeMode(pAllowInSafeMode, pAllowInSafeMode + sizeof(pAllowInSafeMode)/sizeof(pAllowInSafeMode[0]));
2141
2142
2143
2144
2145 //
2146 // HTTP protocol
2147 //
2148 // This ain't Apache.  We're just using HTTP header for the length field
2149 // and to be compatible with other JSON-RPC implementations.
2150 //
2151
2152 string HTTPPost(const string& strMsg, const map<string,string>& mapRequestHeaders)
2153 {
2154     ostringstream s;
2155     s << "POST / HTTP/1.1\r\n"
2156       << "User-Agent: ppcoin-json-rpc/" << FormatFullVersion() << "\r\n"
2157       << "Host: 127.0.0.1\r\n"
2158       << "Content-Type: application/json\r\n"
2159       << "Content-Length: " << strMsg.size() << "\r\n"
2160       << "Connection: close\r\n"
2161       << "Accept: application/json\r\n";
2162     BOOST_FOREACH(const PAIRTYPE(string, string)& item, mapRequestHeaders)
2163         s << item.first << ": " << item.second << "\r\n";
2164     s << "\r\n" << strMsg;
2165
2166     return s.str();
2167 }
2168
2169 string rfc1123Time()
2170 {
2171     char buffer[64];
2172     time_t now;
2173     time(&now);
2174     struct tm* now_gmt = gmtime(&now);
2175     string locale(setlocale(LC_TIME, NULL));
2176     setlocale(LC_TIME, "C"); // we want posix (aka "C") weekday/month strings
2177     strftime(buffer, sizeof(buffer), "%a, %d %b %Y %H:%M:%S +0000", now_gmt);
2178     setlocale(LC_TIME, locale.c_str());
2179     return string(buffer);
2180 }
2181
2182 static string HTTPReply(int nStatus, const string& strMsg)
2183 {
2184     if (nStatus == 401)
2185         return strprintf("HTTP/1.0 401 Authorization Required\r\n"
2186             "Date: %s\r\n"
2187             "Server: ppcoin-json-rpc/%s\r\n"
2188             "WWW-Authenticate: Basic realm=\"jsonrpc\"\r\n"
2189             "Content-Type: text/html\r\n"
2190             "Content-Length: 296\r\n"
2191             "\r\n"
2192             "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\r\n"
2193             "\"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd\">\r\n"
2194             "<HTML>\r\n"
2195             "<HEAD>\r\n"
2196             "<TITLE>Error</TITLE>\r\n"
2197             "<META HTTP-EQUIV='Content-Type' CONTENT='text/html; charset=ISO-8859-1'>\r\n"
2198             "</HEAD>\r\n"
2199             "<BODY><H1>401 Unauthorized.</H1></BODY>\r\n"
2200             "</HTML>\r\n", rfc1123Time().c_str(), FormatFullVersion().c_str());
2201     const char *cStatus;
2202          if (nStatus == 200) cStatus = "OK";
2203     else if (nStatus == 400) cStatus = "Bad Request";
2204     else if (nStatus == 403) cStatus = "Forbidden";
2205     else if (nStatus == 404) cStatus = "Not Found";
2206     else if (nStatus == 500) cStatus = "Internal Server Error";
2207     else cStatus = "";
2208     return strprintf(
2209             "HTTP/1.1 %d %s\r\n"
2210             "Date: %s\r\n"
2211             "Connection: close\r\n"
2212             "Content-Length: %d\r\n"
2213             "Content-Type: application/json\r\n"
2214             "Server: ppcoin-json-rpc/%s\r\n"
2215             "\r\n"
2216             "%s",
2217         nStatus,
2218         cStatus,
2219         rfc1123Time().c_str(),
2220         strMsg.size(),
2221         FormatFullVersion().c_str(),
2222         strMsg.c_str());
2223 }
2224
2225 int ReadHTTPStatus(std::basic_istream<char>& stream)
2226 {
2227     string str;
2228     getline(stream, str);
2229     vector<string> vWords;
2230     boost::split(vWords, str, boost::is_any_of(" "));
2231     if (vWords.size() < 2)
2232         return 500;
2233     return atoi(vWords[1].c_str());
2234 }
2235
2236 int ReadHTTPHeader(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet)
2237 {
2238     int nLen = 0;
2239     loop
2240     {
2241         string str;
2242         std::getline(stream, str);
2243         if (str.empty() || str == "\r")
2244             break;
2245         string::size_type nColon = str.find(":");
2246         if (nColon != string::npos)
2247         {
2248             string strHeader = str.substr(0, nColon);
2249             boost::trim(strHeader);
2250             boost::to_lower(strHeader);
2251             string strValue = str.substr(nColon+1);
2252             boost::trim(strValue);
2253             mapHeadersRet[strHeader] = strValue;
2254             if (strHeader == "content-length")
2255                 nLen = atoi(strValue.c_str());
2256         }
2257     }
2258     return nLen;
2259 }
2260
2261 int ReadHTTP(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet, string& strMessageRet)
2262 {
2263     mapHeadersRet.clear();
2264     strMessageRet = "";
2265
2266     // Read status
2267     int nStatus = ReadHTTPStatus(stream);
2268
2269     // Read header
2270     int nLen = ReadHTTPHeader(stream, mapHeadersRet);
2271     if (nLen < 0 || nLen > MAX_SIZE)
2272         return 500;
2273
2274     // Read message
2275     if (nLen > 0)
2276     {
2277         vector<char> vch(nLen);
2278         stream.read(&vch[0], nLen);
2279         strMessageRet = string(vch.begin(), vch.end());
2280     }
2281
2282     return nStatus;
2283 }
2284
2285 bool HTTPAuthorized(map<string, string>& mapHeaders)
2286 {
2287     string strAuth = mapHeaders["authorization"];
2288     if (strAuth.substr(0,6) != "Basic ")
2289         return false;
2290     string strUserPass64 = strAuth.substr(6); boost::trim(strUserPass64);
2291     string strUserPass = DecodeBase64(strUserPass64);
2292     return strUserPass == strRPCUserColonPass;
2293 }
2294
2295 //
2296 // JSON-RPC protocol.  Bitcoin speaks version 1.0 for maximum compatibility,
2297 // but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
2298 // unspecified (HTTP errors and contents of 'error').
2299 //
2300 // 1.0 spec: http://json-rpc.org/wiki/specification
2301 // 1.2 spec: http://groups.google.com/group/json-rpc/web/json-rpc-over-http
2302 // http://www.codeproject.com/KB/recipes/JSON_Spirit.aspx
2303 //
2304
2305 string JSONRPCRequest(const string& strMethod, const Array& params, const Value& id)
2306 {
2307     Object request;
2308     request.push_back(Pair("method", strMethod));
2309     request.push_back(Pair("params", params));
2310     request.push_back(Pair("id", id));
2311     return write_string(Value(request), false) + "\n";
2312 }
2313
2314 string JSONRPCReply(const Value& result, const Value& error, const Value& id)
2315 {
2316     Object reply;
2317     if (error.type() != null_type)
2318         reply.push_back(Pair("result", Value::null));
2319     else
2320         reply.push_back(Pair("result", result));
2321     reply.push_back(Pair("error", error));
2322     reply.push_back(Pair("id", id));
2323     return write_string(Value(reply), false) + "\n";
2324 }
2325
2326 void ErrorReply(std::ostream& stream, const Object& objError, const Value& id)
2327 {
2328     // Send error reply from json-rpc error object
2329     int nStatus = 500;
2330     int code = find_value(objError, "code").get_int();
2331     if (code == -32600) nStatus = 400;
2332     else if (code == -32601) nStatus = 404;
2333     string strReply = JSONRPCReply(Value::null, objError, id);
2334     stream << HTTPReply(nStatus, strReply) << std::flush;
2335 }
2336
2337 bool ClientAllowed(const string& strAddress)
2338 {
2339     if (strAddress == asio::ip::address_v4::loopback().to_string())
2340         return true;
2341     const vector<string>& vAllow = mapMultiArgs["-rpcallowip"];
2342     BOOST_FOREACH(string strAllow, vAllow)
2343         if (WildcardMatch(strAddress, strAllow))
2344             return true;
2345     return false;
2346 }
2347
2348 #ifdef USE_SSL
2349 //
2350 // IOStream device that speaks SSL but can also speak non-SSL
2351 //
2352 class SSLIOStreamDevice : public iostreams::device<iostreams::bidirectional> {
2353 public:
2354     SSLIOStreamDevice(SSLStream &streamIn, bool fUseSSLIn) : stream(streamIn)
2355     {
2356         fUseSSL = fUseSSLIn;
2357         fNeedHandshake = fUseSSLIn;
2358     }
2359
2360     void handshake(ssl::stream_base::handshake_type role)
2361     {
2362         if (!fNeedHandshake) return;
2363         fNeedHandshake = false;
2364         stream.handshake(role);
2365     }
2366     std::streamsize read(char* s, std::streamsize n)
2367     {
2368         handshake(ssl::stream_base::server); // HTTPS servers read first
2369         if (fUseSSL) return stream.read_some(asio::buffer(s, n));
2370         return stream.next_layer().read_some(asio::buffer(s, n));
2371     }
2372     std::streamsize write(const char* s, std::streamsize n)
2373     {
2374         handshake(ssl::stream_base::client); // HTTPS clients write first
2375         if (fUseSSL) return asio::write(stream, asio::buffer(s, n));
2376         return asio::write(stream.next_layer(), asio::buffer(s, n));
2377     }
2378     bool connect(const std::string& server, const std::string& port)
2379     {
2380         ip::tcp::resolver resolver(stream.get_io_service());
2381         ip::tcp::resolver::query query(server.c_str(), port.c_str());
2382         ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
2383         ip::tcp::resolver::iterator end;
2384         boost::system::error_code error = asio::error::host_not_found;
2385         while (error && endpoint_iterator != end)
2386         {
2387             stream.lowest_layer().close();
2388             stream.lowest_layer().connect(*endpoint_iterator++, error);
2389         }
2390         if (error)
2391             return false;
2392         return true;
2393     }
2394
2395 private:
2396     bool fNeedHandshake;
2397     bool fUseSSL;
2398     SSLStream& stream;
2399 };
2400 #endif
2401
2402 void ThreadRPCServer(void* parg)
2403 {
2404     IMPLEMENT_RANDOMIZE_STACK(ThreadRPCServer(parg));
2405     try
2406     {
2407         vnThreadsRunning[4]++;
2408         ThreadRPCServer2(parg);
2409         vnThreadsRunning[4]--;
2410     }
2411     catch (std::exception& e) {
2412         vnThreadsRunning[4]--;
2413         PrintException(&e, "ThreadRPCServer()");
2414     } catch (...) {
2415         vnThreadsRunning[4]--;
2416         PrintException(NULL, "ThreadRPCServer()");
2417     }
2418     printf("ThreadRPCServer exiting\n");
2419 }
2420
2421 void ThreadRPCServer2(void* parg)
2422 {
2423     printf("ThreadRPCServer started\n");
2424
2425     strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"];
2426     if (strRPCUserColonPass == ":")
2427     {
2428         string strWhatAmI = "To use ppcoind";
2429         if (mapArgs.count("-server"))
2430             strWhatAmI = strprintf(_("To use the %s option"), "\"-server\"");
2431         else if (mapArgs.count("-daemon"))
2432             strWhatAmI = strprintf(_("To use the %s option"), "\"-daemon\"");
2433         PrintConsole(
2434             _("Error: %s, you must set rpcpassword=<password>\nin the configuration file: %s\n"
2435               "If the file does not exist, create it with owner-readable-only file permissions.\n"),
2436                 strWhatAmI.c_str(),
2437                 GetConfigFile().c_str());
2438 #ifndef QT_GUI
2439         CreateThread(Shutdown, NULL);
2440 #endif
2441         return;
2442     }
2443
2444     bool fUseSSL = GetBoolArg("-rpcssl");
2445     asio::ip::address bindAddress = mapArgs.count("-rpcallowip") ? asio::ip::address_v4::any() : asio::ip::address_v4::loopback();
2446
2447     asio::io_service io_service;
2448     ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", RPC_PORT));
2449     ip::tcp::acceptor acceptor(io_service, endpoint);
2450
2451     acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
2452
2453 #ifdef USE_SSL
2454     ssl::context context(io_service, ssl::context::sslv23);
2455     if (fUseSSL)
2456     {
2457         context.set_options(ssl::context::no_sslv2);
2458         filesystem::path certfile = GetArg("-rpcsslcertificatechainfile", "server.cert");
2459         if (!certfile.is_complete()) certfile = filesystem::path(GetDataDir()) / certfile;
2460         if (filesystem::exists(certfile)) context.use_certificate_chain_file(certfile.string().c_str());
2461         else printf("ThreadRPCServer ERROR: missing server certificate file %s\n", certfile.string().c_str());
2462         filesystem::path pkfile = GetArg("-rpcsslprivatekeyfile", "server.pem");
2463         if (!pkfile.is_complete()) pkfile = filesystem::path(GetDataDir()) / pkfile;
2464         if (filesystem::exists(pkfile)) context.use_private_key_file(pkfile.string().c_str(), ssl::context::pem);
2465         else printf("ThreadRPCServer ERROR: missing server private key file %s\n", pkfile.string().c_str());
2466
2467         string ciphers = GetArg("-rpcsslciphers",
2468                                          "TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH");
2469         SSL_CTX_set_cipher_list(context.impl(), ciphers.c_str());
2470     }
2471 #else
2472     if (fUseSSL)
2473         throw runtime_error("-rpcssl=1, but ppcoin compiled without full openssl libraries.");
2474 #endif
2475
2476     loop
2477     {
2478         // Accept connection
2479 #ifdef USE_SSL
2480         SSLStream sslStream(io_service, context);
2481         SSLIOStreamDevice d(sslStream, fUseSSL);
2482         iostreams::stream<SSLIOStreamDevice> stream(d);
2483 #else
2484         ip::tcp::iostream stream;
2485 #endif
2486
2487         ip::tcp::endpoint peer;
2488         vnThreadsRunning[4]--;
2489 #ifdef USE_SSL
2490         acceptor.accept(sslStream.lowest_layer(), peer);
2491 #else
2492         acceptor.accept(*stream.rdbuf(), peer);
2493 #endif
2494         vnThreadsRunning[4]++;
2495         if (fShutdown)
2496             return;
2497
2498         // Restrict callers by IP
2499         if (!ClientAllowed(peer.address().to_string()))
2500         {
2501             // Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake.
2502             if (!fUseSSL)
2503                 stream << HTTPReply(403, "") << std::flush;
2504             continue;
2505         }
2506
2507         map<string, string> mapHeaders;
2508         string strRequest;
2509
2510         boost::thread api_caller(ReadHTTP, boost::ref(stream), boost::ref(mapHeaders), boost::ref(strRequest));
2511         if (!api_caller.timed_join(boost::posix_time::seconds(GetArg("-rpctimeout", 30))))
2512         {   // Timed out:
2513             acceptor.cancel();
2514             printf("ThreadRPCServer ReadHTTP timeout\n");
2515             continue;
2516         }
2517
2518         // Check authorization
2519         if (mapHeaders.count("authorization") == 0)
2520         {
2521             stream << HTTPReply(401, "") << std::flush;
2522             continue;
2523         }
2524         if (!HTTPAuthorized(mapHeaders))
2525         {
2526             // Deter brute-forcing short passwords
2527             if (mapArgs["-rpcpassword"].size() < 15)
2528                 Sleep(50);
2529
2530             stream << HTTPReply(401, "") << std::flush;
2531             printf("ThreadRPCServer incorrect password attempt\n");
2532             continue;
2533         }
2534
2535         Value id = Value::null;
2536         try
2537         {
2538             // Parse request
2539             Value valRequest;
2540             if (!read_string(strRequest, valRequest) || valRequest.type() != obj_type)
2541                 throw JSONRPCError(-32700, "Parse error");
2542             const Object& request = valRequest.get_obj();
2543
2544             // Parse id now so errors from here on will have the id
2545             id = find_value(request, "id");
2546
2547             // Parse method
2548             Value valMethod = find_value(request, "method");
2549             if (valMethod.type() == null_type)
2550                 throw JSONRPCError(-32600, "Missing method");
2551             if (valMethod.type() != str_type)
2552                 throw JSONRPCError(-32600, "Method must be a string");
2553             string strMethod = valMethod.get_str();
2554             if (strMethod != "getwork" && strMethod != "getmemorypool")
2555                 printf("ThreadRPCServer method=%s\n", strMethod.c_str());
2556
2557             // Parse params
2558             Value valParams = find_value(request, "params");
2559             Array params;
2560             if (valParams.type() == array_type)
2561                 params = valParams.get_array();
2562             else if (valParams.type() == null_type)
2563                 params = Array();
2564             else
2565                 throw JSONRPCError(-32600, "Params must be an array");
2566
2567             // Find method
2568             map<string, rpcfn_type>::iterator mi = mapCallTable.find(strMethod);
2569             if (mi == mapCallTable.end())
2570                 throw JSONRPCError(-32601, "Method not found");
2571
2572             // Observe safe mode
2573             string strWarning = GetWarnings("rpc");
2574             if (strWarning != "" && !GetBoolArg("-disablesafemode") && !setAllowInSafeMode.count(strMethod))
2575                 throw JSONRPCError(-2, string("Safe mode: ") + strWarning);
2576
2577             try
2578             {
2579                 // Execute
2580                 Value result;
2581                 CRITICAL_BLOCK(cs_main)
2582                 CRITICAL_BLOCK(pwalletMain->cs_wallet)
2583                     result = (*(*mi).second)(params, false);
2584
2585                 // Send reply
2586                 string strReply = JSONRPCReply(result, Value::null, id);
2587                 stream << HTTPReply(200, strReply) << std::flush;
2588             }
2589             catch (std::exception& e)
2590             {
2591                 ErrorReply(stream, JSONRPCError(-1, e.what()), id);
2592             }
2593         }
2594         catch (Object& objError)
2595         {
2596             ErrorReply(stream, objError, id);
2597         }
2598         catch (std::exception& e)
2599         {
2600             ErrorReply(stream, JSONRPCError(-32700, e.what()), id);
2601         }
2602     }
2603 }
2604
2605
2606
2607
2608 Object CallRPC(const string& strMethod, const Array& params)
2609 {
2610     if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
2611         throw runtime_error(strprintf(
2612             _("You must set rpcpassword=<password> in the configuration file:\n%s\n"
2613               "If the file does not exist, create it with owner-readable-only file permissions."),
2614                 GetConfigFile().c_str()));
2615
2616     // Connect to localhost
2617     bool fUseSSL = GetBoolArg("-rpcssl");
2618 #ifdef USE_SSL
2619     asio::io_service io_service;
2620     ssl::context context(io_service, ssl::context::sslv23);
2621     context.set_options(ssl::context::no_sslv2);
2622     SSLStream sslStream(io_service, context);
2623     SSLIOStreamDevice d(sslStream, fUseSSL);
2624     iostreams::stream<SSLIOStreamDevice> stream(d);
2625     if (!d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", CBigNum(RPC_PORT).ToString().c_str())))
2626         throw runtime_error("couldn't connect to server");
2627 #else
2628     if (fUseSSL)
2629         throw runtime_error("-rpcssl=1, but ppcoin compiled without full openssl libraries.");
2630
2631     ip::tcp::iostream stream(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", CBigNum(RPC_PORT).ToString().c_str()));
2632     if (stream.fail())
2633         throw runtime_error("couldn't connect to server");
2634 #endif
2635
2636
2637     // HTTP basic authentication
2638     string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
2639     map<string, string> mapRequestHeaders;
2640     mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64;
2641
2642     // Send request
2643     string strRequest = JSONRPCRequest(strMethod, params, 1);
2644     string strPost = HTTPPost(strRequest, mapRequestHeaders);
2645     stream << strPost << std::flush;
2646
2647     // Receive reply
2648     map<string, string> mapHeaders;
2649     string strReply;
2650     int nStatus = ReadHTTP(stream, mapHeaders, strReply);
2651     if (nStatus == 401)
2652         throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
2653     else if (nStatus >= 400 && nStatus != 400 && nStatus != 404 && nStatus != 500)
2654         throw runtime_error(strprintf("server returned HTTP error %d", nStatus));
2655     else if (strReply.empty())
2656         throw runtime_error("no response from server");
2657
2658     // Parse reply
2659     Value valReply;
2660     if (!read_string(strReply, valReply))
2661         throw runtime_error("couldn't parse reply from server");
2662     const Object& reply = valReply.get_obj();
2663     if (reply.empty())
2664         throw runtime_error("expected reply to have result, error and id properties");
2665
2666     return reply;
2667 }
2668
2669
2670
2671
2672 template<typename T>
2673 void ConvertTo(Value& value)
2674 {
2675     if (value.type() == str_type)
2676     {
2677         // reinterpret string as unquoted json value
2678         Value value2;
2679         if (!read_string(value.get_str(), value2))
2680             throw runtime_error("type mismatch");
2681         value = value2.get_value<T>();
2682     }
2683     else
2684     {
2685         value = value.get_value<T>();
2686     }
2687 }
2688
2689 int CommandLineRPC(int argc, char *argv[])
2690 {
2691     string strPrint;
2692     int nRet = 0;
2693     try
2694     {
2695         // Skip switches
2696         while (argc > 1 && IsSwitchChar(argv[1][0]))
2697         {
2698             argc--;
2699             argv++;
2700         }
2701
2702         // Method
2703         if (argc < 2)
2704             throw runtime_error("too few parameters");
2705         string strMethod = argv[1];
2706
2707         // Parameters default to strings
2708         Array params;
2709         for (int i = 2; i < argc; i++)
2710             params.push_back(argv[i]);
2711         int n = params.size();
2712
2713         //
2714         // Special case non-string parameter types
2715         //
2716         if (strMethod == "setgenerate"            && n > 0) ConvertTo<bool>(params[0]);
2717         if (strMethod == "setgenerate"            && n > 1) ConvertTo<boost::int64_t>(params[1]);
2718         if (strMethod == "sendtoaddress"          && n > 1) ConvertTo<double>(params[1]);
2719         if (strMethod == "settxfee"               && n > 0) ConvertTo<double>(params[0]);
2720         if (strMethod == "getreceivedbyaddress"   && n > 1) ConvertTo<boost::int64_t>(params[1]);
2721         if (strMethod == "getreceivedbyaccount"   && n > 1) ConvertTo<boost::int64_t>(params[1]);
2722         if (strMethod == "listreceivedbyaddress"  && n > 0) ConvertTo<boost::int64_t>(params[0]);
2723         if (strMethod == "listreceivedbyaddress"  && n > 1) ConvertTo<bool>(params[1]);
2724         if (strMethod == "listreceivedbyaccount"  && n > 0) ConvertTo<boost::int64_t>(params[0]);
2725         if (strMethod == "listreceivedbyaccount"  && n > 1) ConvertTo<bool>(params[1]);
2726         if (strMethod == "getbalance"             && n > 1) ConvertTo<boost::int64_t>(params[1]);
2727         if (strMethod == "move"                   && n > 2) ConvertTo<double>(params[2]);
2728         if (strMethod == "move"                   && n > 3) ConvertTo<boost::int64_t>(params[3]);
2729         if (strMethod == "sendfrom"               && n > 2) ConvertTo<double>(params[2]);
2730         if (strMethod == "sendfrom"               && n > 3) ConvertTo<boost::int64_t>(params[3]);
2731         if (strMethod == "listtransactions"       && n > 1) ConvertTo<boost::int64_t>(params[1]);
2732         if (strMethod == "listtransactions"       && n > 2) ConvertTo<boost::int64_t>(params[2]);
2733         if (strMethod == "listaccounts"           && n > 0) ConvertTo<boost::int64_t>(params[0]);
2734         if (strMethod == "walletpassphrase"       && n > 1) ConvertTo<boost::int64_t>(params[1]);
2735         if (strMethod == "walletpassphrase"       && n > 2) ConvertTo<bool>(params[2]);
2736         if (strMethod == "listsinceblock"         && n > 1) ConvertTo<boost::int64_t>(params[1]);
2737         if (strMethod == "sendalert"              && n > 2) ConvertTo<boost::int64_t>(params[2]);
2738         if (strMethod == "sendalert"              && n > 3) ConvertTo<boost::int64_t>(params[3]);
2739         if (strMethod == "sendalert"              && n > 4) ConvertTo<boost::int64_t>(params[4]);
2740         if (strMethod == "sendalert"              && n > 5) ConvertTo<boost::int64_t>(params[5]);
2741         if (strMethod == "sendmany"               && n > 1)
2742         {
2743             string s = params[1].get_str();
2744             Value v;
2745             if (!read_string(s, v) || v.type() != obj_type)
2746                 throw runtime_error("type mismatch");
2747             params[1] = v.get_obj();
2748         }
2749         if (strMethod == "sendmany"                && n > 2) ConvertTo<boost::int64_t>(params[2]);
2750         if (strMethod == "reservebalance"          && n > 0) ConvertTo<bool>(params[0]);
2751         if (strMethod == "reservebalance"          && n > 1) ConvertTo<double>(params[1]);
2752
2753         // Execute
2754         Object reply = CallRPC(strMethod, params);
2755
2756         // Parse reply
2757         const Value& result = find_value(reply, "result");
2758         const Value& error  = find_value(reply, "error");
2759
2760         if (error.type() != null_type)
2761         {
2762             // Error
2763             strPrint = "error: " + write_string(error, false);
2764             int code = find_value(error.get_obj(), "code").get_int();
2765             nRet = abs(code);
2766         }
2767         else
2768         {
2769             // Result
2770             if (result.type() == null_type)
2771                 strPrint = "";
2772             else if (result.type() == str_type)
2773                 strPrint = result.get_str();
2774             else
2775                 strPrint = write_string(result, true);
2776         }
2777     }
2778     catch (std::exception& e)
2779     {
2780         strPrint = string("error: ") + e.what();
2781         nRet = 87;
2782     }
2783     catch (...)
2784     {
2785         PrintException(NULL, "CommandLineRPC()");
2786     }
2787
2788     if (strPrint != "")
2789     {
2790         fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
2791     }
2792     return nRet;
2793 }
2794
2795
2796
2797
2798 #ifdef TEST
2799 int main(int argc, char *argv[])
2800 {
2801 #ifdef _MSC_VER
2802     // Turn off microsoft heap dump noise
2803     _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
2804     _CrtSetReportFile(_CRT_WARN, CreateFile("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0));
2805 #endif
2806     setbuf(stdin, NULL);
2807     setbuf(stdout, NULL);
2808     setbuf(stderr, NULL);
2809
2810     try
2811     {
2812         if (argc >= 2 && string(argv[1]) == "-server")
2813         {
2814             printf("server ready\n");
2815             ThreadRPCServer(NULL);
2816         }
2817         else
2818         {
2819             return CommandLineRPC(argc, argv);
2820         }
2821     }
2822     catch (std::exception& e) {
2823         PrintException(&e, "main()");
2824     } catch (...) {
2825         PrintException(NULL, "main()");
2826     }
2827     return 0;
2828 }
2829 #endif