50299cc88ce95713b9dd00f46a0a5b437584068f
[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             BOOST_FOREACH(const CTxIn& txin, tx.vin)
163                 txinfo.push_back(txin.ToStringShort());
164             BOOST_FOREACH(const CTxOut& txout, tx.vout)
165                 txinfo.push_back(txout.ToStringShort());
166         }
167         else
168             txinfo.push_back(tx.GetHash().GetHex());
169     }
170     result.push_back(Pair("tx", txinfo));
171     return result;
172 }
173
174
175
176 ///
177 /// Note: This interface may still be subject to change.
178 ///
179
180 string CRPCTable::help(string strCommand) const
181 {
182     string strRet;
183     set<rpcfn_type> setDone;
184     for (map<string, const CRPCCommand*>::const_iterator mi = mapCommands.begin(); mi != mapCommands.end(); ++mi)
185     {
186         const CRPCCommand *pcmd = mi->second;
187         string strMethod = mi->first;
188         // We already filter duplicates, but these deprecated screw up the sort order
189         if (strMethod == "getamountreceived" ||
190             strMethod == "getallreceived" ||
191             strMethod == "getblocknumber" || // deprecated
192             (strMethod.find("label") != string::npos))
193             continue;
194         if (strCommand != "" && strMethod != strCommand)
195             continue;
196         try
197         {
198             Array params;
199             rpcfn_type pfn = pcmd->actor;
200             if (setDone.insert(pfn).second)
201                 (*pfn)(params, true);
202         }
203         catch (std::exception& e)
204         {
205             // Help text is returned in an exception
206             string strHelp = string(e.what());
207             if (strCommand == "")
208                 if (strHelp.find('\n') != string::npos)
209                     strHelp = strHelp.substr(0, strHelp.find('\n'));
210             strRet += strHelp + "\n";
211         }
212     }
213     if (strRet == "")
214         strRet = strprintf("help: unknown command: %s\n", strCommand.c_str());
215     strRet = strRet.substr(0,strRet.size()-1);
216     return strRet;
217 }
218
219 Value help(const Array& params, bool fHelp)
220 {
221     if (fHelp || params.size() > 1)
222         throw runtime_error(
223             "help [command]\n"
224             "List commands, or get help for a command.");
225
226     string strCommand;
227     if (params.size() > 0)
228         strCommand = params[0].get_str();
229
230     return tableRPC.help(strCommand);
231 }
232
233
234 Value stop(const Array& params, bool fHelp)
235 {
236     if (fHelp || params.size() != 0)
237         throw runtime_error(
238             "stop\n"
239             "Stop ppcoin server.");
240     // Shutdown will take long enough that the response should get back
241     StartShutdown();
242     return "ppcoin server stopping";
243 }
244
245
246 Value getblockcount(const Array& params, bool fHelp)
247 {
248     if (fHelp || params.size() != 0)
249         throw runtime_error(
250             "getblockcount\n"
251             "Returns the number of blocks in the longest block chain.");
252
253     return nBestHeight;
254 }
255
256
257 // deprecated
258 Value getblocknumber(const Array& params, bool fHelp)
259 {
260     if (fHelp || params.size() != 0)
261         throw runtime_error(
262             "getblocknumber\n"
263             "Deprecated.  Use getblockcount.");
264
265     return nBestHeight;
266 }
267
268
269 Value getconnectioncount(const Array& params, bool fHelp)
270 {
271     if (fHelp || params.size() != 0)
272         throw runtime_error(
273             "getconnectioncount\n"
274             "Returns the number of connections to other nodes.");
275
276     return (int)vNodes.size();
277 }
278
279
280 Value getdifficulty(const Array& params, bool fHelp)
281 {
282     if (fHelp || params.size() != 0)
283         throw runtime_error(
284             "getdifficulty\n"
285             "Returns difficulty as a multiple of the minimum difficulty.");
286
287     Object obj;
288     obj.push_back(Pair("proof-of-work",        GetDifficulty()));
289     obj.push_back(Pair("proof-of-stake",       GetDifficulty(GetLastBlockIndex(pindexBest, true))));
290     return obj;
291 }
292
293
294 Value getgenerate(const Array& params, bool fHelp)
295 {
296     if (fHelp || params.size() != 0)
297         throw runtime_error(
298             "getgenerate\n"
299             "Returns true or false.");
300
301     return GetBoolArg("-gen");
302 }
303
304
305 Value setgenerate(const Array& params, bool fHelp)
306 {
307     if (fHelp || params.size() < 1 || params.size() > 2)
308         throw runtime_error(
309             "setgenerate <generate> [genproclimit]\n"
310             "<generate> is true or false to turn generation on or off.\n"
311             "Generation is limited to [genproclimit] processors, -1 is unlimited.");
312
313     bool fGenerate = true;
314     if (params.size() > 0)
315         fGenerate = params[0].get_bool();
316
317     if (params.size() > 1)
318     {
319         int nGenProcLimit = params[1].get_int();
320         mapArgs["-genproclimit"] = itostr(nGenProcLimit);
321         if (nGenProcLimit == 0)
322             fGenerate = false;
323     }
324     mapArgs["-gen"] = (fGenerate ? "1" : "0");
325
326     GenerateBitcoins(fGenerate, pwalletMain);
327     return Value::null;
328 }
329
330
331 Value gethashespersec(const Array& params, bool fHelp)
332 {
333     if (fHelp || params.size() != 0)
334         throw runtime_error(
335             "gethashespersec\n"
336             "Returns a recent hashes per second performance measurement while generating.");
337
338     if (GetTimeMillis() - nHPSTimerStart > 8000)
339         return (boost::int64_t)0;
340     return (boost::int64_t)dHashesPerSec;
341 }
342
343
344 Value getinfo(const Array& params, bool fHelp)
345 {
346     if (fHelp || params.size() != 0)
347         throw runtime_error(
348             "getinfo\n"
349             "Returns an object containing various state info.");
350
351     Object obj;
352     obj.push_back(Pair("version",       FormatFullVersion()));
353     obj.push_back(Pair("protocolversion",(int)PROTOCOL_VERSION));
354     obj.push_back(Pair("walletversion", pwalletMain->GetVersion()));
355     obj.push_back(Pair("balance",       ValueFromAmount(pwalletMain->GetBalance())));
356     obj.push_back(Pair("newmint",       ValueFromAmount(pwalletMain->GetNewMint())));
357     obj.push_back(Pair("stake",         ValueFromAmount(pwalletMain->GetStake())));
358     obj.push_back(Pair("blocks",        (int)nBestHeight));
359     obj.push_back(Pair("moneysupply",   ValueFromAmount(pindexBest->nMoneySupply)));
360     obj.push_back(Pair("connections",   (int)vNodes.size()));
361     obj.push_back(Pair("proxy",         (fUseProxy ? addrProxy.ToStringIPPort() : string())));
362     obj.push_back(Pair("ip",            addrSeenByPeer.ToStringIP()));
363     obj.push_back(Pair("difficulty",    (double)GetDifficulty()));
364     obj.push_back(Pair("testnet",       fTestNet));
365     obj.push_back(Pair("keypoololdest", (boost::int64_t)pwalletMain->GetOldestKeyPoolTime()));
366     obj.push_back(Pair("keypoolsize",   pwalletMain->GetKeyPoolSize()));
367     obj.push_back(Pair("paytxfee",      ValueFromAmount(nTransactionFee)));
368     if (pwalletMain->IsCrypted())
369         obj.push_back(Pair("unlocked_until", (boost::int64_t)nWalletUnlockTime / 1000));
370     obj.push_back(Pair("errors",        GetWarnings("statusbar")));
371     return obj;
372 }
373
374
375 Value getmininginfo(const Array& params, bool fHelp)
376 {
377     if (fHelp || params.size() != 0)
378         throw runtime_error(
379             "getmininginfo\n"
380             "Returns an object containing mining-related information.");
381
382     Object obj;
383     obj.push_back(Pair("blocks",        (int)nBestHeight));
384     obj.push_back(Pair("currentblocksize",(uint64_t)nLastBlockSize));
385     obj.push_back(Pair("currentblocktx",(uint64_t)nLastBlockTx));
386     obj.push_back(Pair("difficulty",    (double)GetDifficulty()));
387     obj.push_back(Pair("errors",        GetWarnings("statusbar")));
388     obj.push_back(Pair("generate",      GetBoolArg("-gen")));
389     obj.push_back(Pair("genproclimit",  (int)GetArg("-genproclimit", -1)));
390     obj.push_back(Pair("hashespersec",  gethashespersec(params, false)));
391     obj.push_back(Pair("pooledtx",      (uint64_t)mempool.size()));
392     obj.push_back(Pair("testnet",       fTestNet));
393     return obj;
394 }
395
396
397 Value getnewaddress(const Array& params, bool fHelp)
398 {
399     if (fHelp || params.size() > 1)
400         throw runtime_error(
401             "getnewaddress [account]\n"
402             "Returns a new ppcoin address for receiving payments.  "
403             "If [account] is specified (recommended), it is added to the address book "
404             "so payments received with the address will be credited to [account].");
405
406     // Parse the account first so we don't generate a key if there's an error
407     string strAccount;
408     if (params.size() > 0)
409         strAccount = AccountFromValue(params[0]);
410
411     if (!pwalletMain->IsLocked())
412         pwalletMain->TopUpKeyPool();
413
414     // Generate a new key that is added to wallet
415     std::vector<unsigned char> newKey;
416     if (!pwalletMain->GetKeyFromPool(newKey, false))
417         throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
418     CBitcoinAddress address(newKey);
419
420     pwalletMain->SetAddressBookName(address, strAccount);
421
422     return address.ToString();
423 }
424
425
426 CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false)
427 {
428     CWalletDB walletdb(pwalletMain->strWalletFile);
429
430     CAccount account;
431     walletdb.ReadAccount(strAccount, account);
432
433     bool bKeyUsed = false;
434
435     // Check if the current key has been used
436     if (!account.vchPubKey.empty())
437     {
438         CScript scriptPubKey;
439         scriptPubKey.SetBitcoinAddress(account.vchPubKey);
440         for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
441              it != pwalletMain->mapWallet.end() && !account.vchPubKey.empty();
442              ++it)
443         {
444             const CWalletTx& wtx = (*it).second;
445             BOOST_FOREACH(const CTxOut& txout, wtx.vout)
446                 if (txout.scriptPubKey == scriptPubKey)
447                     bKeyUsed = true;
448         }
449     }
450
451     // Generate a new key
452     if (account.vchPubKey.empty() || bForceNew || bKeyUsed)
453     {
454         if (!pwalletMain->GetKeyFromPool(account.vchPubKey, false))
455             throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
456
457         pwalletMain->SetAddressBookName(CBitcoinAddress(account.vchPubKey), strAccount);
458         walletdb.WriteAccount(strAccount, account);
459     }
460
461     return CBitcoinAddress(account.vchPubKey);
462 }
463
464 Value getaccountaddress(const Array& params, bool fHelp)
465 {
466     if (fHelp || params.size() != 1)
467         throw runtime_error(
468             "getaccountaddress <account>\n"
469             "Returns the current ppcoin address for receiving payments to this account.");
470
471     // Parse the account first so we don't generate a key if there's an error
472     string strAccount = AccountFromValue(params[0]);
473
474     Value ret;
475
476     ret = GetAccountAddress(strAccount).ToString();
477
478     return ret;
479 }
480
481
482
483 Value setaccount(const Array& params, bool fHelp)
484 {
485     if (fHelp || params.size() < 1 || params.size() > 2)
486         throw runtime_error(
487             "setaccount <ppcoinaddress> <account>\n"
488             "Sets the account associated with the given address.");
489
490     CBitcoinAddress address(params[0].get_str());
491     if (!address.IsValid())
492         throw JSONRPCError(-5, "Invalid ppcoin address");
493
494
495     string strAccount;
496     if (params.size() > 1)
497         strAccount = AccountFromValue(params[1]);
498
499     // Detect when changing the account of an address that is the 'unused current key' of another account:
500     if (pwalletMain->mapAddressBook.count(address))
501     {
502         string strOldAccount = pwalletMain->mapAddressBook[address];
503         if (address == GetAccountAddress(strOldAccount))
504             GetAccountAddress(strOldAccount, true);
505     }
506
507     pwalletMain->SetAddressBookName(address, strAccount);
508
509     return Value::null;
510 }
511
512
513 Value getaccount(const Array& params, bool fHelp)
514 {
515     if (fHelp || params.size() != 1)
516         throw runtime_error(
517             "getaccount <ppcoinaddress>\n"
518             "Returns the account associated with the given address.");
519
520     CBitcoinAddress address(params[0].get_str());
521     if (!address.IsValid())
522         throw JSONRPCError(-5, "Invalid ppcoin address");
523
524     string strAccount;
525     map<CBitcoinAddress, string>::iterator mi = pwalletMain->mapAddressBook.find(address);
526     if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.empty())
527         strAccount = (*mi).second;
528     return strAccount;
529 }
530
531
532 Value getaddressesbyaccount(const Array& params, bool fHelp)
533 {
534     if (fHelp || params.size() != 1)
535         throw runtime_error(
536             "getaddressesbyaccount <account>\n"
537             "Returns the list of addresses for the given account.");
538
539     string strAccount = AccountFromValue(params[0]);
540
541     // Find all addresses that have the given account
542     Array ret;
543     BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
544     {
545         const CBitcoinAddress& address = item.first;
546         const string& strName = item.second;
547         if (strName == strAccount)
548             ret.push_back(address.ToString());
549     }
550     return ret;
551 }
552
553 Value settxfee(const Array& params, bool fHelp)
554 {
555     if (fHelp || params.size() < 1 || params.size() > 1 || AmountFromValue(params[0]) < MIN_TX_FEE)
556         throw runtime_error(
557             "settxfee <amount>\n"
558             "<amount> is a real and is rounded to 0.01 (cent)\n"
559             "Minimum and default transaction fee per KB is 1 cent");
560
561     nTransactionFee = AmountFromValue(params[0]);
562     nTransactionFee = (nTransactionFee / CENT) * CENT;  // round to cent
563     return true;
564 }
565
566 Value sendtoaddress(const Array& params, bool fHelp)
567 {
568     if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
569         throw runtime_error(
570             "sendtoaddress <ppcoinaddress> <amount> [comment] [comment-to]\n"
571             "<amount> is a real and is rounded to the nearest 0.000001\n"
572             "requires wallet passphrase to be set with walletpassphrase first");
573     if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
574         throw runtime_error(
575             "sendtoaddress <ppcoinaddress> <amount> [comment] [comment-to]\n"
576             "<amount> is a real and is rounded to the nearest 0.000001");
577
578     CBitcoinAddress address(params[0].get_str());
579     if (!address.IsValid())
580         throw JSONRPCError(-5, "Invalid ppcoin address");
581
582     // Amount
583     int64 nAmount = AmountFromValue(params[1]);
584     if (nAmount < MIN_TXOUT_AMOUNT)
585         throw JSONRPCError(-101, "Send amount too small");
586
587     // Wallet comments
588     CWalletTx wtx;
589     if (params.size() > 2 && params[2].type() != null_type && !params[2].get_str().empty())
590         wtx.mapValue["comment"] = params[2].get_str();
591     if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
592         wtx.mapValue["to"]      = params[3].get_str();
593
594     if (pwalletMain->IsLocked())
595         throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
596
597     string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
598     if (strError != "")
599         throw JSONRPCError(-4, strError);
600
601     return wtx.GetHash().GetHex();
602 }
603
604 Value signmessage(const Array& params, bool fHelp)
605 {
606     if (fHelp || params.size() != 2)
607         throw runtime_error(
608             "signmessage <ppcoinaddress> <message>\n"
609             "Sign a message with the private key of an address");
610
611     if (pwalletMain->IsLocked())
612         throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
613
614     string strAddress = params[0].get_str();
615     string strMessage = params[1].get_str();
616
617     CBitcoinAddress addr(strAddress);
618     if (!addr.IsValid())
619         throw JSONRPCError(-3, "Invalid address");
620
621     CKey key;
622     if (!pwalletMain->GetKey(addr, key))
623         throw JSONRPCError(-4, "Private key not available");
624
625     CDataStream ss(SER_GETHASH, 0);
626     ss << strMessageMagic;
627     ss << strMessage;
628
629     vector<unsigned char> vchSig;
630     if (!key.SignCompact(Hash(ss.begin(), ss.end()), vchSig))
631         throw JSONRPCError(-5, "Sign failed");
632
633     return EncodeBase64(&vchSig[0], vchSig.size());
634 }
635
636 Value verifymessage(const Array& params, bool fHelp)
637 {
638     if (fHelp || params.size() != 3)
639         throw runtime_error(
640             "verifymessage <ppcoinaddress> <signature> <message>\n"
641             "Verify a signed message");
642
643     string strAddress  = params[0].get_str();
644     string strSign     = params[1].get_str();
645     string strMessage  = params[2].get_str();
646
647     CBitcoinAddress addr(strAddress);
648     if (!addr.IsValid())
649         throw JSONRPCError(-3, "Invalid address");
650
651     bool fInvalid = false;
652     vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid);
653
654     if (fInvalid)
655         throw JSONRPCError(-5, "Malformed base64 encoding");
656
657     CDataStream ss(SER_GETHASH, 0);
658     ss << strMessageMagic;
659     ss << strMessage;
660
661     CKey key;
662     if (!key.SetCompactSignature(Hash(ss.begin(), ss.end()), vchSig))
663         return false;
664
665     return (CBitcoinAddress(key.GetPubKey()) == addr);
666 }
667
668
669 Value getreceivedbyaddress(const Array& params, bool fHelp)
670 {
671     if (fHelp || params.size() < 1 || params.size() > 2)
672         throw runtime_error(
673             "getreceivedbyaddress <ppcoinaddress> [minconf=1]\n"
674             "Returns the total amount received by <ppcoinaddress> in transactions with at least [minconf] confirmations.");
675
676     // Bitcoin address
677     CBitcoinAddress address = CBitcoinAddress(params[0].get_str());
678     CScript scriptPubKey;
679     if (!address.IsValid())
680         throw JSONRPCError(-5, "Invalid ppcoin address");
681     scriptPubKey.SetBitcoinAddress(address);
682     if (!IsMine(*pwalletMain,scriptPubKey))
683         return (double)0.0;
684
685     // Minimum confirmations
686     int nMinDepth = 1;
687     if (params.size() > 1)
688         nMinDepth = params[1].get_int();
689
690     // Tally
691     int64 nAmount = 0;
692     for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
693     {
694         const CWalletTx& wtx = (*it).second;
695         if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
696             continue;
697
698         BOOST_FOREACH(const CTxOut& txout, wtx.vout)
699             if (txout.scriptPubKey == scriptPubKey)
700                 if (wtx.GetDepthInMainChain() >= nMinDepth)
701                     nAmount += txout.nValue;
702     }
703
704     return  ValueFromAmount(nAmount);
705 }
706
707
708 void GetAccountAddresses(string strAccount, set<CBitcoinAddress>& setAddress)
709 {
710     BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
711     {
712         const CBitcoinAddress& address = item.first;
713         const string& strName = item.second;
714         if (strName == strAccount)
715             setAddress.insert(address);
716     }
717 }
718
719
720 Value getreceivedbyaccount(const Array& params, bool fHelp)
721 {
722     if (fHelp || params.size() < 1 || params.size() > 2)
723         throw runtime_error(
724             "getreceivedbyaccount <account> [minconf=1]\n"
725             "Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.");
726
727     // Minimum confirmations
728     int nMinDepth = 1;
729     if (params.size() > 1)
730         nMinDepth = params[1].get_int();
731
732     // Get the set of pub keys assigned to account
733     string strAccount = AccountFromValue(params[0]);
734     set<CBitcoinAddress> setAddress;
735     GetAccountAddresses(strAccount, setAddress);
736
737     // Tally
738     int64 nAmount = 0;
739     for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
740     {
741         const CWalletTx& wtx = (*it).second;
742         if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
743             continue;
744
745         BOOST_FOREACH(const CTxOut& txout, wtx.vout)
746         {
747             CBitcoinAddress address;
748             if (ExtractAddress(txout.scriptPubKey, address) && pwalletMain->HaveKey(address) && setAddress.count(address))
749                 if (wtx.GetDepthInMainChain() >= nMinDepth)
750                     nAmount += txout.nValue;
751         }
752     }
753
754     return (double)nAmount / (double)COIN;
755 }
756
757
758 int64 GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth)
759 {
760     int64 nBalance = 0;
761
762     // Tally wallet transactions
763     for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
764     {
765         const CWalletTx& wtx = (*it).second;
766         if (!wtx.IsFinal())
767             continue;
768
769         int64 nGenerated, nReceived, nSent, nFee;
770         wtx.GetAccountAmounts(strAccount, nGenerated, nReceived, nSent, nFee);
771
772         if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
773             nBalance += nReceived;
774         nBalance += nGenerated - nSent - nFee;
775     }
776
777     // Tally internal accounting entries
778     nBalance += walletdb.GetAccountCreditDebit(strAccount);
779
780     return nBalance;
781 }
782
783 int64 GetAccountBalance(const string& strAccount, int nMinDepth)
784 {
785     CWalletDB walletdb(pwalletMain->strWalletFile);
786     return GetAccountBalance(walletdb, strAccount, nMinDepth);
787 }
788
789
790 Value getbalance(const Array& params, bool fHelp)
791 {
792     if (fHelp || params.size() > 2)
793         throw runtime_error(
794             "getbalance [account] [minconf=1]\n"
795             "If [account] is not specified, returns the server's total available balance.\n"
796             "If [account] is specified, returns the balance in the account.");
797
798     if (params.size() == 0)
799         return  ValueFromAmount(pwalletMain->GetBalance());
800
801     int nMinDepth = 1;
802     if (params.size() > 1)
803         nMinDepth = params[1].get_int();
804
805     if (params[0].get_str() == "*") {
806         // Calculate total balance a different way from GetBalance()
807         // (GetBalance() sums up all unspent TxOuts)
808         // getbalance and getbalance '*' should always return the same number.
809         int64 nBalance = 0;
810         for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
811         {
812             const CWalletTx& wtx = (*it).second;
813             if (!wtx.IsFinal())
814                 continue;
815
816             int64 allGeneratedImmature, allGeneratedMature, allFee;
817             allGeneratedImmature = allGeneratedMature = allFee = 0;
818             string strSentAccount;
819             list<pair<CBitcoinAddress, int64> > listReceived;
820             list<pair<CBitcoinAddress, int64> > listSent;
821             wtx.GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount);
822             if (wtx.GetDepthInMainChain() >= nMinDepth)
823             {
824                 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listReceived)
825                     nBalance += r.second;
826             }
827             BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listSent)
828                 nBalance -= r.second;
829             nBalance -= allFee;
830             nBalance += allGeneratedMature;
831         }
832         return  ValueFromAmount(nBalance);
833     }
834
835     string strAccount = AccountFromValue(params[0]);
836
837     int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
838
839     return ValueFromAmount(nBalance);
840 }
841
842
843 Value movecmd(const Array& params, bool fHelp)
844 {
845     if (fHelp || params.size() < 3 || params.size() > 5)
846         throw runtime_error(
847             "move <fromaccount> <toaccount> <amount> [minconf=1] [comment]\n"
848             "Move from one account in your wallet to another.");
849
850     string strFrom = AccountFromValue(params[0]);
851     string strTo = AccountFromValue(params[1]);
852     int64 nAmount = AmountFromValue(params[2]);
853     if (params.size() > 3)
854         // unused parameter, used to be nMinDepth, keep type-checking it though
855         (void)params[3].get_int();
856     string strComment;
857     if (params.size() > 4)
858         strComment = params[4].get_str();
859
860     CWalletDB walletdb(pwalletMain->strWalletFile);
861     if (!walletdb.TxnBegin())
862         throw JSONRPCError(-20, "database error");
863
864     int64 nNow = GetAdjustedTime();
865
866     // Debit
867     CAccountingEntry debit;
868     debit.strAccount = strFrom;
869     debit.nCreditDebit = -nAmount;
870     debit.nTime = nNow;
871     debit.strOtherAccount = strTo;
872     debit.strComment = strComment;
873     walletdb.WriteAccountingEntry(debit);
874
875     // Credit
876     CAccountingEntry credit;
877     credit.strAccount = strTo;
878     credit.nCreditDebit = nAmount;
879     credit.nTime = nNow;
880     credit.strOtherAccount = strFrom;
881     credit.strComment = strComment;
882     walletdb.WriteAccountingEntry(credit);
883
884     if (!walletdb.TxnCommit())
885         throw JSONRPCError(-20, "database error");
886
887     return true;
888 }
889
890
891 Value sendfrom(const Array& params, bool fHelp)
892 {
893     if (pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
894         throw runtime_error(
895             "sendfrom <fromaccount> <toppcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
896             "<amount> is a real and is rounded to the nearest 0.000001\n"
897             "requires wallet passphrase to be set with walletpassphrase first");
898     if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
899         throw runtime_error(
900             "sendfrom <fromaccount> <toppcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
901             "<amount> is a real and is rounded to the nearest 0.000001");
902
903     string strAccount = AccountFromValue(params[0]);
904     CBitcoinAddress address(params[1].get_str());
905     if (!address.IsValid())
906         throw JSONRPCError(-5, "Invalid ppcoin address");
907     int64 nAmount = AmountFromValue(params[2]);
908     if (nAmount < MIN_TXOUT_AMOUNT)
909         throw JSONRPCError(-101, "Send amount too small");
910     int nMinDepth = 1;
911     if (params.size() > 3)
912         nMinDepth = params[3].get_int();
913
914     CWalletTx wtx;
915     wtx.strFromAccount = strAccount;
916     if (params.size() > 4 && params[4].type() != null_type && !params[4].get_str().empty())
917         wtx.mapValue["comment"] = params[4].get_str();
918     if (params.size() > 5 && params[5].type() != null_type && !params[5].get_str().empty())
919         wtx.mapValue["to"]      = params[5].get_str();
920
921     if (pwalletMain->IsLocked())
922         throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
923
924     // Check funds
925     int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
926     if (nAmount > nBalance)
927         throw JSONRPCError(-6, "Account has insufficient funds");
928
929     // Send
930     string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
931     if (strError != "")
932         throw JSONRPCError(-4, strError);
933
934     return wtx.GetHash().GetHex();
935 }
936
937
938 Value sendmany(const Array& params, bool fHelp)
939 {
940     if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
941         throw runtime_error(
942             "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
943             "amounts are double-precision floating point numbers\n"
944             "requires wallet passphrase to be set with walletpassphrase first");
945     if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
946         throw runtime_error(
947             "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
948             "amounts are double-precision floating point numbers");
949
950     string strAccount = AccountFromValue(params[0]);
951     Object sendTo = params[1].get_obj();
952     int nMinDepth = 1;
953     if (params.size() > 2)
954         nMinDepth = params[2].get_int();
955
956     CWalletTx wtx;
957     wtx.strFromAccount = strAccount;
958     if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
959         wtx.mapValue["comment"] = params[3].get_str();
960
961     set<CBitcoinAddress> setAddress;
962     vector<pair<CScript, int64> > vecSend;
963
964     int64 totalAmount = 0;
965     BOOST_FOREACH(const Pair& s, sendTo)
966     {
967         CBitcoinAddress address(s.name_);
968         if (!address.IsValid())
969             throw JSONRPCError(-5, string("Invalid ppcoin address:")+s.name_);
970
971         if (setAddress.count(address))
972             throw JSONRPCError(-8, string("Invalid parameter, duplicated address: ")+s.name_);
973         setAddress.insert(address);
974
975         CScript scriptPubKey;
976         scriptPubKey.SetBitcoinAddress(address);
977         int64 nAmount = AmountFromValue(s.value_); 
978         if (nAmount < MIN_TXOUT_AMOUNT)
979             throw JSONRPCError(-101, "Send amount too small");
980         totalAmount += nAmount;
981
982         vecSend.push_back(make_pair(scriptPubKey, nAmount));
983     }
984
985     if (pwalletMain->IsLocked())
986         throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
987     if (fWalletUnlockMintOnly)
988         throw JSONRPCError(-13, "Error: Wallet unlocked for block minting only.");
989
990     // Check funds
991     int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
992     if (totalAmount > nBalance)
993         throw JSONRPCError(-6, "Account has insufficient funds");
994
995     // Send
996     CReserveKey keyChange(pwalletMain);
997     int64 nFeeRequired = 0;
998     bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired);
999     if (!fCreated)
1000     {
1001         if (totalAmount + nFeeRequired > pwalletMain->GetBalance())
1002             throw JSONRPCError(-6, "Insufficient funds");
1003         throw JSONRPCError(-4, "Transaction creation failed");
1004     }
1005     if (!pwalletMain->CommitTransaction(wtx, keyChange))
1006         throw JSONRPCError(-4, "Transaction commit failed");
1007
1008     return wtx.GetHash().GetHex();
1009 }
1010
1011 Value addmultisigaddress(const Array& params, bool fHelp)
1012 {
1013     if (fHelp || params.size() < 2 || params.size() > 3)
1014     {
1015         string msg = "addmultisigaddress <nrequired> <'[\"key\",\"key\"]'> [account]\n"
1016             "Add a nrequired-to-sign multisignature address to the wallet\"\n"
1017             "each key is a bitcoin address or hex-encoded public key\n"
1018             "If [account] is specified, assign address to [account].";
1019         throw runtime_error(msg);
1020     }
1021
1022     int nRequired = params[0].get_int();
1023     const Array& keys = params[1].get_array();
1024     string strAccount;
1025     if (params.size() > 2)
1026         strAccount = AccountFromValue(params[2]);
1027
1028     // Gather public keys
1029     if (nRequired < 1)
1030         throw runtime_error("a multisignature address must require at least one key to redeem");
1031     if ((int)keys.size() < nRequired)
1032         throw runtime_error(
1033             strprintf("not enough keys supplied "
1034                       "(got %d keys, but need at least %d to redeem)", keys.size(), nRequired));
1035     std::vector<CKey> pubkeys;
1036     pubkeys.resize(keys.size());
1037     for (unsigned int i = 0; i < keys.size(); i++)
1038     {
1039         const std::string& ks = keys[i].get_str();
1040
1041         // Case 1: bitcoin address and we have full public key:
1042         CBitcoinAddress address(ks);
1043         if (address.IsValid())
1044         {
1045             if (address.IsScript())
1046                 throw runtime_error(
1047                     strprintf("%s is a pay-to-script address",ks.c_str()));
1048             std::vector<unsigned char> vchPubKey;
1049             if (!pwalletMain->GetPubKey(address, vchPubKey))
1050                 throw runtime_error(
1051                     strprintf("no full public key for address %s",ks.c_str()));
1052             if (vchPubKey.empty() || !pubkeys[i].SetPubKey(vchPubKey))
1053                 throw runtime_error(" Invalid public key: "+ks);
1054         }
1055
1056         // Case 2: hex public key
1057         else if (IsHex(ks))
1058         {
1059             vector<unsigned char> vchPubKey = ParseHex(ks);
1060             if (vchPubKey.empty() || !pubkeys[i].SetPubKey(vchPubKey))
1061                 throw runtime_error(" Invalid public key: "+ks);
1062         }
1063         else
1064         {
1065             throw runtime_error(" Invalid public key: "+ks);
1066         }
1067     }
1068
1069     // Construct using pay-to-script-hash:
1070     CScript inner;
1071     inner.SetMultisig(nRequired, pubkeys);
1072
1073     uint160 scriptHash = Hash160(inner);
1074     CScript scriptPubKey;
1075     scriptPubKey.SetPayToScriptHash(inner);
1076     pwalletMain->AddCScript(inner);
1077     CBitcoinAddress address;
1078     address.SetScriptHash160(scriptHash);
1079
1080     pwalletMain->SetAddressBookName(address, strAccount);
1081     return address.ToString();
1082 }
1083
1084
1085 struct tallyitem
1086 {
1087     int64 nAmount;
1088     int nConf;
1089     tallyitem()
1090     {
1091         nAmount = 0;
1092         nConf = std::numeric_limits<int>::max();
1093     }
1094 };
1095
1096 Value ListReceived(const Array& params, bool fByAccounts)
1097 {
1098     // Minimum confirmations
1099     int nMinDepth = 1;
1100     if (params.size() > 0)
1101         nMinDepth = params[0].get_int();
1102
1103     // Whether to include empty accounts
1104     bool fIncludeEmpty = false;
1105     if (params.size() > 1)
1106         fIncludeEmpty = params[1].get_bool();
1107
1108     // Tally
1109     map<CBitcoinAddress, tallyitem> mapTally;
1110     for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1111     {
1112         const CWalletTx& wtx = (*it).second;
1113
1114         if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
1115             continue;
1116
1117         int nDepth = wtx.GetDepthInMainChain();
1118         if (nDepth < nMinDepth)
1119             continue;
1120
1121         BOOST_FOREACH(const CTxOut& txout, wtx.vout)
1122         {
1123             CBitcoinAddress address;
1124             if (!ExtractAddress(txout.scriptPubKey, address) || !pwalletMain->HaveKey(address) || !address.IsValid())
1125                 continue;
1126
1127             tallyitem& item = mapTally[address];
1128             item.nAmount += txout.nValue;
1129             item.nConf = min(item.nConf, nDepth);
1130         }
1131     }
1132
1133     // Reply
1134     Array ret;
1135     map<string, tallyitem> mapAccountTally;
1136     BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
1137     {
1138         const CBitcoinAddress& address = item.first;
1139         const string& strAccount = item.second;
1140         map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
1141         if (it == mapTally.end() && !fIncludeEmpty)
1142             continue;
1143
1144         int64 nAmount = 0;
1145         int nConf = std::numeric_limits<int>::max();
1146         if (it != mapTally.end())
1147         {
1148             nAmount = (*it).second.nAmount;
1149             nConf = (*it).second.nConf;
1150         }
1151
1152         if (fByAccounts)
1153         {
1154             tallyitem& item = mapAccountTally[strAccount];
1155             item.nAmount += nAmount;
1156             item.nConf = min(item.nConf, nConf);
1157         }
1158         else
1159         {
1160             Object obj;
1161             obj.push_back(Pair("address",       address.ToString()));
1162             obj.push_back(Pair("account",       strAccount));
1163             obj.push_back(Pair("amount",        ValueFromAmount(nAmount)));
1164             obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
1165             ret.push_back(obj);
1166         }
1167     }
1168
1169     if (fByAccounts)
1170     {
1171         for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
1172         {
1173             int64 nAmount = (*it).second.nAmount;
1174             int nConf = (*it).second.nConf;
1175             Object obj;
1176             obj.push_back(Pair("account",       (*it).first));
1177             obj.push_back(Pair("amount",        ValueFromAmount(nAmount)));
1178             obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
1179             ret.push_back(obj);
1180         }
1181     }
1182
1183     return ret;
1184 }
1185
1186 Value listreceivedbyaddress(const Array& params, bool fHelp)
1187 {
1188     if (fHelp || params.size() > 2)
1189         throw runtime_error(
1190             "listreceivedbyaddress [minconf=1] [includeempty=false]\n"
1191             "[minconf] is the minimum number of confirmations before payments are included.\n"
1192             "[includeempty] whether to include addresses that haven't received any payments.\n"
1193             "Returns an array of objects containing:\n"
1194             "  \"address\" : receiving address\n"
1195             "  \"account\" : the account of the receiving address\n"
1196             "  \"amount\" : total amount received by the address\n"
1197             "  \"confirmations\" : number of confirmations of the most recent transaction included");
1198
1199     return ListReceived(params, false);
1200 }
1201
1202 Value listreceivedbyaccount(const Array& params, bool fHelp)
1203 {
1204     if (fHelp || params.size() > 2)
1205         throw runtime_error(
1206             "listreceivedbyaccount [minconf=1] [includeempty=false]\n"
1207             "[minconf] is the minimum number of confirmations before payments are included.\n"
1208             "[includeempty] whether to include accounts that haven't received any payments.\n"
1209             "Returns an array of objects containing:\n"
1210             "  \"account\" : the account of the receiving addresses\n"
1211             "  \"amount\" : total amount received by addresses with this account\n"
1212             "  \"confirmations\" : number of confirmations of the most recent transaction included");
1213
1214     return ListReceived(params, true);
1215 }
1216
1217 void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret)
1218 {
1219     int64 nGeneratedImmature, nGeneratedMature, nFee;
1220     string strSentAccount;
1221     list<pair<CBitcoinAddress, int64> > listReceived;
1222     list<pair<CBitcoinAddress, int64> > listSent;
1223
1224     wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1225
1226     bool fAllAccounts = (strAccount == string("*"));
1227
1228     // Generated blocks assigned to account ""
1229     if ((nGeneratedMature+nGeneratedImmature) != 0 && (fAllAccounts || strAccount == ""))
1230     {
1231         Object entry;
1232         entry.push_back(Pair("account", string("")));
1233         if (nGeneratedImmature)
1234         {
1235             entry.push_back(Pair("category", wtx.GetDepthInMainChain() ? "immature" : "orphan"));
1236             entry.push_back(Pair("amount", ValueFromAmount(nGeneratedImmature)));
1237         }
1238         else
1239         {
1240             entry.push_back(Pair("category", "generate"));
1241             entry.push_back(Pair("amount", ValueFromAmount(nGeneratedMature)));
1242         }
1243         if (fLong)
1244             WalletTxToJSON(wtx, entry);
1245         ret.push_back(entry);
1246     }
1247
1248     // Sent
1249     if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
1250     {
1251         BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1252         {
1253             Object entry;
1254             entry.push_back(Pair("account", strSentAccount));
1255             entry.push_back(Pair("address", s.first.ToString()));
1256             entry.push_back(Pair("category", "send"));
1257             entry.push_back(Pair("amount", ValueFromAmount(-s.second)));
1258             entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
1259             if (fLong)
1260                 WalletTxToJSON(wtx, entry);
1261             ret.push_back(entry);
1262         }
1263     }
1264
1265     // Received
1266     if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
1267     {
1268         BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1269         {
1270             string account;
1271             if (pwalletMain->mapAddressBook.count(r.first))
1272                 account = pwalletMain->mapAddressBook[r.first];
1273             if (fAllAccounts || (account == strAccount))
1274             {
1275                 Object entry;
1276                 entry.push_back(Pair("account", account));
1277                 entry.push_back(Pair("address", r.first.ToString()));
1278                 entry.push_back(Pair("category", "receive"));
1279                 entry.push_back(Pair("amount", ValueFromAmount(r.second)));
1280                 if (fLong)
1281                     WalletTxToJSON(wtx, entry);
1282                 ret.push_back(entry);
1283             }
1284         }
1285     }
1286 }
1287
1288 void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret)
1289 {
1290     bool fAllAccounts = (strAccount == string("*"));
1291
1292     if (fAllAccounts || acentry.strAccount == strAccount)
1293     {
1294         Object entry;
1295         entry.push_back(Pair("account", acentry.strAccount));
1296         entry.push_back(Pair("category", "move"));
1297         entry.push_back(Pair("time", (boost::int64_t)acentry.nTime));
1298         entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
1299         entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
1300         entry.push_back(Pair("comment", acentry.strComment));
1301         ret.push_back(entry);
1302     }
1303 }
1304
1305 Value listtransactions(const Array& params, bool fHelp)
1306 {
1307     if (fHelp || params.size() > 3)
1308         throw runtime_error(
1309             "listtransactions [account] [count=10] [from=0]\n"
1310             "Returns up to [count] most recent transactions skipping the first [from] transactions for account [account].");
1311
1312     string strAccount = "*";
1313     if (params.size() > 0)
1314         strAccount = params[0].get_str();
1315     int nCount = 10;
1316     if (params.size() > 1)
1317         nCount = params[1].get_int();
1318     int nFrom = 0;
1319     if (params.size() > 2)
1320         nFrom = params[2].get_int();
1321
1322     if (nCount < 0)
1323         throw JSONRPCError(-8, "Negative count");
1324     if (nFrom < 0)
1325         throw JSONRPCError(-8, "Negative from");
1326
1327     Array ret;
1328     CWalletDB walletdb(pwalletMain->strWalletFile);
1329
1330     // First: get all CWalletTx and CAccountingEntry into a sorted-by-time multimap.
1331     typedef pair<CWalletTx*, CAccountingEntry*> TxPair;
1332     typedef multimap<int64, TxPair > TxItems;
1333     TxItems txByTime;
1334
1335     // Note: maintaining indices in the database of (account,time) --> txid and (account, time) --> acentry
1336     // would make this much faster for applications that do this a lot.
1337     for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1338     {
1339         CWalletTx* wtx = &((*it).second);
1340         txByTime.insert(make_pair(wtx->GetTxTime(), TxPair(wtx, (CAccountingEntry*)0)));
1341     }
1342     list<CAccountingEntry> acentries;
1343     walletdb.ListAccountCreditDebit(strAccount, acentries);
1344     BOOST_FOREACH(CAccountingEntry& entry, acentries)
1345     {
1346         txByTime.insert(make_pair(entry.nTime, TxPair((CWalletTx*)0, &entry)));
1347     }
1348
1349     // iterate backwards until we have nCount items to return:
1350     for (TxItems::reverse_iterator it = txByTime.rbegin(); it != txByTime.rend(); ++it)
1351     {
1352         CWalletTx *const pwtx = (*it).second.first;
1353         if (pwtx != 0)
1354             ListTransactions(*pwtx, strAccount, 0, true, ret);
1355         CAccountingEntry *const pacentry = (*it).second.second;
1356         if (pacentry != 0)
1357             AcentryToJSON(*pacentry, strAccount, ret);
1358
1359         if (ret.size() >= (nCount+nFrom)) break;
1360     }
1361     // ret is newest to oldest
1362     
1363     if (nFrom > (int)ret.size())
1364         nFrom = ret.size();
1365     if ((nFrom + nCount) > (int)ret.size())
1366         nCount = ret.size() - nFrom;
1367     Array::iterator first = ret.begin();
1368     std::advance(first, nFrom);
1369     Array::iterator last = ret.begin();
1370     std::advance(last, nFrom+nCount);
1371
1372     if (last != ret.end()) ret.erase(last, ret.end());
1373     if (first != ret.begin()) ret.erase(ret.begin(), first);
1374
1375     std::reverse(ret.begin(), ret.end()); // Return oldest to newest
1376
1377     return ret;
1378 }
1379
1380 Value listaccounts(const Array& params, bool fHelp)
1381 {
1382     if (fHelp || params.size() > 1)
1383         throw runtime_error(
1384             "listaccounts [minconf=1]\n"
1385             "Returns Object that has account names as keys, account balances as values.");
1386
1387     int nMinDepth = 1;
1388     if (params.size() > 0)
1389         nMinDepth = params[0].get_int();
1390
1391     map<string, int64> mapAccountBalances;
1392     BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& entry, pwalletMain->mapAddressBook) {
1393         if (pwalletMain->HaveKey(entry.first)) // This address belongs to me
1394             mapAccountBalances[entry.second] = 0;
1395     }
1396
1397     for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1398     {
1399         const CWalletTx& wtx = (*it).second;
1400         int64 nGeneratedImmature, nGeneratedMature, nFee;
1401         string strSentAccount;
1402         list<pair<CBitcoinAddress, int64> > listReceived;
1403         list<pair<CBitcoinAddress, int64> > listSent;
1404         wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1405         mapAccountBalances[strSentAccount] -= nFee;
1406         BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1407             mapAccountBalances[strSentAccount] -= s.second;
1408         if (wtx.GetDepthInMainChain() >= nMinDepth)
1409         {
1410             mapAccountBalances[""] += nGeneratedMature;
1411             BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1412                 if (pwalletMain->mapAddressBook.count(r.first))
1413                     mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second;
1414                 else
1415                     mapAccountBalances[""] += r.second;
1416         }
1417     }
1418
1419     list<CAccountingEntry> acentries;
1420     CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
1421     BOOST_FOREACH(const CAccountingEntry& entry, acentries)
1422         mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
1423
1424     Object ret;
1425     BOOST_FOREACH(const PAIRTYPE(string, int64)& accountBalance, mapAccountBalances) {
1426         ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
1427     }
1428     return ret;
1429 }
1430
1431 Value listsinceblock(const Array& params, bool fHelp)
1432 {
1433     if (fHelp)
1434         throw runtime_error(
1435             "listsinceblock [blockhash] [target-confirmations]\n"
1436             "Get all transactions in blocks since block [blockhash], or all transactions if omitted");
1437
1438     CBlockIndex *pindex = NULL;
1439     int target_confirms = 1;
1440
1441     if (params.size() > 0)
1442     {
1443         uint256 blockId = 0;
1444
1445         blockId.SetHex(params[0].get_str());
1446         pindex = CBlockLocator(blockId).GetBlockIndex();
1447     }
1448
1449     if (params.size() > 1)
1450     {
1451         target_confirms = params[1].get_int();
1452
1453         if (target_confirms < 1)
1454             throw JSONRPCError(-8, "Invalid parameter");
1455     }
1456
1457     int depth = pindex ? (1 + nBestHeight - pindex->nHeight) : -1;
1458
1459     Array transactions;
1460
1461     for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++)
1462     {
1463         CWalletTx tx = (*it).second;
1464
1465         if (depth == -1 || tx.GetDepthInMainChain() < depth)
1466             ListTransactions(tx, "*", 0, true, transactions);
1467     }
1468
1469     uint256 lastblock;
1470
1471     if (target_confirms == 1)
1472     {
1473         lastblock = hashBestChain;
1474     }
1475     else
1476     {
1477         int target_height = pindexBest->nHeight + 1 - target_confirms;
1478
1479         CBlockIndex *block;
1480         for (block = pindexBest;
1481              block && block->nHeight > target_height;
1482              block = block->pprev)  { }
1483
1484         lastblock = block ? block->GetBlockHash() : 0;
1485     }
1486
1487     Object ret;
1488     ret.push_back(Pair("transactions", transactions));
1489     ret.push_back(Pair("lastblock", lastblock.GetHex()));
1490
1491     return ret;
1492 }
1493
1494 Value gettransaction(const Array& params, bool fHelp)
1495 {
1496     if (fHelp || params.size() != 1)
1497         throw runtime_error(
1498             "gettransaction <txid>\n"
1499             "Get detailed information about <txid>");
1500
1501     uint256 hash;
1502     hash.SetHex(params[0].get_str());
1503
1504     Object entry;
1505
1506     if (!pwalletMain->mapWallet.count(hash))
1507         throw JSONRPCError(-5, "Invalid or non-wallet transaction id");
1508     const CWalletTx& wtx = pwalletMain->mapWallet[hash];
1509
1510     int64 nCredit = wtx.GetCredit();
1511     int64 nDebit = wtx.GetDebit();
1512     int64 nNet = nCredit - nDebit;
1513     int64 nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0);
1514
1515     entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
1516     if (wtx.IsFromMe())
1517         entry.push_back(Pair("fee", ValueFromAmount(nFee)));
1518
1519     WalletTxToJSON(pwalletMain->mapWallet[hash], entry);
1520
1521     Array details;
1522     ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details);
1523     entry.push_back(Pair("details", details));
1524
1525     return entry;
1526 }
1527
1528
1529 Value backupwallet(const Array& params, bool fHelp)
1530 {
1531     if (fHelp || params.size() != 1)
1532         throw runtime_error(
1533             "backupwallet <destination>\n"
1534             "Safely copies wallet.dat to destination, which can be a directory or a path with filename.");
1535
1536     string strDest = params[0].get_str();
1537     BackupWallet(*pwalletMain, strDest);
1538
1539     return Value::null;
1540 }
1541
1542
1543 Value keypoolrefill(const Array& params, bool fHelp)
1544 {
1545     if (pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1546         throw runtime_error(
1547             "keypoolrefill\n"
1548             "Fills the keypool, requires wallet passphrase to be set.");
1549     if (!pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1550         throw runtime_error(
1551             "keypoolrefill\n"
1552             "Fills the keypool.");
1553
1554     if (pwalletMain->IsLocked())
1555         throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
1556
1557     pwalletMain->TopUpKeyPool();
1558
1559     if (pwalletMain->GetKeyPoolSize() < GetArg("-keypool", 100))
1560         throw JSONRPCError(-4, "Error refreshing keypool.");
1561
1562     return Value::null;
1563 }
1564
1565
1566 void ThreadTopUpKeyPool(void* parg)
1567 {
1568     pwalletMain->TopUpKeyPool();
1569 }
1570
1571 void ThreadCleanWalletPassphrase(void* parg)
1572 {
1573     int64 nMyWakeTime = GetTimeMillis() + *((int64*)parg) * 1000;
1574
1575     ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1576
1577     if (nWalletUnlockTime == 0)
1578     {
1579         nWalletUnlockTime = nMyWakeTime;
1580
1581         do
1582         {
1583             if (nWalletUnlockTime==0)
1584                 break;
1585             int64 nToSleep = nWalletUnlockTime - GetTimeMillis();
1586             if (nToSleep <= 0)
1587                 break;
1588
1589             LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1590             Sleep(nToSleep);
1591             ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1592
1593         } while(1);
1594
1595         if (nWalletUnlockTime)
1596         {
1597             nWalletUnlockTime = 0;
1598             pwalletMain->Lock();
1599         }
1600     }
1601     else
1602     {
1603         if (nWalletUnlockTime < nMyWakeTime)
1604             nWalletUnlockTime = nMyWakeTime;
1605     }
1606
1607     LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1608
1609     delete (int64*)parg;
1610 }
1611
1612 Value walletpassphrase(const Array& params, bool fHelp)
1613 {
1614     if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 3))
1615         throw runtime_error(
1616             "walletpassphrase <passphrase> <timeout> [mintonly]\n"
1617             "Stores the wallet decryption key in memory for <timeout> seconds.\n"
1618             "mintonly is optional true/false allowing only block minting.");
1619     if (fHelp)
1620         return true;
1621     if (!pwalletMain->IsCrypted())
1622         throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
1623
1624     if (!pwalletMain->IsLocked())
1625         throw JSONRPCError(-17, "Error: Wallet is already unlocked, use walletlock first if need to change unlock settings.");
1626
1627     // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
1628     SecureString strWalletPass;
1629     strWalletPass.reserve(100);
1630     // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1631     // Alternately, find a way to make params[0] mlock()'d to begin with.
1632     strWalletPass = params[0].get_str().c_str();
1633
1634     if (strWalletPass.length() > 0)
1635     {
1636         if (!pwalletMain->Unlock(strWalletPass))
1637             throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1638     }
1639     else
1640         throw runtime_error(
1641             "walletpassphrase <passphrase> <timeout>\n"
1642             "Stores the wallet decryption key in memory for <timeout> seconds.");
1643
1644     CreateThread(ThreadTopUpKeyPool, NULL);
1645     int64* pnSleepTime = new int64(params[1].get_int64());
1646     CreateThread(ThreadCleanWalletPassphrase, pnSleepTime);
1647
1648     // ppcoin: if user OS account compromised prevent trivial sendmoney commands
1649     if (params.size() > 2)
1650         fWalletUnlockMintOnly = params[2].get_bool();
1651     else
1652         fWalletUnlockMintOnly = false;
1653
1654     return Value::null;
1655 }
1656
1657
1658 Value walletpassphrasechange(const Array& params, bool fHelp)
1659 {
1660     if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1661         throw runtime_error(
1662             "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1663             "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1664     if (fHelp)
1665         return true;
1666     if (!pwalletMain->IsCrypted())
1667         throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
1668
1669     // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
1670     // Alternately, find a way to make params[0] mlock()'d to begin with.
1671     SecureString strOldWalletPass;
1672     strOldWalletPass.reserve(100);
1673     strOldWalletPass = params[0].get_str().c_str();
1674
1675     SecureString strNewWalletPass;
1676     strNewWalletPass.reserve(100);
1677     strNewWalletPass = params[1].get_str().c_str();
1678
1679     if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
1680         throw runtime_error(
1681             "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1682             "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1683
1684     if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
1685         throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1686
1687     return Value::null;
1688 }
1689
1690
1691 Value walletlock(const Array& params, bool fHelp)
1692 {
1693     if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
1694         throw runtime_error(
1695             "walletlock\n"
1696             "Removes the wallet encryption key from memory, locking the wallet.\n"
1697             "After calling this method, you will need to call walletpassphrase again\n"
1698             "before being able to call any methods which require the wallet to be unlocked.");
1699     if (fHelp)
1700         return true;
1701     if (!pwalletMain->IsCrypted())
1702         throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletlock was called.");
1703
1704     {
1705         LOCK(cs_nWalletUnlockTime);
1706         pwalletMain->Lock();
1707         nWalletUnlockTime = 0;
1708     }
1709
1710     return Value::null;
1711 }
1712
1713
1714 Value encryptwallet(const Array& params, bool fHelp)
1715 {
1716     if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
1717         throw runtime_error(
1718             "encryptwallet <passphrase>\n"
1719             "Encrypts the wallet with <passphrase>.");
1720     if (fHelp)
1721         return true;
1722     if (pwalletMain->IsCrypted())
1723         throw JSONRPCError(-15, "Error: running with an encrypted wallet, but encryptwallet was called.");
1724
1725     // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1726     // Alternately, find a way to make params[0] mlock()'d to begin with.
1727     SecureString strWalletPass;
1728     strWalletPass.reserve(100);
1729     strWalletPass = params[0].get_str().c_str();
1730
1731     if (strWalletPass.length() < 1)
1732         throw runtime_error(
1733             "encryptwallet <passphrase>\n"
1734             "Encrypts the wallet with <passphrase>.");
1735
1736     if (!pwalletMain->EncryptWallet(strWalletPass))
1737         throw JSONRPCError(-16, "Error: Failed to encrypt the wallet.");
1738
1739     // BDB seems to have a bad habit of writing old data into
1740     // slack space in .dat files; that is bad if the old data is
1741     // unencrypted private keys.  So:
1742     StartShutdown();
1743     return "wallet encrypted; ppcoin server stopping, restart to run with encrypted wallet";
1744 }
1745
1746
1747 Value validateaddress(const Array& params, bool fHelp)
1748 {
1749     if (fHelp || params.size() != 1)
1750         throw runtime_error(
1751             "validateaddress <ppcoinaddress>\n"
1752             "Return information about <ppcoinaddress>.");
1753
1754     CBitcoinAddress address(params[0].get_str());
1755     bool isValid = address.IsValid();
1756
1757     Object ret;
1758     ret.push_back(Pair("isvalid", isValid));
1759     if (isValid)
1760     {
1761         // Call Hash160ToAddress() so we always return current ADDRESSVERSION
1762         // version of the address:
1763         string currentAddress = address.ToString();
1764         ret.push_back(Pair("address", currentAddress));
1765         if (pwalletMain->HaveKey(address))
1766         {
1767             ret.push_back(Pair("ismine", true));
1768             std::vector<unsigned char> vchPubKey;
1769             pwalletMain->GetPubKey(address, vchPubKey);
1770             ret.push_back(Pair("pubkey", HexStr(vchPubKey)));
1771             CKey key;
1772             key.SetPubKey(vchPubKey);
1773             ret.push_back(Pair("iscompressed", key.IsCompressed()));
1774         }
1775         else if (pwalletMain->HaveCScript(address.GetHash160()))
1776         {
1777             ret.push_back(Pair("isscript", true));
1778             CScript subscript;
1779             pwalletMain->GetCScript(address.GetHash160(), subscript);
1780             ret.push_back(Pair("ismine", ::IsMine(*pwalletMain, subscript)));
1781             std::vector<CBitcoinAddress> addresses;
1782             txnouttype whichType;
1783             int nRequired;
1784             ExtractAddresses(subscript, whichType, addresses, nRequired);
1785             ret.push_back(Pair("script", GetTxnOutputType(whichType)));
1786             Array a;
1787             BOOST_FOREACH(const CBitcoinAddress& addr, addresses)
1788                 a.push_back(addr.ToString());
1789             ret.push_back(Pair("addresses", a));
1790             if (whichType == TX_MULTISIG)
1791                 ret.push_back(Pair("sigsrequired", nRequired));
1792         }
1793         else
1794             ret.push_back(Pair("ismine", false));
1795         if (pwalletMain->mapAddressBook.count(address))
1796             ret.push_back(Pair("account", pwalletMain->mapAddressBook[address]));
1797     }
1798     return ret;
1799 }
1800
1801 Value getwork(const Array& params, bool fHelp)
1802 {
1803     if (fHelp || params.size() > 1)
1804         throw runtime_error(
1805             "getwork [data]\n"
1806             "If [data] is not specified, returns formatted hash data to work on:\n"
1807             "  \"midstate\" : precomputed hash state after hashing the first half of the data (DEPRECATED)\n" // deprecated
1808             "  \"data\" : block data\n"
1809             "  \"hash1\" : formatted hash buffer for second hash (DEPRECATED)\n" // deprecated
1810             "  \"target\" : little endian hash target\n"
1811             "If [data] is specified, tries to solve the block and returns true if it was successful.");
1812
1813     if (vNodes.empty())
1814         throw JSONRPCError(-9, "PPCoin is not connected!");
1815
1816     if (IsInitialBlockDownload())
1817         throw JSONRPCError(-10, "PPCoin is downloading blocks...");
1818
1819     typedef map<uint256, pair<CBlock*, CScript> > mapNewBlock_t;
1820     static mapNewBlock_t mapNewBlock;
1821     static vector<CBlock*> vNewBlock;
1822     static CReserveKey reservekey(pwalletMain);
1823
1824     if (params.size() == 0)
1825     {
1826         // Update block
1827         static unsigned int nTransactionsUpdatedLast;
1828         static CBlockIndex* pindexPrev;
1829         static int64 nStart;
1830         static CBlock* pblock;
1831         if (pindexPrev != pindexBest ||
1832             (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60))
1833         {
1834             if (pindexPrev != pindexBest)
1835             {
1836                 // Deallocate old blocks since they're obsolete now
1837                 mapNewBlock.clear();
1838                 BOOST_FOREACH(CBlock* pblock, vNewBlock)
1839                     delete pblock;
1840                 vNewBlock.clear();
1841             }
1842             nTransactionsUpdatedLast = nTransactionsUpdated;
1843             pindexPrev = pindexBest;
1844             nStart = GetTime();
1845
1846             // Create new block
1847             pblock = CreateNewBlock(pwalletMain);
1848             if (!pblock)
1849                 throw JSONRPCError(-7, "Out of memory");
1850             vNewBlock.push_back(pblock);
1851         }
1852
1853         // Update nTime
1854         pblock->UpdateTime(pindexPrev);
1855         pblock->nNonce = 0;
1856
1857         // Update nExtraNonce
1858         static unsigned int nExtraNonce = 0;
1859         IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
1860
1861         // Save
1862         mapNewBlock[pblock->hashMerkleRoot] = make_pair(pblock, pblock->vtx[0].vin[0].scriptSig);
1863
1864         // Prebuild hash buffers
1865         char pmidstate[32];
1866         char pdata[128];
1867         char phash1[64];
1868         FormatHashBuffers(pblock, pmidstate, pdata, phash1);
1869
1870         uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
1871
1872         Object result;
1873         result.push_back(Pair("midstate", HexStr(BEGIN(pmidstate), END(pmidstate)))); // deprecated
1874         result.push_back(Pair("data",     HexStr(BEGIN(pdata), END(pdata))));
1875         result.push_back(Pair("hash1",    HexStr(BEGIN(phash1), END(phash1)))); // deprecated
1876         result.push_back(Pair("target",   HexStr(BEGIN(hashTarget), END(hashTarget))));
1877         return result;
1878     }
1879     else
1880     {
1881         // Parse parameters
1882         vector<unsigned char> vchData = ParseHex(params[0].get_str());
1883         if (vchData.size() != 128)
1884             throw JSONRPCError(-8, "Invalid parameter");
1885         CBlock* pdata = (CBlock*)&vchData[0];
1886
1887         // Byte reverse
1888         for (int i = 0; i < 128/4; i++)
1889             ((unsigned int*)pdata)[i] = ByteReverse(((unsigned int*)pdata)[i]);
1890
1891         // Get saved block
1892         if (!mapNewBlock.count(pdata->hashMerkleRoot))
1893             return false;
1894         CBlock* pblock = mapNewBlock[pdata->hashMerkleRoot].first;
1895
1896         pblock->nTime = pdata->nTime;
1897         pblock->nNonce = pdata->nNonce;
1898         pblock->vtx[0].vin[0].scriptSig = mapNewBlock[pdata->hashMerkleRoot].second;
1899         pblock->hashMerkleRoot = pblock->BuildMerkleTree();
1900         if (!pblock->SignBlock(*pwalletMain))
1901             throw JSONRPCError(-100, "Unable to sign block, wallet locked?");
1902
1903         return CheckWork(pblock, *pwalletMain, reservekey);
1904     }
1905 }
1906
1907
1908 Value getmemorypool(const Array& params, bool fHelp)
1909 {
1910     if (fHelp || params.size() > 1)
1911         throw runtime_error(
1912             "getmemorypool [data]\n"
1913             "If [data] is not specified, returns data needed to construct a block to work on:\n"
1914             "  \"version\" : block version\n"
1915             "  \"previousblockhash\" : hash of current highest block\n"
1916             "  \"transactions\" : contents of non-coinbase transactions that should be included in the next block\n"
1917             "  \"coinbasevalue\" : maximum allowable input to coinbase transaction, including the generation award and transaction fees\n"
1918             "  \"coinbaseflags\" : data that should be included in coinbase so support for new features can be judged\n"
1919             "  \"time\" : timestamp appropriate for next block\n"
1920             "  \"mintime\" : minimum timestamp appropriate for next block\n"
1921             "  \"curtime\" : current timestamp\n"
1922             "  \"bits\" : compressed target of next block\n"
1923             "If [data] is specified, tries to solve the block and returns true if it was successful.");
1924
1925     if (params.size() == 0)
1926     {
1927         if (vNodes.empty())
1928             throw JSONRPCError(-9, "PPCoin is not connected!");
1929
1930         if (IsInitialBlockDownload())
1931             throw JSONRPCError(-10, "PPCoin is downloading blocks...");
1932
1933         static CReserveKey reservekey(pwalletMain);
1934
1935         // Update block
1936         static unsigned int nTransactionsUpdatedLast;
1937         static CBlockIndex* pindexPrev;
1938         static int64 nStart;
1939         static CBlock* pblock;
1940         if (pindexPrev != pindexBest ||
1941             (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 5))
1942         {
1943             nTransactionsUpdatedLast = nTransactionsUpdated;
1944             pindexPrev = pindexBest;
1945             nStart = GetTime();
1946
1947             // Create new block
1948             if(pblock)
1949                 delete pblock;
1950             pblock = CreateNewBlock(pwalletMain);
1951             if (!pblock)
1952                 throw JSONRPCError(-7, "Out of memory");
1953         }
1954
1955         // Update nTime
1956         pblock->UpdateTime(pindexPrev);
1957         pblock->nNonce = 0;
1958
1959         Array transactions;
1960         BOOST_FOREACH(CTransaction tx, pblock->vtx) {
1961             if(tx.IsCoinBase() || tx.IsCoinStake())
1962                 continue;
1963
1964             CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
1965             ssTx << tx;
1966
1967             transactions.push_back(HexStr(ssTx.begin(), ssTx.end()));
1968         }
1969
1970         Object result;
1971         result.push_back(Pair("version", pblock->nVersion));
1972         result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex()));
1973         result.push_back(Pair("transactions", transactions));
1974         result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue));
1975         result.push_back(Pair("coinbaseflags", HexStr(COINBASE_FLAGS.begin(), COINBASE_FLAGS.end())));
1976         result.push_back(Pair("time", (int64_t)pblock->nTime));
1977         result.push_back(Pair("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1));
1978         result.push_back(Pair("curtime", (int64_t)GetAdjustedTime()));
1979         result.push_back(Pair("bits", HexBits(pblock->nBits)));
1980
1981         return result;
1982     }
1983     else
1984     {
1985         // Parse parameters
1986         CDataStream ssBlock(ParseHex(params[0].get_str()), SER_NETWORK, PROTOCOL_VERSION);
1987         CBlock pblock;
1988         ssBlock >> pblock;
1989
1990         return ProcessBlock(NULL, &pblock);
1991     }
1992 }
1993
1994 Value getblockhash(const Array& params, bool fHelp)
1995 {
1996     if (fHelp || params.size() != 1)
1997         throw runtime_error(
1998             "getblockhash <index>\n"
1999             "Returns hash of block in best-block-chain at <index>.");
2000
2001     int nHeight = params[0].get_int();
2002     if (nHeight < 0 || nHeight > nBestHeight)
2003         throw runtime_error("Block number out of range.");
2004
2005     CBlock block;
2006     CBlockIndex* pblockindex = mapBlockIndex[hashBestChain];
2007     while (pblockindex->nHeight > nHeight)
2008         pblockindex = pblockindex->pprev;
2009     return pblockindex->phashBlock->GetHex();
2010 }
2011
2012 Value getblock(const Array& params, bool fHelp)
2013 {
2014     if (fHelp || params.size() < 1 || params.size() > 2)
2015         throw runtime_error(
2016             "getblock <hash> [txinfo]\n"
2017             "txinfo optional to print more detailed tx info\n"
2018             "Returns details of a block with given block-hash.");
2019
2020     std::string strHash = params[0].get_str();
2021     uint256 hash(strHash);
2022
2023     if (mapBlockIndex.count(hash) == 0)
2024         throw JSONRPCError(-5, "Block not found");
2025
2026     CBlock block;
2027     CBlockIndex* pblockindex = mapBlockIndex[hash];
2028     block.ReadFromDisk(pblockindex, true);
2029
2030     return blockToJSON(block, pblockindex, params.size() > 1 ? params[1].get_bool() : false);
2031 }
2032
2033
2034 // ppcoin: get information of sync-checkpoint
2035 Value getcheckpoint(const Array& params, bool fHelp)
2036 {
2037     if (fHelp || params.size() != 0)
2038         throw runtime_error(
2039             "getcheckpoint\n"
2040             "Show info of synchronized checkpoint.\n");
2041
2042     Object result;
2043     CBlockIndex* pindexCheckpoint;
2044     
2045     result.push_back(Pair("synccheckpoint", Checkpoints::hashSyncCheckpoint.ToString().c_str()));
2046     pindexCheckpoint = mapBlockIndex[Checkpoints::hashSyncCheckpoint];        
2047     result.push_back(Pair("height", pindexCheckpoint->nHeight));
2048     result.push_back(Pair("timestamp", DateTimeStrFormat(pindexCheckpoint->GetBlockTime()).c_str()));
2049     if (mapArgs.count("-checkpointkey"))
2050         result.push_back(Pair("checkpointmaster", true));
2051
2052     return result;
2053 }
2054
2055
2056 // ppcoin: reserve balance from being staked for network protection
2057 Value reservebalance(const Array& params, bool fHelp)
2058 {
2059     if (fHelp || params.size() > 2)
2060         throw runtime_error(
2061             "reservebalance [<reserve> [amount]]\n"
2062             "<reserve> is true or false to turn balance reserve on or off.\n"
2063             "<amount> is a real and rounded to cent.\n"
2064             "Set reserve amount not participating in network protection.\n"
2065             "If no parameters provided current setting is printed.\n");
2066
2067     if (params.size() > 0)
2068     {
2069         bool fReserve = params[0].get_bool();
2070         if (fReserve)
2071         {
2072             if (params.size() == 1)
2073                 throw runtime_error("must provide amount to reserve balance.\n");
2074             int64 nAmount = AmountFromValue(params[1]);
2075             nAmount = (nAmount / CENT) * CENT;  // round to cent
2076             if (nAmount < 0)
2077                 throw runtime_error("amount cannot be negative.\n");
2078             mapArgs["-reservebalance"] = FormatMoney(nAmount).c_str();
2079         }
2080         else
2081         {
2082             if (params.size() > 1)
2083                 throw runtime_error("cannot specify amount to turn off reserve.\n");
2084             mapArgs["-reservebalance"] = "0";
2085         }
2086     }
2087
2088     Object result;
2089     int64 nReserveBalance = 0;
2090     if (mapArgs.count("-reservebalance") && !ParseMoney(mapArgs["-reservebalance"], nReserveBalance))
2091         throw runtime_error("invalid reserve balance amount\n");
2092     result.push_back(Pair("reserve", (nReserveBalance > 0)));
2093     result.push_back(Pair("amount", ValueFromAmount(nReserveBalance)));
2094     return result;
2095 }
2096
2097
2098 // ppcoin: check wallet integrity
2099 Value checkwallet(const Array& params, bool fHelp)
2100 {
2101     if (fHelp || params.size() > 0)
2102         throw runtime_error(
2103             "checkwallet\n"
2104             "Check wallet for integrity.\n");
2105
2106     int nMismatchSpent;
2107     int64 nBalanceInQuestion;
2108     if (!pwalletMain->CheckSpentCoins(nMismatchSpent, nBalanceInQuestion))
2109     {
2110         Object result;
2111         result.push_back(Pair("mismatched spent coins", nMismatchSpent));
2112         result.push_back(Pair("amount in question", ValueFromAmount(nBalanceInQuestion)));
2113         return result;
2114     }
2115     return Value::null;
2116 }
2117
2118
2119 // ppcoin: repair wallet
2120 Value repairwallet(const Array& params, bool fHelp)
2121 {
2122     if (fHelp || params.size() > 0)
2123         throw runtime_error(
2124             "repairwallet\n"
2125             "Repair wallet if checkwallet reports any problem.\n");
2126
2127     int nMismatchSpent;
2128     int64 nBalanceInQuestion;
2129     pwalletMain->FixSpentCoins(nMismatchSpent, nBalanceInQuestion);
2130     Object result;
2131     if (nMismatchSpent == 0)
2132     {
2133         result.push_back(Pair("wallet check passed", true));
2134     }
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;