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