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