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