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