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