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