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