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