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