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