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