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