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