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