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