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