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