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