e650eb08bd0aaadbe945c9195463014afce1b8e1
[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() < 5)
2162         throw runtime_error(
2163             "sendalert <message> <privatekey> <minver> <maxver> <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 client version\n"
2167             "<maxver> is the maximum applicable client version\n"
2168             "<id> is the alert id\n"
2169             "[cancelupto] cancels all alert id's up to this number\n"
2170             "Returns true or false.");    
2171
2172     CAlert alert;
2173     CKey key;
2174
2175     alert.strStatusBar = params[0].get_str();
2176     alert.nMinVer = params[2].get_int();
2177     alert.nMaxVer = params[3].get_int();
2178     alert.nID = params[4].get_int();
2179     if (params.size() > 5)
2180         alert.nCancel = params[5].get_int();
2181     alert.nVersion = PROTOCOL_VERSION;
2182     alert.nRelayUntil = GetAdjustedTime() + 365*24*60*60;
2183     alert.nExpiration = GetAdjustedTime() + 365*24*60*60;
2184     alert.nPriority = 1;
2185
2186     CDataStream sMsg(SER_NETWORK, PROTOCOL_VERSION);
2187     sMsg << (CUnsignedAlert)alert;
2188     alert.vchMsg = vector<unsigned char>(sMsg.begin(), sMsg.end());
2189     
2190     vector<unsigned char> vchPrivKey = ParseHex(params[1].get_str());
2191     key.SetPrivKey(CPrivKey(vchPrivKey.begin(), vchPrivKey.end())); // if key is not correct openssl may crash
2192     if (!key.Sign(Hash(alert.vchMsg.begin(), alert.vchMsg.end()), alert.vchSig))
2193         throw runtime_error(
2194             "Unable to sign alert, check private key?\n");  
2195     if(!alert.ProcessAlert()) 
2196         throw runtime_error(
2197             "Failed to process alert.\n");
2198     // Relay alert
2199     {
2200         LOCK(cs_vNodes);
2201         BOOST_FOREACH(CNode* pnode, vNodes)
2202             alert.RelayTo(pnode);
2203     }
2204
2205     Object result;
2206     result.push_back(Pair("strStatusBar", alert.strStatusBar));
2207     result.push_back(Pair("nVersion", alert.nVersion));
2208     result.push_back(Pair("nMinVer", alert.nMinVer));
2209     result.push_back(Pair("nMaxVer", alert.nMaxVer));
2210     result.push_back(Pair("nID", alert.nID));
2211     if (alert.nCancel > 0)
2212         result.push_back(Pair("nCancel", alert.nCancel));
2213     return result;
2214 }
2215
2216
2217
2218 //
2219 // Call Table
2220 //
2221
2222
2223 static const CRPCCommand vRPCCommands[] =
2224 { //  name                      function                 safe mode?
2225   //  ------------------------  -----------------------  ----------
2226     { "help",                   &help,                   true },
2227     { "stop",                   &stop,                   true },
2228     { "getblockcount",          &getblockcount,          true },
2229     { "getblocknumber",         &getblocknumber,         true },
2230     { "getconnectioncount",     &getconnectioncount,     true },
2231     { "getdifficulty",          &getdifficulty,          true },
2232     { "getgenerate",            &getgenerate,            true },
2233     { "setgenerate",            &setgenerate,            true },
2234     { "gethashespersec",        &gethashespersec,        true },
2235     { "getinfo",                &getinfo,                true },
2236     { "getmininginfo",          &getmininginfo,          true },
2237     { "getnewaddress",          &getnewaddress,          true },
2238     { "getaccountaddress",      &getaccountaddress,      true },
2239     { "setaccount",             &setaccount,             true },
2240     { "getaccount",             &getaccount,             false },
2241     { "getaddressesbyaccount",  &getaddressesbyaccount,  true },
2242     { "sendtoaddress",          &sendtoaddress,          false },
2243     { "getreceivedbyaddress",   &getreceivedbyaddress,   false },
2244     { "getreceivedbyaccount",   &getreceivedbyaccount,   false },
2245     { "listreceivedbyaddress",  &listreceivedbyaddress,  false },
2246     { "listreceivedbyaccount",  &listreceivedbyaccount,  false },
2247     { "backupwallet",           &backupwallet,           true },
2248     { "keypoolrefill",          &keypoolrefill,          true },
2249     { "walletpassphrase",       &walletpassphrase,       true },
2250     { "walletpassphrasechange", &walletpassphrasechange, false },
2251     { "walletlock",             &walletlock,             true },
2252     { "encryptwallet",          &encryptwallet,          false },
2253     { "validateaddress",        &validateaddress,        true },
2254     { "getbalance",             &getbalance,             false },
2255     { "move",                   &movecmd,                false },
2256     { "sendfrom",               &sendfrom,               false },
2257     { "sendmany",               &sendmany,               false },
2258     { "addmultisigaddress",     &addmultisigaddress,     false },
2259     { "getblock",               &getblock,               false },
2260     { "getblockhash",           &getblockhash,           false },
2261     { "gettransaction",         &gettransaction,         false },
2262     { "listtransactions",       &listtransactions,       false },
2263     { "signmessage",            &signmessage,            false },
2264     { "verifymessage",          &verifymessage,          false },
2265     { "getwork",                &getwork,                true },
2266     { "listaccounts",           &listaccounts,           false },
2267     { "settxfee",               &settxfee,               false },
2268     { "getmemorypool",          &getmemorypool,          true },
2269     { "listsinceblock",         &listsinceblock,         false },
2270     { "dumpprivkey",            &dumpprivkey,            false },
2271     { "importprivkey",          &importprivkey,          false },
2272     { "getcheckpoint",          &getcheckpoint,          true },
2273     { "reservebalance",         &reservebalance,         false},
2274     { "checkwallet",            &checkwallet,            false},
2275     { "repairwallet",           &repairwallet,           false},
2276     { "makekeypair",            &makekeypair,            false},
2277     { "sendalert",              &sendalert,              false},
2278 };
2279
2280 CRPCTable::CRPCTable()
2281 {
2282     unsigned int vcidx;
2283     for (vcidx = 0; vcidx < (sizeof(vRPCCommands) / sizeof(vRPCCommands[0])); vcidx++)
2284     {
2285         const CRPCCommand *pcmd;
2286
2287         pcmd = &vRPCCommands[vcidx];
2288         mapCommands[pcmd->name] = pcmd;
2289     }
2290 }
2291
2292 const CRPCCommand *CRPCTable::operator[](string name) const
2293 {
2294     map<string, const CRPCCommand*>::const_iterator it = mapCommands.find(name);
2295     if (it == mapCommands.end())
2296         return NULL;
2297     return (*it).second;
2298 }
2299
2300 //
2301 // HTTP protocol
2302 //
2303 // This ain't Apache.  We're just using HTTP header for the length field
2304 // and to be compatible with other JSON-RPC implementations.
2305 //
2306
2307 string HTTPPost(const string& strMsg, const map<string,string>& mapRequestHeaders)
2308 {
2309     ostringstream s;
2310     s << "POST / HTTP/1.1\r\n"
2311       << "User-Agent: ppcoin-json-rpc/" << FormatFullVersion() << "\r\n"
2312       << "Host: 127.0.0.1\r\n"
2313       << "Content-Type: application/json\r\n"
2314       << "Content-Length: " << strMsg.size() << "\r\n"
2315       << "Connection: close\r\n"
2316       << "Accept: application/json\r\n";
2317     BOOST_FOREACH(const PAIRTYPE(string, string)& item, mapRequestHeaders)
2318         s << item.first << ": " << item.second << "\r\n";
2319     s << "\r\n" << strMsg;
2320
2321     return s.str();
2322 }
2323
2324 string rfc1123Time()
2325 {
2326     char buffer[64];
2327     time_t now;
2328     time(&now);
2329     struct tm* now_gmt = gmtime(&now);
2330     string locale(setlocale(LC_TIME, NULL));
2331     setlocale(LC_TIME, "C"); // we want posix (aka "C") weekday/month strings
2332     strftime(buffer, sizeof(buffer), "%a, %d %b %Y %H:%M:%S +0000", now_gmt);
2333     setlocale(LC_TIME, locale.c_str());
2334     return string(buffer);
2335 }
2336
2337 static string HTTPReply(int nStatus, const string& strMsg)
2338 {
2339     if (nStatus == 401)
2340         return strprintf("HTTP/1.0 401 Authorization Required\r\n"
2341             "Date: %s\r\n"
2342             "Server: ppcoin-json-rpc/%s\r\n"
2343             "WWW-Authenticate: Basic realm=\"jsonrpc\"\r\n"
2344             "Content-Type: text/html\r\n"
2345             "Content-Length: 296\r\n"
2346             "\r\n"
2347             "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\r\n"
2348             "\"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd\">\r\n"
2349             "<HTML>\r\n"
2350             "<HEAD>\r\n"
2351             "<TITLE>Error</TITLE>\r\n"
2352             "<META HTTP-EQUIV='Content-Type' CONTENT='text/html; charset=ISO-8859-1'>\r\n"
2353             "</HEAD>\r\n"
2354             "<BODY><H1>401 Unauthorized.</H1></BODY>\r\n"
2355             "</HTML>\r\n", rfc1123Time().c_str(), FormatFullVersion().c_str());
2356     const char *cStatus;
2357          if (nStatus == 200) cStatus = "OK";
2358     else if (nStatus == 400) cStatus = "Bad Request";
2359     else if (nStatus == 403) cStatus = "Forbidden";
2360     else if (nStatus == 404) cStatus = "Not Found";
2361     else if (nStatus == 500) cStatus = "Internal Server Error";
2362     else cStatus = "";
2363     return strprintf(
2364             "HTTP/1.1 %d %s\r\n"
2365             "Date: %s\r\n"
2366             "Connection: close\r\n"
2367             "Content-Length: %d\r\n"
2368             "Content-Type: application/json\r\n"
2369             "Server: ppcoin-json-rpc/%s\r\n"
2370             "\r\n"
2371             "%s",
2372         nStatus,
2373         cStatus,
2374         rfc1123Time().c_str(),
2375         strMsg.size(),
2376         FormatFullVersion().c_str(),
2377         strMsg.c_str());
2378 }
2379
2380 int ReadHTTPStatus(std::basic_istream<char>& stream)
2381 {
2382     string str;
2383     getline(stream, str);
2384     vector<string> vWords;
2385     boost::split(vWords, str, boost::is_any_of(" "));
2386     if (vWords.size() < 2)
2387         return 500;
2388     return atoi(vWords[1].c_str());
2389 }
2390
2391 int ReadHTTPHeader(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet)
2392 {
2393     int nLen = 0;
2394     loop
2395     {
2396         string str;
2397         std::getline(stream, str);
2398         if (str.empty() || str == "\r")
2399             break;
2400         string::size_type nColon = str.find(":");
2401         if (nColon != string::npos)
2402         {
2403             string strHeader = str.substr(0, nColon);
2404             boost::trim(strHeader);
2405             boost::to_lower(strHeader);
2406             string strValue = str.substr(nColon+1);
2407             boost::trim(strValue);
2408             mapHeadersRet[strHeader] = strValue;
2409             if (strHeader == "content-length")
2410                 nLen = atoi(strValue.c_str());
2411         }
2412     }
2413     return nLen;
2414 }
2415
2416 int ReadHTTP(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet, string& strMessageRet)
2417 {
2418     mapHeadersRet.clear();
2419     strMessageRet = "";
2420
2421     // Read status
2422     int nStatus = ReadHTTPStatus(stream);
2423
2424     // Read header
2425     int nLen = ReadHTTPHeader(stream, mapHeadersRet);
2426     if (nLen < 0 || nLen > (int)MAX_SIZE)
2427         return 500;
2428
2429     // Read message
2430     if (nLen > 0)
2431     {
2432         vector<char> vch(nLen);
2433         stream.read(&vch[0], nLen);
2434         strMessageRet = string(vch.begin(), vch.end());
2435     }
2436
2437     return nStatus;
2438 }
2439
2440 bool HTTPAuthorized(map<string, string>& mapHeaders)
2441 {
2442     string strAuth = mapHeaders["authorization"];
2443     if (strAuth.substr(0,6) != "Basic ")
2444         return false;
2445     string strUserPass64 = strAuth.substr(6); boost::trim(strUserPass64);
2446     string strUserPass = DecodeBase64(strUserPass64);
2447     return strUserPass == strRPCUserColonPass;
2448 }
2449
2450 //
2451 // JSON-RPC protocol.  Bitcoin speaks version 1.0 for maximum compatibility,
2452 // but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
2453 // unspecified (HTTP errors and contents of 'error').
2454 //
2455 // 1.0 spec: http://json-rpc.org/wiki/specification
2456 // 1.2 spec: http://groups.google.com/group/json-rpc/web/json-rpc-over-http
2457 // http://www.codeproject.com/KB/recipes/JSON_Spirit.aspx
2458 //
2459
2460 string JSONRPCRequest(const string& strMethod, const Array& params, const Value& id)
2461 {
2462     Object request;
2463     request.push_back(Pair("method", strMethod));
2464     request.push_back(Pair("params", params));
2465     request.push_back(Pair("id", id));
2466     return write_string(Value(request), false) + "\n";
2467 }
2468
2469 string JSONRPCReply(const Value& result, const Value& error, const Value& id)
2470 {
2471     Object reply;
2472     if (error.type() != null_type)
2473         reply.push_back(Pair("result", Value::null));
2474     else
2475         reply.push_back(Pair("result", result));
2476     reply.push_back(Pair("error", error));
2477     reply.push_back(Pair("id", id));
2478     return write_string(Value(reply), false) + "\n";
2479 }
2480
2481 void ErrorReply(std::ostream& stream, const Object& objError, const Value& id)
2482 {
2483     // Send error reply from json-rpc error object
2484     int nStatus = 500;
2485     int code = find_value(objError, "code").get_int();
2486     if (code == -32600) nStatus = 400;
2487     else if (code == -32601) nStatus = 404;
2488     string strReply = JSONRPCReply(Value::null, objError, id);
2489     stream << HTTPReply(nStatus, strReply) << std::flush;
2490 }
2491
2492 bool ClientAllowed(const string& strAddress)
2493 {
2494     if (strAddress == asio::ip::address_v4::loopback().to_string())
2495         return true;
2496     const vector<string>& vAllow = mapMultiArgs["-rpcallowip"];
2497     BOOST_FOREACH(string strAllow, vAllow)
2498         if (WildcardMatch(strAddress, strAllow))
2499             return true;
2500     return false;
2501 }
2502
2503 //
2504 // IOStream device that speaks SSL but can also speak non-SSL
2505 //
2506 class SSLIOStreamDevice : public iostreams::device<iostreams::bidirectional> {
2507 public:
2508     SSLIOStreamDevice(SSLStream &streamIn, bool fUseSSLIn) : stream(streamIn)
2509     {
2510         fUseSSL = fUseSSLIn;
2511         fNeedHandshake = fUseSSLIn;
2512     }
2513
2514     void handshake(ssl::stream_base::handshake_type role)
2515     {
2516         if (!fNeedHandshake) return;
2517         fNeedHandshake = false;
2518         stream.handshake(role);
2519     }
2520     std::streamsize read(char* s, std::streamsize n)
2521     {
2522         handshake(ssl::stream_base::server); // HTTPS servers read first
2523         if (fUseSSL) return stream.read_some(asio::buffer(s, n));
2524         return stream.next_layer().read_some(asio::buffer(s, n));
2525     }
2526     std::streamsize write(const char* s, std::streamsize n)
2527     {
2528         handshake(ssl::stream_base::client); // HTTPS clients write first
2529         if (fUseSSL) return asio::write(stream, asio::buffer(s, n));
2530         return asio::write(stream.next_layer(), asio::buffer(s, n));
2531     }
2532     bool connect(const std::string& server, const std::string& port)
2533     {
2534         ip::tcp::resolver resolver(stream.get_io_service());
2535         ip::tcp::resolver::query query(server.c_str(), port.c_str());
2536         ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
2537         ip::tcp::resolver::iterator end;
2538         boost::system::error_code error = asio::error::host_not_found;
2539         while (error && endpoint_iterator != end)
2540         {
2541             stream.lowest_layer().close();
2542             stream.lowest_layer().connect(*endpoint_iterator++, error);
2543         }
2544         if (error)
2545             return false;
2546         return true;
2547     }
2548
2549 private:
2550     bool fNeedHandshake;
2551     bool fUseSSL;
2552     SSLStream& stream;
2553 };
2554
2555 void ThreadRPCServer(void* parg)
2556 {
2557     IMPLEMENT_RANDOMIZE_STACK(ThreadRPCServer(parg));
2558     try
2559     {
2560         vnThreadsRunning[THREAD_RPCSERVER]++;
2561         ThreadRPCServer2(parg);
2562         vnThreadsRunning[THREAD_RPCSERVER]--;
2563     }
2564     catch (std::exception& e) {
2565         vnThreadsRunning[THREAD_RPCSERVER]--;
2566         PrintException(&e, "ThreadRPCServer()");
2567     } catch (...) {
2568         vnThreadsRunning[THREAD_RPCSERVER]--;
2569         PrintException(NULL, "ThreadRPCServer()");
2570     }
2571     printf("ThreadRPCServer exiting\n");
2572 }
2573
2574 void ThreadRPCServer2(void* parg)
2575 {
2576     printf("ThreadRPCServer started\n");
2577
2578     strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"];
2579     if (mapArgs["-rpcpassword"] == "")
2580     {
2581         unsigned char rand_pwd[32];
2582         RAND_bytes(rand_pwd, 32);
2583         string strWhatAmI = "To use ppcoind";
2584         if (mapArgs.count("-server"))
2585             strWhatAmI = strprintf(_("To use the %s option"), "\"-server\"");
2586         else if (mapArgs.count("-daemon"))
2587             strWhatAmI = strprintf(_("To use the %s option"), "\"-daemon\"");
2588         ThreadSafeMessageBox(strprintf(
2589             _("%s, you must set a rpcpassword in the configuration file:\n %s\n"
2590               "It is recommended you use the following random password:\n"
2591               "rpcuser=bitcoinrpc\n"
2592               "rpcpassword=%s\n"
2593               "(you do not need to remember this password)\n"
2594               "If the file does not exist, create it with owner-readable-only file permissions.\n"),
2595                 strWhatAmI.c_str(),
2596                 GetConfigFile().string().c_str(),
2597                 EncodeBase58(&rand_pwd[0],&rand_pwd[0]+32).c_str()),
2598             _("Error"), wxOK | wxMODAL);
2599         StartShutdown();
2600         return;
2601     }
2602
2603     bool fUseSSL = GetBoolArg("-rpcssl");
2604     asio::ip::address bindAddress = mapArgs.count("-rpcallowip") ? asio::ip::address_v4::any() : asio::ip::address_v4::loopback();
2605
2606     asio::io_service io_service;
2607     ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", RPC_PORT));
2608     ip::tcp::acceptor acceptor(io_service);
2609     try
2610     {
2611         acceptor.open(endpoint.protocol());
2612         acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
2613         acceptor.bind(endpoint);
2614         acceptor.listen(socket_base::max_connections);
2615     }
2616     catch(boost::system::system_error &e)
2617     {
2618         ThreadSafeMessageBox(strprintf(_("An error occured while setting up the RPC port %i for listening: %s"), endpoint.port(), e.what()),
2619                              _("Error"), wxOK | wxMODAL);
2620         StartShutdown();
2621         return;
2622     }
2623
2624     ssl::context context(io_service, ssl::context::sslv23);
2625     if (fUseSSL)
2626     {
2627         context.set_options(ssl::context::no_sslv2);
2628
2629         filesystem::path pathCertFile(GetArg("-rpcsslcertificatechainfile", "server.cert"));
2630         if (!pathCertFile.is_complete()) pathCertFile = filesystem::path(GetDataDir()) / pathCertFile;
2631         if (filesystem::exists(pathCertFile)) context.use_certificate_chain_file(pathCertFile.string());
2632         else printf("ThreadRPCServer ERROR: missing server certificate file %s\n", pathCertFile.string().c_str());
2633
2634         filesystem::path pathPKFile(GetArg("-rpcsslprivatekeyfile", "server.pem"));
2635         if (!pathPKFile.is_complete()) pathPKFile = filesystem::path(GetDataDir()) / pathPKFile;
2636         if (filesystem::exists(pathPKFile)) context.use_private_key_file(pathPKFile.string(), ssl::context::pem);
2637         else printf("ThreadRPCServer ERROR: missing server private key file %s\n", pathPKFile.string().c_str());
2638
2639         string strCiphers = GetArg("-rpcsslciphers", "TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH");
2640         SSL_CTX_set_cipher_list(context.impl(), strCiphers.c_str());
2641     }
2642
2643     loop
2644     {
2645         // Accept connection
2646         SSLStream sslStream(io_service, context);
2647         SSLIOStreamDevice d(sslStream, fUseSSL);
2648         iostreams::stream<SSLIOStreamDevice> stream(d);
2649
2650         ip::tcp::endpoint peer;
2651         vnThreadsRunning[THREAD_RPCSERVER]--;
2652         acceptor.accept(sslStream.lowest_layer(), peer);
2653         vnThreadsRunning[4]++;
2654         if (fShutdown)
2655             return;
2656
2657         // Restrict callers by IP
2658         if (!ClientAllowed(peer.address().to_string()))
2659         {
2660             // Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake.
2661             if (!fUseSSL)
2662                 stream << HTTPReply(403, "") << std::flush;
2663             continue;
2664         }
2665
2666         map<string, string> mapHeaders;
2667         string strRequest;
2668
2669         boost::thread api_caller(ReadHTTP, boost::ref(stream), boost::ref(mapHeaders), boost::ref(strRequest));
2670         if (!api_caller.timed_join(boost::posix_time::seconds(GetArg("-rpctimeout", 30))))
2671         {   // Timed out:
2672             acceptor.cancel();
2673             printf("ThreadRPCServer ReadHTTP timeout\n");
2674             continue;
2675         }
2676
2677         // Check authorization
2678         if (mapHeaders.count("authorization") == 0)
2679         {
2680             stream << HTTPReply(401, "") << std::flush;
2681             continue;
2682         }
2683         if (!HTTPAuthorized(mapHeaders))
2684         {
2685             printf("ThreadRPCServer incorrect password attempt from %s\n",peer.address().to_string().c_str());
2686             /* Deter brute-forcing short passwords.
2687                If this results in a DOS the user really
2688                shouldn't have their RPC port exposed.*/
2689             if (mapArgs["-rpcpassword"].size() < 20)
2690                 Sleep(250);
2691
2692             stream << HTTPReply(401, "") << std::flush;
2693             continue;
2694         }
2695
2696         Value id = Value::null;
2697         try
2698         {
2699             // Parse request
2700             Value valRequest;
2701             if (!read_string(strRequest, valRequest) || valRequest.type() != obj_type)
2702                 throw JSONRPCError(-32700, "Parse error");
2703             const Object& request = valRequest.get_obj();
2704
2705             // Parse id now so errors from here on will have the id
2706             id = find_value(request, "id");
2707
2708             // Parse method
2709             Value valMethod = find_value(request, "method");
2710             if (valMethod.type() == null_type)
2711                 throw JSONRPCError(-32600, "Missing method");
2712             if (valMethod.type() != str_type)
2713                 throw JSONRPCError(-32600, "Method must be a string");
2714             string strMethod = valMethod.get_str();
2715             if (strMethod != "getwork" && strMethod != "getmemorypool")
2716                 printf("ThreadRPCServer method=%s\n", strMethod.c_str());
2717
2718             // Parse params
2719             Value valParams = find_value(request, "params");
2720             Array params;
2721             if (valParams.type() == array_type)
2722                 params = valParams.get_array();
2723             else if (valParams.type() == null_type)
2724                 params = Array();
2725             else
2726                 throw JSONRPCError(-32600, "Params must be an array");
2727
2728             // Find method
2729             const CRPCCommand *pcmd = tableRPC[strMethod];
2730             if (!pcmd)
2731                 throw JSONRPCError(-32601, "Method not found");
2732
2733             // Observe safe mode
2734             string strWarning = GetWarnings("rpc");
2735             if (strWarning != "" && !GetBoolArg("-disablesafemode") &&
2736                 !pcmd->okSafeMode)
2737                 throw JSONRPCError(-2, string("Safe mode: ") + strWarning);
2738
2739             try
2740             {
2741                 // Execute
2742                 Value result;
2743                 {
2744                     LOCK2(cs_main, pwalletMain->cs_wallet);
2745                     result = pcmd->actor(params, false);
2746                 }
2747
2748                 // Send reply
2749                 string strReply = JSONRPCReply(result, Value::null, id);
2750                 stream << HTTPReply(200, strReply) << std::flush;
2751             }
2752             catch (std::exception& e)
2753             {
2754                 ErrorReply(stream, JSONRPCError(-1, e.what()), id);
2755             }
2756         }
2757         catch (Object& objError)
2758         {
2759             ErrorReply(stream, objError, id);
2760         }
2761         catch (std::exception& e)
2762         {
2763             ErrorReply(stream, JSONRPCError(-32700, e.what()), id);
2764         }
2765     }
2766 }
2767
2768
2769
2770
2771 Object CallRPC(const string& strMethod, const Array& params)
2772 {
2773     if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
2774         throw runtime_error(strprintf(
2775             _("You must set rpcpassword=<password> in the configuration file:\n%s\n"
2776               "If the file does not exist, create it with owner-readable-only file permissions."),
2777                 GetConfigFile().string().c_str()));
2778
2779     // Connect to localhost
2780     bool fUseSSL = GetBoolArg("-rpcssl");
2781     asio::io_service io_service;
2782     ssl::context context(io_service, ssl::context::sslv23);
2783     context.set_options(ssl::context::no_sslv2);
2784     SSLStream sslStream(io_service, context);
2785     SSLIOStreamDevice d(sslStream, fUseSSL);
2786     iostreams::stream<SSLIOStreamDevice> stream(d);
2787     if (!d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", CBigNum(RPC_PORT).ToString().c_str())))
2788         throw runtime_error("couldn't connect to server");
2789
2790     // HTTP basic authentication
2791     string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
2792     map<string, string> mapRequestHeaders;
2793     mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64;
2794
2795     // Send request
2796     string strRequest = JSONRPCRequest(strMethod, params, 1);
2797     string strPost = HTTPPost(strRequest, mapRequestHeaders);
2798     stream << strPost << std::flush;
2799
2800     // Receive reply
2801     map<string, string> mapHeaders;
2802     string strReply;
2803     int nStatus = ReadHTTP(stream, mapHeaders, strReply);
2804     if (nStatus == 401)
2805         throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
2806     else if (nStatus >= 400 && nStatus != 400 && nStatus != 404 && nStatus != 500)
2807         throw runtime_error(strprintf("server returned HTTP error %d", nStatus));
2808     else if (strReply.empty())
2809         throw runtime_error("no response from server");
2810
2811     // Parse reply
2812     Value valReply;
2813     if (!read_string(strReply, valReply))
2814         throw runtime_error("couldn't parse reply from server");
2815     const Object& reply = valReply.get_obj();
2816     if (reply.empty())
2817         throw runtime_error("expected reply to have result, error and id properties");
2818
2819     return reply;
2820 }
2821
2822
2823
2824
2825 template<typename T>
2826 void ConvertTo(Value& value)
2827 {
2828     if (value.type() == str_type)
2829     {
2830         // reinterpret string as unquoted json value
2831         Value value2;
2832         if (!read_string(value.get_str(), value2))
2833             throw runtime_error("type mismatch");
2834         value = value2.get_value<T>();
2835     }
2836     else
2837     {
2838         value = value.get_value<T>();
2839     }
2840 }
2841
2842 int CommandLineRPC(int argc, char *argv[])
2843 {
2844     string strPrint;
2845     int nRet = 0;
2846     try
2847     {
2848         // Skip switches
2849         while (argc > 1 && IsSwitchChar(argv[1][0]))
2850         {
2851             argc--;
2852             argv++;
2853         }
2854
2855         // Method
2856         if (argc < 2)
2857             throw runtime_error("too few parameters");
2858         string strMethod = argv[1];
2859
2860         // Parameters default to strings
2861         Array params;
2862         for (int i = 2; i < argc; i++)
2863             params.push_back(argv[i]);
2864         int n = params.size();
2865
2866         //
2867         // Special case non-string parameter types
2868         //
2869         if (strMethod == "setgenerate"            && n > 0) ConvertTo<bool>(params[0]);
2870         if (strMethod == "setgenerate"            && n > 1) ConvertTo<boost::int64_t>(params[1]);
2871         if (strMethod == "sendtoaddress"          && n > 1) ConvertTo<double>(params[1]);
2872         if (strMethod == "settxfee"               && n > 0) ConvertTo<double>(params[0]);
2873         if (strMethod == "getreceivedbyaddress"   && n > 1) ConvertTo<boost::int64_t>(params[1]);
2874         if (strMethod == "getreceivedbyaccount"   && n > 1) ConvertTo<boost::int64_t>(params[1]);
2875         if (strMethod == "listreceivedbyaddress"  && n > 0) ConvertTo<boost::int64_t>(params[0]);
2876         if (strMethod == "listreceivedbyaddress"  && n > 1) ConvertTo<bool>(params[1]);
2877         if (strMethod == "listreceivedbyaccount"  && n > 0) ConvertTo<boost::int64_t>(params[0]);
2878         if (strMethod == "listreceivedbyaccount"  && n > 1) ConvertTo<bool>(params[1]);
2879         if (strMethod == "getbalance"             && n > 1) ConvertTo<boost::int64_t>(params[1]);
2880         if (strMethod == "getblockhash"           && n > 0) ConvertTo<boost::int64_t>(params[0]);
2881         if (strMethod == "move"                   && n > 2) ConvertTo<double>(params[2]);
2882         if (strMethod == "move"                   && n > 3) ConvertTo<boost::int64_t>(params[3]);
2883         if (strMethod == "sendfrom"               && n > 2) ConvertTo<double>(params[2]);
2884         if (strMethod == "sendfrom"               && n > 3) ConvertTo<boost::int64_t>(params[3]);
2885         if (strMethod == "listtransactions"       && n > 1) ConvertTo<boost::int64_t>(params[1]);
2886         if (strMethod == "listtransactions"       && n > 2) ConvertTo<boost::int64_t>(params[2]);
2887         if (strMethod == "listaccounts"           && n > 0) ConvertTo<boost::int64_t>(params[0]);
2888         if (strMethod == "walletpassphrase"       && n > 1) ConvertTo<boost::int64_t>(params[1]);
2889         if (strMethod == "walletpassphrase"       && n > 2) ConvertTo<bool>(params[2]);
2890         if (strMethod == "listsinceblock"         && n > 1) ConvertTo<boost::int64_t>(params[1]);
2891         if (strMethod == "sendalert"              && n > 2) ConvertTo<boost::int64_t>(params[2]);
2892         if (strMethod == "sendalert"              && n > 3) ConvertTo<boost::int64_t>(params[3]);
2893         if (strMethod == "sendalert"              && n > 4) ConvertTo<boost::int64_t>(params[4]);
2894         if (strMethod == "sendalert"              && n > 5) ConvertTo<boost::int64_t>(params[5]);
2895         if (strMethod == "sendmany"               && n > 1)
2896         {
2897             string s = params[1].get_str();
2898             Value v;
2899             if (!read_string(s, v) || v.type() != obj_type)
2900                 throw runtime_error("type mismatch");
2901             params[1] = v.get_obj();
2902         }
2903         if (strMethod == "sendmany"                && n > 2) ConvertTo<boost::int64_t>(params[2]);
2904         if (strMethod == "reservebalance"          && n > 0) ConvertTo<bool>(params[0]);
2905         if (strMethod == "reservebalance"          && n > 1) ConvertTo<double>(params[1]);
2906         if (strMethod == "addmultisigaddress"      && n > 0) ConvertTo<boost::int64_t>(params[0]);
2907         if (strMethod == "addmultisigaddress"      && n > 1)
2908         {
2909             string s = params[1].get_str();
2910             Value v;
2911             if (!read_string(s, v) || v.type() != array_type)
2912                 throw runtime_error("type mismatch "+s);
2913             params[1] = v.get_array();
2914         }
2915
2916         // Execute
2917         Object reply = CallRPC(strMethod, params);
2918
2919         // Parse reply
2920         const Value& result = find_value(reply, "result");
2921         const Value& error  = find_value(reply, "error");
2922
2923         if (error.type() != null_type)
2924         {
2925             // Error
2926             strPrint = "error: " + write_string(error, false);
2927             int code = find_value(error.get_obj(), "code").get_int();
2928             nRet = abs(code);
2929         }
2930         else
2931         {
2932             // Result
2933             if (result.type() == null_type)
2934                 strPrint = "";
2935             else if (result.type() == str_type)
2936                 strPrint = result.get_str();
2937             else
2938                 strPrint = write_string(result, true);
2939         }
2940     }
2941     catch (std::exception& e)
2942     {
2943         strPrint = string("error: ") + e.what();
2944         nRet = 87;
2945     }
2946     catch (...)
2947     {
2948         PrintException(NULL, "CommandLineRPC()");
2949     }
2950
2951     if (strPrint != "")
2952     {
2953         fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
2954     }
2955     return nRet;
2956 }
2957
2958
2959
2960
2961 #ifdef TEST
2962 int main(int argc, char *argv[])
2963 {
2964 #ifdef _MSC_VER
2965     // Turn off microsoft heap dump noise
2966     _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
2967     _CrtSetReportFile(_CRT_WARN, CreateFile("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0));
2968 #endif
2969     setbuf(stdin, NULL);
2970     setbuf(stdout, NULL);
2971     setbuf(stderr, NULL);
2972
2973     try
2974     {
2975         if (argc >= 2 && string(argv[1]) == "-server")
2976         {
2977             printf("server ready\n");
2978             ThreadRPCServer(NULL);
2979         }
2980         else
2981         {
2982             return CommandLineRPC(argc, argv);
2983         }
2984     }
2985     catch (std::exception& e) {
2986         PrintException(&e, "main()");
2987     } catch (...) {
2988         PrintException(NULL, "main()");
2989     }
2990     return 0;
2991 }
2992 #endif
2993
2994 const CRPCTable tableRPC;