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