Improve getblock/getblockbynumber output
[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", (boost::int64_t)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("time", (boost::int64_t)pindex->nTime));
1627                     }
1628                     else
1629                         entry.push_back(Pair("confirmations", 0));
1630                 }
1631             }
1632         }
1633         else
1634             throw JSONRPCError(-5, "No information available about transaction");
1635     }
1636
1637     return entry;
1638 }
1639
1640
1641 Value backupwallet(const Array& params, bool fHelp)
1642 {
1643     if (fHelp || params.size() != 1)
1644         throw runtime_error(
1645             "backupwallet <destination>\n"
1646             "Safely copies wallet.dat to destination, which can be a directory or a path with filename.");
1647
1648     string strDest = params[0].get_str();
1649     BackupWallet(*pwalletMain, strDest);
1650
1651     return Value::null;
1652 }
1653
1654
1655 Value keypoolrefill(const Array& params, bool fHelp)
1656 {
1657     if (pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1658         throw runtime_error(
1659             "keypoolrefill\n"
1660             "Fills the keypool, requires wallet passphrase to be set.");
1661     if (!pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1662         throw runtime_error(
1663             "keypoolrefill\n"
1664             "Fills the keypool.");
1665
1666     if (pwalletMain->IsLocked())
1667         throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
1668
1669     pwalletMain->TopUpKeyPool();
1670
1671     if (pwalletMain->GetKeyPoolSize() < GetArg("-keypool", 100))
1672         throw JSONRPCError(-4, "Error refreshing keypool.");
1673
1674     return Value::null;
1675 }
1676
1677
1678 void ThreadTopUpKeyPool(void* parg)
1679 {
1680     pwalletMain->TopUpKeyPool();
1681 }
1682
1683 void ThreadCleanWalletPassphrase(void* parg)
1684 {
1685     int64 nMyWakeTime = GetTimeMillis() + *((int64*)parg) * 1000;
1686
1687     ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1688
1689     if (nWalletUnlockTime == 0)
1690     {
1691         nWalletUnlockTime = nMyWakeTime;
1692
1693         do
1694         {
1695             if (nWalletUnlockTime==0)
1696                 break;
1697             int64 nToSleep = nWalletUnlockTime - GetTimeMillis();
1698             if (nToSleep <= 0)
1699                 break;
1700
1701             LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1702             Sleep(nToSleep);
1703             ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1704
1705         } while(1);
1706
1707         if (nWalletUnlockTime)
1708         {
1709             nWalletUnlockTime = 0;
1710             pwalletMain->Lock();
1711         }
1712     }
1713     else
1714     {
1715         if (nWalletUnlockTime < nMyWakeTime)
1716             nWalletUnlockTime = nMyWakeTime;
1717     }
1718
1719     LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1720
1721     delete (int64*)parg;
1722 }
1723
1724 Value walletpassphrase(const Array& params, bool fHelp)
1725 {
1726     if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 3))
1727         throw runtime_error(
1728             "walletpassphrase <passphrase> <timeout> [mintonly]\n"
1729             "Stores the wallet decryption key in memory for <timeout> seconds.\n"
1730             "mintonly is optional true/false allowing only block minting.");
1731     if (fHelp)
1732         return true;
1733     if (!pwalletMain->IsCrypted())
1734         throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
1735
1736     if (!pwalletMain->IsLocked())
1737         throw JSONRPCError(-17, "Error: Wallet is already unlocked, use walletlock first if need to change unlock settings.");
1738
1739     // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
1740     SecureString strWalletPass;
1741     strWalletPass.reserve(100);
1742     // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1743     // Alternately, find a way to make params[0] mlock()'d to begin with.
1744     strWalletPass = params[0].get_str().c_str();
1745
1746     if (strWalletPass.length() > 0)
1747     {
1748         if (!pwalletMain->Unlock(strWalletPass))
1749             throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1750     }
1751     else
1752         throw runtime_error(
1753             "walletpassphrase <passphrase> <timeout>\n"
1754             "Stores the wallet decryption key in memory for <timeout> seconds.");
1755
1756     CreateThread(ThreadTopUpKeyPool, NULL);
1757     int64* pnSleepTime = new int64(params[1].get_int64());
1758     CreateThread(ThreadCleanWalletPassphrase, pnSleepTime);
1759
1760     // ppcoin: if user OS account compromised prevent trivial sendmoney commands
1761     if (params.size() > 2)
1762         fWalletUnlockMintOnly = params[2].get_bool();
1763     else
1764         fWalletUnlockMintOnly = false;
1765
1766     return Value::null;
1767 }
1768
1769
1770 Value walletpassphrasechange(const Array& params, bool fHelp)
1771 {
1772     if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1773         throw runtime_error(
1774             "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1775             "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1776     if (fHelp)
1777         return true;
1778     if (!pwalletMain->IsCrypted())
1779         throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
1780
1781     // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
1782     // Alternately, find a way to make params[0] mlock()'d to begin with.
1783     SecureString strOldWalletPass;
1784     strOldWalletPass.reserve(100);
1785     strOldWalletPass = params[0].get_str().c_str();
1786
1787     SecureString strNewWalletPass;
1788     strNewWalletPass.reserve(100);
1789     strNewWalletPass = params[1].get_str().c_str();
1790
1791     if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
1792         throw runtime_error(
1793             "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1794             "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1795
1796     if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
1797         throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1798
1799     return Value::null;
1800 }
1801
1802
1803 Value walletlock(const Array& params, bool fHelp)
1804 {
1805     if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
1806         throw runtime_error(
1807             "walletlock\n"
1808             "Removes the wallet encryption key from memory, locking the wallet.\n"
1809             "After calling this method, you will need to call walletpassphrase again\n"
1810             "before being able to call any methods which require the wallet to be unlocked.");
1811     if (fHelp)
1812         return true;
1813     if (!pwalletMain->IsCrypted())
1814         throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletlock was called.");
1815
1816     {
1817         LOCK(cs_nWalletUnlockTime);
1818         pwalletMain->Lock();
1819         nWalletUnlockTime = 0;
1820     }
1821
1822     return Value::null;
1823 }
1824
1825
1826 Value encryptwallet(const Array& params, bool fHelp)
1827 {
1828     if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
1829         throw runtime_error(
1830             "encryptwallet <passphrase>\n"
1831             "Encrypts the wallet with <passphrase>.");
1832     if (fHelp)
1833         return true;
1834     if (pwalletMain->IsCrypted())
1835         throw JSONRPCError(-15, "Error: running with an encrypted wallet, but encryptwallet was called.");
1836
1837     // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1838     // Alternately, find a way to make params[0] mlock()'d to begin with.
1839     SecureString strWalletPass;
1840     strWalletPass.reserve(100);
1841     strWalletPass = params[0].get_str().c_str();
1842
1843     if (strWalletPass.length() < 1)
1844         throw runtime_error(
1845             "encryptwallet <passphrase>\n"
1846             "Encrypts the wallet with <passphrase>.");
1847
1848     if (!pwalletMain->EncryptWallet(strWalletPass))
1849         throw JSONRPCError(-16, "Error: Failed to encrypt the wallet.");
1850
1851     // BDB seems to have a bad habit of writing old data into
1852     // slack space in .dat files; that is bad if the old data is
1853     // unencrypted private keys.  So:
1854     StartShutdown();
1855     return "wallet encrypted; novacoin server stopping, restart to run with encrypted wallet";
1856 }
1857
1858
1859 Value validateaddress(const Array& params, bool fHelp)
1860 {
1861     if (fHelp || params.size() != 1)
1862         throw runtime_error(
1863             "validateaddress <novacoinaddress>\n"
1864             "Return information about <novacoinaddress>.");
1865
1866     CBitcoinAddress address(params[0].get_str());
1867     bool isValid = address.IsValid();
1868
1869     Object ret;
1870     ret.push_back(Pair("isvalid", isValid));
1871     if (isValid)
1872     {
1873         // Call Hash160ToAddress() so we always return current ADDRESSVERSION
1874         // version of the address:
1875         string currentAddress = address.ToString();
1876         ret.push_back(Pair("address", currentAddress));
1877         if (pwalletMain->HaveKey(address))
1878         {
1879             ret.push_back(Pair("ismine", true));
1880             std::vector<unsigned char> vchPubKey;
1881             pwalletMain->GetPubKey(address, vchPubKey);
1882             ret.push_back(Pair("pubkey", HexStr(vchPubKey)));
1883             CKey key;
1884             key.SetPubKey(vchPubKey);
1885             ret.push_back(Pair("iscompressed", key.IsCompressed()));
1886         }
1887         else if (pwalletMain->HaveCScript(address.GetHash160()))
1888         {
1889             ret.push_back(Pair("isscript", true));
1890             CScript subscript;
1891             pwalletMain->GetCScript(address.GetHash160(), subscript);
1892             ret.push_back(Pair("ismine", ::IsMine(*pwalletMain, subscript)));
1893             std::vector<CBitcoinAddress> addresses;
1894             txnouttype whichType;
1895             int nRequired;
1896             ExtractAddresses(subscript, whichType, addresses, nRequired);
1897             ret.push_back(Pair("script", GetTxnOutputType(whichType)));
1898             Array a;
1899             BOOST_FOREACH(const CBitcoinAddress& addr, addresses)
1900                 a.push_back(addr.ToString());
1901             ret.push_back(Pair("addresses", a));
1902             if (whichType == TX_MULTISIG)
1903                 ret.push_back(Pair("sigsrequired", nRequired));
1904         }
1905         else
1906             ret.push_back(Pair("ismine", false));
1907         if (pwalletMain->mapAddressBook.count(address))
1908             ret.push_back(Pair("account", pwalletMain->mapAddressBook[address]));
1909     }
1910     return ret;
1911 }
1912
1913 Value validatepubkey(const Array& params, bool fHelp)
1914 {
1915     if (fHelp || !params.size() || params.size() > 2)
1916         throw runtime_error(
1917             "validatepubkey <novacoinpubkey>\n"
1918             "Return information about <novacoinpubkey>.");
1919
1920     std::vector<unsigned char> vchPubKey = ParseHex(params[0].get_str());
1921     bool isValid;
1922
1923     if(vchPubKey.size() == 33) // Compressed key
1924         isValid = (vchPubKey[0] == 0x02 || vchPubKey[0] == 0x03);
1925     else if(vchPubKey.size() == 65) // Uncompressed key
1926         isValid = vchPubKey[0] == 0x04;
1927     else
1928         isValid = false;
1929
1930     CBitcoinAddress address(vchPubKey);
1931     isValid = isValid ? address.IsValid() : false;
1932
1933     Object ret;
1934     ret.push_back(Pair("isvalid", isValid));
1935     if (isValid)
1936     {
1937         // Call Hash160ToAddress() so we always return current ADDRESSVERSION
1938         // version of the address:
1939         string currentAddress = address.ToString();
1940         ret.push_back(Pair("address", currentAddress));
1941         if (pwalletMain->HaveKey(address))
1942         {
1943             ret.push_back(Pair("ismine", true));
1944             CKey key;
1945             key.SetPubKey(vchPubKey);
1946             ret.push_back(Pair("iscompressed", key.IsCompressed()));
1947         }
1948         else
1949             ret.push_back(Pair("ismine", false));
1950         if (pwalletMain->mapAddressBook.count(address))
1951             ret.push_back(Pair("account", pwalletMain->mapAddressBook[address]));
1952     }
1953     return ret;
1954 }
1955
1956 Value getworkex(const Array& params, bool fHelp)
1957 {
1958     if (fHelp || params.size() > 2)
1959         throw runtime_error(
1960             "getworkex [data, coinbase]\n"
1961             "If [data, coinbase] is not specified, returns extended work data.\n"
1962         );
1963
1964     if (vNodes.empty())
1965         throw JSONRPCError(-9, "NovaCoin is not connected!");
1966
1967     if (IsInitialBlockDownload())
1968         throw JSONRPCError(-10, "NovaCoin is downloading blocks...");
1969
1970     typedef map<uint256, pair<CBlock*, CScript> > mapNewBlock_t;
1971     static mapNewBlock_t mapNewBlock;
1972     static vector<CBlock*> vNewBlock;
1973     static CReserveKey reservekey(pwalletMain);
1974
1975     if (params.size() == 0)
1976     {
1977         // Update block
1978         static unsigned int nTransactionsUpdatedLast;
1979         static CBlockIndex* pindexPrev;
1980         static int64 nStart;
1981         static CBlock* pblock;
1982         if (pindexPrev != pindexBest ||
1983             (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60))
1984         {
1985             if (pindexPrev != pindexBest)
1986             {
1987                 // Deallocate old blocks since they're obsolete now
1988                 mapNewBlock.clear();
1989                 BOOST_FOREACH(CBlock* pblock, vNewBlock)
1990                     delete pblock;
1991                 vNewBlock.clear();
1992             }
1993             nTransactionsUpdatedLast = nTransactionsUpdated;
1994             pindexPrev = pindexBest;
1995             nStart = GetTime();
1996
1997             // Create new block
1998             pblock = CreateNewBlock(pwalletMain);
1999             if (!pblock)
2000                 throw JSONRPCError(-7, "Out of memory");
2001             vNewBlock.push_back(pblock);
2002         }
2003
2004         // Update nTime
2005         pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
2006         pblock->nNonce = 0;
2007
2008         // Update nExtraNonce
2009         static unsigned int nExtraNonce = 0;
2010         IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
2011
2012         // Save
2013         mapNewBlock[pblock->hashMerkleRoot] = make_pair(pblock, pblock->vtx[0].vin[0].scriptSig);
2014
2015         // Prebuild hash buffers
2016         char pmidstate[32];
2017         char pdata[128];
2018         char phash1[64];
2019         FormatHashBuffers(pblock, pmidstate, pdata, phash1);
2020
2021         uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
2022
2023         CTransaction coinbaseTx = pblock->vtx[0];
2024         std::vector<uint256> merkle = pblock->GetMerkleBranch(0);
2025
2026         Object result;
2027         result.push_back(Pair("data",     HexStr(BEGIN(pdata), END(pdata))));
2028         result.push_back(Pair("target",   HexStr(BEGIN(hashTarget), END(hashTarget))));
2029
2030         CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
2031         ssTx << coinbaseTx;
2032         result.push_back(Pair("coinbase", HexStr(ssTx.begin(), ssTx.end())));
2033
2034         Array merkle_arr;
2035         printf("DEBUG: merkle size %i\n", merkle.size());
2036
2037         BOOST_FOREACH(uint256 merkleh, merkle) {
2038             printf("%s\n", merkleh.ToString().c_str());
2039             merkle_arr.push_back(HexStr(BEGIN(merkleh), END(merkleh)));
2040         }
2041
2042         result.push_back(Pair("merkle", merkle_arr));
2043
2044
2045         return result;
2046     }
2047     else
2048     {
2049         // Parse parameters
2050         vector<unsigned char> vchData = ParseHex(params[0].get_str());
2051         vector<unsigned char> coinbase;
2052
2053         if(params.size() == 2)
2054             coinbase = ParseHex(params[1].get_str());
2055
2056         if (vchData.size() != 128)
2057             throw JSONRPCError(-8, "Invalid parameter");
2058
2059         CBlock* pdata = (CBlock*)&vchData[0];
2060
2061         // Byte reverse
2062         for (int i = 0; i < 128/4; i++)
2063             ((unsigned int*)pdata)[i] = ByteReverse(((unsigned int*)pdata)[i]);
2064
2065         // Get saved block
2066         if (!mapNewBlock.count(pdata->hashMerkleRoot))
2067             return false;
2068         CBlock* pblock = mapNewBlock[pdata->hashMerkleRoot].first;
2069
2070         pblock->nTime = pdata->nTime;
2071         pblock->nNonce = pdata->nNonce;
2072
2073         if(coinbase.size() == 0)
2074             pblock->vtx[0].vin[0].scriptSig = mapNewBlock[pdata->hashMerkleRoot].second;
2075         else
2076             CDataStream(coinbase, SER_NETWORK, PROTOCOL_VERSION) >> pblock->vtx[0]; // FIXME - HACK!
2077
2078         pblock->hashMerkleRoot = pblock->BuildMerkleTree();
2079
2080         if (!pblock->SignBlock(*pwalletMain))
2081             throw JSONRPCError(-100, "Unable to sign block, wallet locked?");
2082
2083         return CheckWork(pblock, *pwalletMain, reservekey);
2084     }
2085 }
2086
2087
2088 Value getwork(const Array& params, bool fHelp)
2089 {
2090     if (fHelp || params.size() > 1)
2091         throw runtime_error(
2092             "getwork [data]\n"
2093             "If [data] is not specified, returns formatted hash data to work on:\n"
2094             "  \"midstate\" : precomputed hash state after hashing the first half of the data (DEPRECATED)\n" // deprecated
2095             "  \"data\" : block data\n"
2096             "  \"hash1\" : formatted hash buffer for second hash (DEPRECATED)\n" // deprecated
2097             "  \"target\" : little endian hash target\n"
2098             "If [data] is specified, tries to solve the block and returns true if it was successful.");
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     typedef map<uint256, pair<CBlock*, CScript> > mapNewBlock_t;
2107     static mapNewBlock_t mapNewBlock;
2108     static vector<CBlock*> vNewBlock;
2109     static CReserveKey reservekey(pwalletMain);
2110
2111     if (params.size() == 0)
2112     {
2113         // Update block
2114         static unsigned int nTransactionsUpdatedLast;
2115         static CBlockIndex* pindexPrev;
2116         static int64 nStart;
2117         static CBlock* pblock;
2118         if (pindexPrev != pindexBest ||
2119             (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60))
2120         {
2121             if (pindexPrev != pindexBest)
2122             {
2123                 // Deallocate old blocks since they're obsolete now
2124                 mapNewBlock.clear();
2125                 BOOST_FOREACH(CBlock* pblock, vNewBlock)
2126                     delete pblock;
2127                 vNewBlock.clear();
2128             }
2129             nTransactionsUpdatedLast = nTransactionsUpdated;
2130             pindexPrev = pindexBest;
2131             nStart = GetTime();
2132
2133             // Create new block
2134             pblock = CreateNewBlock(pwalletMain);
2135             if (!pblock)
2136                 throw JSONRPCError(-7, "Out of memory");
2137             vNewBlock.push_back(pblock);
2138         }
2139
2140         // Update nTime
2141         pblock->UpdateTime(pindexPrev);
2142         pblock->nNonce = 0;
2143
2144         // Update nExtraNonce
2145         static unsigned int nExtraNonce = 0;
2146         IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
2147
2148         // Save
2149         mapNewBlock[pblock->hashMerkleRoot] = make_pair(pblock, pblock->vtx[0].vin[0].scriptSig);
2150
2151         // Prebuild hash buffers
2152         char pmidstate[32];
2153         char pdata[128];
2154         char phash1[64];
2155         FormatHashBuffers(pblock, pmidstate, pdata, phash1);
2156
2157         uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
2158
2159         Object result;
2160         result.push_back(Pair("midstate", HexStr(BEGIN(pmidstate), END(pmidstate)))); // deprecated
2161         result.push_back(Pair("data",     HexStr(BEGIN(pdata), END(pdata))));
2162         result.push_back(Pair("hash1",    HexStr(BEGIN(phash1), END(phash1)))); // deprecated
2163         result.push_back(Pair("target",   HexStr(BEGIN(hashTarget), END(hashTarget))));
2164         return result;
2165     }
2166     else
2167     {
2168         // Parse parameters
2169         vector<unsigned char> vchData = ParseHex(params[0].get_str());
2170         if (vchData.size() != 128)
2171             throw JSONRPCError(-8, "Invalid parameter");
2172         CBlock* pdata = (CBlock*)&vchData[0];
2173
2174         // Byte reverse
2175         for (int i = 0; i < 128/4; i++)
2176             ((unsigned int*)pdata)[i] = ByteReverse(((unsigned int*)pdata)[i]);
2177
2178         // Get saved block
2179         if (!mapNewBlock.count(pdata->hashMerkleRoot))
2180             return false;
2181         CBlock* pblock = mapNewBlock[pdata->hashMerkleRoot].first;
2182
2183         pblock->nTime = pdata->nTime;
2184         pblock->nNonce = pdata->nNonce;
2185         pblock->vtx[0].vin[0].scriptSig = mapNewBlock[pdata->hashMerkleRoot].second;
2186         pblock->hashMerkleRoot = pblock->BuildMerkleTree();
2187         if (!pblock->SignBlock(*pwalletMain))
2188             throw JSONRPCError(-100, "Unable to sign block, wallet locked?");
2189
2190         return CheckWork(pblock, *pwalletMain, reservekey);
2191     }
2192 }
2193
2194 Value getblocktemplate(const Array& params, bool fHelp)
2195 {
2196     if (fHelp || params.size() > 1)
2197         throw runtime_error(
2198             "getblocktemplate [params]\n"
2199             "Returns data needed to construct a block to work on:\n"
2200             "  \"version\" : block version\n"
2201             "  \"previousblockhash\" : hash of current highest block\n"
2202             "  \"transactions\" : contents of non-coinbase transactions that should be included in the next block\n"
2203             "  \"coinbaseaux\" : data that should be included in coinbase\n"
2204             "  \"coinbasevalue\" : maximum allowable input to coinbase transaction, including the generation award and transaction fees\n"
2205             "  \"target\" : hash target\n"
2206             "  \"mintime\" : minimum timestamp appropriate for next block\n"
2207             "  \"curtime\" : current timestamp\n"
2208             "  \"mutable\" : list of ways the block template may be changed\n"
2209             "  \"noncerange\" : range of valid nonces\n"
2210             "  \"sigoplimit\" : limit of sigops in blocks\n"
2211             "  \"sizelimit\" : limit of block size\n"
2212             "  \"bits\" : compressed target of next block\n"
2213             "  \"height\" : height of the next block\n"
2214             "See https://en.bitcoin.it/wiki/BIP_0022 for full specification.");
2215
2216     std::string strMode = "template";
2217     if (params.size() > 0)
2218     {
2219         const Object& oparam = params[0].get_obj();
2220         const Value& modeval = find_value(oparam, "mode");
2221         if (modeval.type() == str_type)
2222             strMode = modeval.get_str();
2223         else
2224             throw JSONRPCError(-8, "Invalid mode");
2225     }
2226
2227     if (strMode != "template")
2228         throw JSONRPCError(-8, "Invalid mode");
2229
2230     if (vNodes.empty())
2231         throw JSONRPCError(-9, "NovaCoin is not connected!");
2232
2233     if (IsInitialBlockDownload())
2234         throw JSONRPCError(-10, "NovaCoin is downloading blocks...");
2235
2236     static CReserveKey reservekey(pwalletMain);
2237
2238     // Update block
2239     static unsigned int nTransactionsUpdatedLast;
2240     static CBlockIndex* pindexPrev;
2241     static int64 nStart;
2242     static CBlock* pblock;
2243     if (pindexPrev != pindexBest ||
2244         (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 5))
2245     {
2246         // Clear pindexPrev so future calls make a new block, despite any failures from here on
2247         pindexPrev = NULL;
2248
2249         // Store the pindexBest used before CreateNewBlock, to avoid races
2250         nTransactionsUpdatedLast = nTransactionsUpdated;
2251         CBlockIndex* pindexPrevNew = pindexBest;
2252         nStart = GetTime();
2253
2254         // Create new block
2255         if(pblock)
2256         {
2257             delete pblock;
2258             pblock = NULL;
2259         }
2260         pblock = CreateNewBlock(pwalletMain);
2261         if (!pblock)
2262             throw JSONRPCError(-7, "Out of memory");
2263
2264         // Need to update only after we know CreateNewBlock succeeded
2265         pindexPrev = pindexPrevNew;
2266     }
2267
2268     // Update nTime
2269     pblock->UpdateTime(pindexPrev);
2270     pblock->nNonce = 0;
2271
2272     Array transactions;
2273     map<uint256, int64_t> setTxIndex;
2274     int i = 0;
2275     CTxDB txdb("r");
2276     BOOST_FOREACH (CTransaction& tx, pblock->vtx)
2277     {
2278         uint256 txHash = tx.GetHash();
2279         setTxIndex[txHash] = i++;
2280
2281         if (tx.IsCoinBase() || tx.IsCoinStake())
2282             continue;
2283
2284         Object entry;
2285
2286         CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
2287         ssTx << tx;
2288         entry.push_back(Pair("data", HexStr(ssTx.begin(), ssTx.end())));
2289
2290         entry.push_back(Pair("hash", txHash.GetHex()));
2291
2292         MapPrevTx mapInputs;
2293         map<uint256, CTxIndex> mapUnused;
2294         bool fInvalid = false;
2295         if (tx.FetchInputs(txdb, mapUnused, false, false, mapInputs, fInvalid))
2296         {
2297             entry.push_back(Pair("fee", (int64_t)(tx.GetValueIn(mapInputs) - tx.GetValueOut())));
2298
2299             Array deps;
2300             BOOST_FOREACH (MapPrevTx::value_type& inp, mapInputs)
2301             {
2302                 if (setTxIndex.count(inp.first))
2303                     deps.push_back(setTxIndex[inp.first]);
2304             }
2305             entry.push_back(Pair("depends", deps));
2306
2307             int64_t nSigOps = tx.GetLegacySigOpCount();
2308             nSigOps += tx.GetP2SHSigOpCount(mapInputs);
2309             entry.push_back(Pair("sigops", nSigOps));
2310         }
2311
2312         transactions.push_back(entry);
2313     }
2314
2315     Object aux;
2316     aux.push_back(Pair("flags", HexStr(COINBASE_FLAGS.begin(), COINBASE_FLAGS.end())));
2317
2318     uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
2319
2320     static Array aMutable;
2321     if (aMutable.empty())
2322     {
2323         aMutable.push_back("time");
2324         aMutable.push_back("transactions");
2325         aMutable.push_back("prevblock");
2326     }
2327
2328     Object result;
2329     result.push_back(Pair("version", pblock->nVersion));
2330     result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex()));
2331     result.push_back(Pair("transactions", transactions));
2332     result.push_back(Pair("coinbaseaux", aux));
2333     result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue));
2334     result.push_back(Pair("target", hashTarget.GetHex()));
2335     result.push_back(Pair("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1));
2336     result.push_back(Pair("mutable", aMutable));
2337     result.push_back(Pair("noncerange", "00000000ffffffff"));
2338     result.push_back(Pair("sigoplimit", (int64_t)MAX_BLOCK_SIGOPS));
2339     result.push_back(Pair("sizelimit", (int64_t)MAX_BLOCK_SIZE));
2340     result.push_back(Pair("curtime", (int64_t)pblock->nTime));
2341     result.push_back(Pair("bits", HexBits(pblock->nBits)));
2342     result.push_back(Pair("height", (int64_t)(pindexPrev->nHeight+1)));
2343
2344     return result;
2345 }
2346
2347 Value submitblock(const Array& params, bool fHelp)
2348 {
2349     if (fHelp || params.size() < 1 || params.size() > 2)
2350         throw runtime_error(
2351             "submitblock <hex data> [optional-params-obj]\n"
2352             "[optional-params-obj] parameter is currently ignored.\n"
2353             "Attempts to submit new block to network.\n"
2354             "See https://en.bitcoin.it/wiki/BIP_0022 for full specification.");
2355
2356     vector<unsigned char> blockData(ParseHex(params[0].get_str()));
2357     CDataStream ssBlock(blockData, SER_NETWORK, PROTOCOL_VERSION);
2358     CBlock block;
2359     try {
2360         ssBlock >> block;
2361     }
2362     catch (std::exception &e) {
2363         throw JSONRPCError(-22, "Block decode failed");
2364     }
2365
2366     static CReserveKey reservekey(pwalletMain);
2367
2368     if(!block.SignBlock(*pwalletMain))
2369         throw JSONRPCError(-100, "Unable to sign block, wallet locked?");
2370
2371     bool fAccepted = CheckWork(&block, *pwalletMain, reservekey);
2372     if (!fAccepted)
2373         return "rejected";
2374
2375     return Value::null;
2376 }
2377
2378
2379 Value getmemorypool(const Array& params, bool fHelp)
2380 {
2381     if (fHelp || params.size() > 1)
2382         throw runtime_error(
2383             "getmemorypool [data]\n"
2384             "If [data] is not specified, returns data needed to construct a block to work on:\n"
2385             "  \"version\" : block version\n"
2386             "  \"previousblockhash\" : hash of current highest block\n"
2387             "  \"transactions\" : contents of non-coinbase transactions that should be included in the next block\n"
2388             "  \"coinbasevalue\" : maximum allowable input to coinbase transaction, including the generation award and transaction fees\n"
2389             "  \"coinbaseflags\" : data that should be included in coinbase so support for new features can be judged\n"
2390             "  \"time\" : timestamp appropriate for next block\n"
2391             "  \"mintime\" : minimum timestamp appropriate for next block\n"
2392             "  \"curtime\" : current timestamp\n"
2393             "  \"bits\" : compressed target of next block\n"
2394             "If [data] is specified, tries to solve the block and returns true if it was successful.");
2395
2396     if (params.size() == 0)
2397     {
2398         if (vNodes.empty())
2399             throw JSONRPCError(-9, "NovaCoin is not connected!");
2400
2401         if (IsInitialBlockDownload())
2402             throw JSONRPCError(-10, "NovaCoin is downloading blocks...");
2403
2404         static CReserveKey reservekey(pwalletMain);
2405
2406         // Update block
2407         static unsigned int nTransactionsUpdatedLast;
2408         static CBlockIndex* pindexPrev;
2409         static int64 nStart;
2410         static CBlock* pblock;
2411         if (pindexPrev != pindexBest ||
2412             (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 5))
2413         {
2414             nTransactionsUpdatedLast = nTransactionsUpdated;
2415             pindexPrev = pindexBest;
2416             nStart = GetTime();
2417
2418             // Create new block
2419             if(pblock)
2420                 delete pblock;
2421             pblock = CreateNewBlock(pwalletMain);
2422             if (!pblock)
2423                 throw JSONRPCError(-7, "Out of memory");
2424         }
2425
2426         // Update nTime
2427         pblock->UpdateTime(pindexPrev);
2428         pblock->nNonce = 0;
2429
2430         Array transactions;
2431         BOOST_FOREACH(CTransaction tx, pblock->vtx) {
2432             if(tx.IsCoinBase() || tx.IsCoinStake())
2433                 continue;
2434
2435             CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
2436             ssTx << tx;
2437
2438             transactions.push_back(HexStr(ssTx.begin(), ssTx.end()));
2439         }
2440
2441         Object result;
2442         result.push_back(Pair("version", pblock->nVersion));
2443         result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex()));
2444         result.push_back(Pair("transactions", transactions));
2445         result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue));
2446         result.push_back(Pair("coinbaseflags", HexStr(COINBASE_FLAGS.begin(), COINBASE_FLAGS.end())));
2447         result.push_back(Pair("time", (int64_t)pblock->nTime));
2448         result.push_back(Pair("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1));
2449         result.push_back(Pair("curtime", (int64_t)GetAdjustedTime()));
2450         result.push_back(Pair("bits", HexBits(pblock->nBits)));
2451
2452         return result;
2453     }
2454     else
2455     {
2456         // Parse parameters
2457         CDataStream ssBlock(ParseHex(params[0].get_str()), SER_NETWORK, PROTOCOL_VERSION);
2458         CBlock pblock;
2459         ssBlock >> pblock;
2460
2461         static CReserveKey reservekey(pwalletMain);
2462
2463         if(!pblock.SignBlock(*pwalletMain))
2464             throw JSONRPCError(-100, "Unable to sign block, wallet locked?");
2465
2466         return CheckWork(&pblock, *pwalletMain, reservekey);
2467     }
2468 }
2469
2470 Value getnewpubkey(const Array& params, bool fHelp)
2471 {
2472     if (fHelp || params.size() > 1)
2473         throw runtime_error(
2474             "getnewpubkey [account]\n"
2475             "Returns new public key for coinbase generation.");
2476
2477     // Parse the account first so we don't generate a key if there's an error
2478     string strAccount;
2479     if (params.size() > 0)
2480         strAccount = AccountFromValue(params[0]);
2481
2482     if (!pwalletMain->IsLocked())
2483         pwalletMain->TopUpKeyPool();
2484
2485     // Generate a new key that is added to wallet
2486     std::vector<unsigned char> newKey = pwalletMain->GenerateNewKey(false);
2487
2488     if(!newKey.size())
2489         throw JSONRPCError(-12, "Error: Unable to create key");
2490
2491     CBitcoinAddress address(newKey);
2492     pwalletMain->SetAddressBookName(address, strAccount);
2493
2494     return HexStr(newKey.begin(), newKey.end());
2495 }
2496
2497 Value getblockhash(const Array& params, bool fHelp)
2498 {
2499     if (fHelp || params.size() != 1)
2500         throw runtime_error(
2501             "getblockhash <index>\n"
2502             "Returns hash of block in best-block-chain at <index>.");
2503
2504     int nHeight = params[0].get_int();
2505     if (nHeight < 0 || nHeight > nBestHeight)
2506         throw runtime_error("Block number out of range.");
2507
2508     CBlock block;
2509     CBlockIndex* pblockindex = mapBlockIndex[hashBestChain];
2510     while (pblockindex->nHeight > nHeight)
2511         pblockindex = pblockindex->pprev;
2512     return pblockindex->phashBlock->GetHex();
2513 }
2514
2515 Value getblock(const Array& params, bool fHelp)
2516 {
2517     if (fHelp || params.size() < 1 || params.size() > 2)
2518         throw runtime_error(
2519             "getblock <hash> [txinfo]\n"
2520             "txinfo optional to print more detailed tx info\n"
2521             "Returns details of a block with given block-hash.");
2522
2523     std::string strHash = params[0].get_str();
2524     uint256 hash(strHash);
2525
2526     if (mapBlockIndex.count(hash) == 0)
2527         throw JSONRPCError(-5, "Block not found");
2528
2529     CBlock block;
2530     CBlockIndex* pblockindex = mapBlockIndex[hash];
2531     block.ReadFromDisk(pblockindex, true);
2532
2533     return blockToJSON(block, pblockindex, params.size() > 1 ? params[1].get_bool() : false);
2534 }
2535
2536 Value getblockbynumber(const Array& params, bool fHelp)
2537 {
2538     if (fHelp || params.size() < 1 || params.size() > 2)
2539         throw runtime_error(
2540             "getblock <number> [txinfo]\n"
2541             "txinfo optional to print more detailed tx info\n"
2542             "Returns details of a block with given block-number.");
2543
2544     int nHeight = params[0].get_int();
2545     if (nHeight < 0 || nHeight > nBestHeight)
2546         throw runtime_error("Block number out of range.");
2547
2548     CBlock block;
2549     CBlockIndex* pblockindex = mapBlockIndex[hashBestChain];
2550     while (pblockindex->nHeight > nHeight)
2551         pblockindex = pblockindex->pprev;
2552
2553     uint256 hash = *pblockindex->phashBlock;
2554
2555     pblockindex = mapBlockIndex[hash];
2556     block.ReadFromDisk(pblockindex, true);
2557
2558     return blockToJSON(block, pblockindex, params.size() > 1 ? params[1].get_bool() : false);
2559 }
2560
2561 // ppcoin: get information of sync-checkpoint
2562 Value getcheckpoint(const Array& params, bool fHelp)
2563 {
2564     if (fHelp || params.size() != 0)
2565         throw runtime_error(
2566             "getcheckpoint\n"
2567             "Show info of synchronized checkpoint.\n");
2568
2569     Object result;
2570     CBlockIndex* pindexCheckpoint;
2571     
2572     result.push_back(Pair("synccheckpoint", Checkpoints::hashSyncCheckpoint.ToString().c_str()));
2573     pindexCheckpoint = mapBlockIndex[Checkpoints::hashSyncCheckpoint];        
2574     result.push_back(Pair("height", pindexCheckpoint->nHeight));
2575     result.push_back(Pair("timestamp", DateTimeStrFormat(pindexCheckpoint->GetBlockTime()).c_str()));
2576     if (mapArgs.count("-checkpointkey"))
2577         result.push_back(Pair("checkpointmaster", true));
2578
2579     return result;
2580 }
2581
2582
2583 // ppcoin: reserve balance from being staked for network protection
2584 Value reservebalance(const Array& params, bool fHelp)
2585 {
2586     if (fHelp || params.size() > 2)
2587         throw runtime_error(
2588             "reservebalance [<reserve> [amount]]\n"
2589             "<reserve> is true or false to turn balance reserve on or off.\n"
2590             "<amount> is a real and rounded to cent.\n"
2591             "Set reserve amount not participating in network protection.\n"
2592             "If no parameters provided current setting is printed.\n");
2593
2594     if (params.size() > 0)
2595     {
2596         bool fReserve = params[0].get_bool();
2597         if (fReserve)
2598         {
2599             if (params.size() == 1)
2600                 throw runtime_error("must provide amount to reserve balance.\n");
2601             int64 nAmount = AmountFromValue(params[1]);
2602             nAmount = (nAmount / CENT) * CENT;  // round to cent
2603             if (nAmount < 0)
2604                 throw runtime_error("amount cannot be negative.\n");
2605             mapArgs["-reservebalance"] = FormatMoney(nAmount).c_str();
2606         }
2607         else
2608         {
2609             if (params.size() > 1)
2610                 throw runtime_error("cannot specify amount to turn off reserve.\n");
2611             mapArgs["-reservebalance"] = "0";
2612         }
2613     }
2614
2615     Object result;
2616     int64 nReserveBalance = 0;
2617     if (mapArgs.count("-reservebalance") && !ParseMoney(mapArgs["-reservebalance"], nReserveBalance))
2618         throw runtime_error("invalid reserve balance amount\n");
2619     result.push_back(Pair("reserve", (nReserveBalance > 0)));
2620     result.push_back(Pair("amount", ValueFromAmount(nReserveBalance)));
2621     return result;
2622 }
2623
2624
2625 // ppcoin: check wallet integrity
2626 Value checkwallet(const Array& params, bool fHelp)
2627 {
2628     if (fHelp || params.size() > 0)
2629         throw runtime_error(
2630             "checkwallet\n"
2631             "Check wallet for integrity.\n");
2632
2633     int nMismatchSpent;
2634     int64 nBalanceInQuestion;
2635     pwalletMain->FixSpentCoins(nMismatchSpent, nBalanceInQuestion, true);
2636     Object result;
2637     if (nMismatchSpent == 0)
2638         result.push_back(Pair("wallet check passed", true));
2639     else
2640     {
2641         result.push_back(Pair("mismatched spent coins", nMismatchSpent));
2642         result.push_back(Pair("amount in question", ValueFromAmount(nBalanceInQuestion)));
2643     }
2644     return result;
2645 }
2646
2647
2648 // ppcoin: repair wallet
2649 Value repairwallet(const Array& params, bool fHelp)
2650 {
2651     if (fHelp || params.size() > 0)
2652         throw runtime_error(
2653             "repairwallet\n"
2654             "Repair wallet if checkwallet reports any problem.\n");
2655
2656     int nMismatchSpent;
2657     int64 nBalanceInQuestion;
2658     pwalletMain->FixSpentCoins(nMismatchSpent, nBalanceInQuestion);
2659     Object result;
2660     if (nMismatchSpent == 0)
2661         result.push_back(Pair("wallet check passed", true));
2662     else
2663     {
2664         result.push_back(Pair("mismatched spent coins", nMismatchSpent));
2665         result.push_back(Pair("amount affected by repair", ValueFromAmount(nBalanceInQuestion)));
2666     }
2667     return result;
2668 }
2669
2670 // NovaCoin: resend unconfirmed wallet transactions
2671 Value resendtx(const Array& params, bool fHelp)
2672 {
2673     if (fHelp || params.size() > 1)
2674         throw runtime_error(
2675             "resendtx\n"
2676             "Re-send unconfirmed transactions.\n"
2677         );
2678
2679     ResendWalletTransactions();
2680
2681     return Value::null;
2682 }
2683
2684
2685 // ppcoin: make a public-private key pair
2686 Value makekeypair(const Array& params, bool fHelp)
2687 {
2688     if (fHelp || params.size() > 1)
2689         throw runtime_error(
2690             "makekeypair [prefix]\n"
2691             "Make a public/private key pair.\n"
2692             "[prefix] is optional preferred prefix for the public key.\n");
2693
2694     string strPrefix = "";
2695     if (params.size() > 0)
2696         strPrefix = params[0].get_str();
2697  
2698     CKey key;
2699     int nCount = 0;
2700     do
2701     {
2702         key.MakeNewKey(false);
2703         nCount++;
2704     } while (nCount < 10000 && strPrefix != HexStr(key.GetPubKey()).substr(0, strPrefix.size()));
2705
2706     if (strPrefix != HexStr(key.GetPubKey()).substr(0, strPrefix.size()))
2707         return Value::null;
2708
2709     CPrivKey vchPrivKey = key.GetPrivKey();
2710     Object result;
2711     result.push_back(Pair("PrivateKey", HexStr<CPrivKey::iterator>(vchPrivKey.begin(), vchPrivKey.end())));
2712     result.push_back(Pair("PublicKey", HexStr(key.GetPubKey())));
2713     return result;
2714 }
2715
2716 extern CCriticalSection cs_mapAlerts;
2717 extern map<uint256, CAlert> mapAlerts;
2718
2719 // ppcoin: send alert.  
2720 // There is a known deadlock situation with ThreadMessageHandler
2721 // ThreadMessageHandler: holds cs_vSend and acquiring cs_main in SendMessages()
2722 // ThreadRPCServer: holds cs_main and acquiring cs_vSend in alert.RelayTo()/PushMessage()/BeginMessage()
2723 Value sendalert(const Array& params, bool fHelp)
2724 {
2725     if (fHelp || params.size() < 6)
2726         throw runtime_error(
2727             "sendalert <message> <privatekey> <minver> <maxver> <priority> <id> [cancelupto]\n"
2728             "<message> is the alert text message\n"
2729             "<privatekey> is hex string of alert master private key\n"
2730             "<minver> is the minimum applicable internal client version\n"
2731             "<maxver> is the maximum applicable internal client version\n"
2732             "<priority> is integer priority number\n"
2733             "<id> is the alert id\n"
2734             "[cancelupto] cancels all alert id's up to this number\n"
2735             "Returns true or false.");
2736
2737     CAlert alert;
2738     CKey key;
2739
2740     alert.strStatusBar = params[0].get_str();
2741     alert.nMinVer = params[2].get_int();
2742     alert.nMaxVer = params[3].get_int();
2743     alert.nPriority = params[4].get_int();
2744     alert.nID = params[5].get_int();
2745     if (params.size() > 6)
2746         alert.nCancel = params[6].get_int();
2747     alert.nVersion = PROTOCOL_VERSION;
2748     alert.nRelayUntil = GetAdjustedTime() + 365*24*60*60;
2749     alert.nExpiration = GetAdjustedTime() + 365*24*60*60;
2750
2751     CDataStream sMsg(SER_NETWORK, PROTOCOL_VERSION);
2752     sMsg << (CUnsignedAlert)alert;
2753     alert.vchMsg = vector<unsigned char>(sMsg.begin(), sMsg.end());
2754     
2755     vector<unsigned char> vchPrivKey = ParseHex(params[1].get_str());
2756     key.SetPrivKey(CPrivKey(vchPrivKey.begin(), vchPrivKey.end())); // if key is not correct openssl may crash
2757     if (!key.Sign(Hash(alert.vchMsg.begin(), alert.vchMsg.end()), alert.vchSig))
2758         throw runtime_error(
2759             "Unable to sign alert, check private key?\n");  
2760     if(!alert.ProcessAlert()) 
2761         throw runtime_error(
2762             "Failed to process alert.\n");
2763     // Relay alert
2764     {
2765         LOCK(cs_vNodes);
2766         BOOST_FOREACH(CNode* pnode, vNodes)
2767             alert.RelayTo(pnode);
2768     }
2769
2770     Object result;
2771     result.push_back(Pair("strStatusBar", alert.strStatusBar));
2772     result.push_back(Pair("nVersion", alert.nVersion));
2773     result.push_back(Pair("nMinVer", alert.nMinVer));
2774     result.push_back(Pair("nMaxVer", alert.nMaxVer));
2775     result.push_back(Pair("nPriority", alert.nPriority));
2776     result.push_back(Pair("nID", alert.nID));
2777     if (alert.nCancel > 0)
2778         result.push_back(Pair("nCancel", alert.nCancel));
2779     return result;
2780 }
2781
2782
2783
2784 //
2785 // Call Table
2786 //
2787
2788
2789 static const CRPCCommand vRPCCommands[] =
2790 { //  name                      function                 safe mode?
2791   //  ------------------------  -----------------------  ----------
2792     { "help",                   &help,                   true },
2793     { "stop",                   &stop,                   true },
2794     { "getblockcount",          &getblockcount,          true },
2795     { "getblocknumber",         &getblocknumber,         true },
2796     { "getconnectioncount",     &getconnectioncount,     true },
2797     { "getdifficulty",          &getdifficulty,          true },
2798     { "getpowreward",           &getpowreward,           true },
2799     { "getgenerate",            &getgenerate,            true },
2800     { "setgenerate",            &setgenerate,            true },
2801     { "gethashespersec",        &gethashespersec,        true },
2802     { "getinfo",                &getinfo,                true },
2803     { "getmininginfo",          &getmininginfo,          true },
2804     { "getnewaddress",          &getnewaddress,          true },
2805     { "getnewpubkey",           &getnewpubkey,           true },
2806     { "getaccountaddress",      &getaccountaddress,      true },
2807     { "setaccount",             &setaccount,             true },
2808     { "getaccount",             &getaccount,             false },
2809     { "getaddressesbyaccount",  &getaddressesbyaccount,  true },
2810     { "sendtoaddress",          &sendtoaddress,          false },
2811     { "getreceivedbyaddress",   &getreceivedbyaddress,   false },
2812     { "getreceivedbyaccount",   &getreceivedbyaccount,   false },
2813     { "listreceivedbyaddress",  &listreceivedbyaddress,  false },
2814     { "listreceivedbyaccount",  &listreceivedbyaccount,  false },
2815     { "backupwallet",           &backupwallet,           true },
2816     { "keypoolrefill",          &keypoolrefill,          true },
2817     { "walletpassphrase",       &walletpassphrase,       true },
2818     { "walletpassphrasechange", &walletpassphrasechange, false },
2819     { "walletlock",             &walletlock,             true },
2820     { "encryptwallet",          &encryptwallet,          false },
2821     { "validateaddress",        &validateaddress,        true },
2822     { "validatepubkey",         &validatepubkey,         true },
2823     { "getbalance",             &getbalance,             false },
2824     { "move",                   &movecmd,                false },
2825     { "sendfrom",               &sendfrom,               false },
2826     { "sendmany",               &sendmany,               false },
2827     { "addmultisigaddress",     &addmultisigaddress,     false },
2828     { "getblock",               &getblock,               false },
2829     { "getblockhash",           &getblockhash,           false },
2830     { "getblockbynumber",       &getblockbynumber,       false },
2831     { "gettransaction",         &gettransaction,         false },
2832     { "listtransactions",       &listtransactions,       false },
2833     { "signmessage",            &signmessage,            false },
2834     { "verifymessage",          &verifymessage,          false },
2835     { "getwork",                &getwork,                true },
2836     { "getworkex",              &getworkex,                true },
2837     { "listaccounts",           &listaccounts,           false },
2838     { "settxfee",               &settxfee,               false },
2839     { "getmemorypool",          &getmemorypool,          true },
2840     { "getblocktemplate",       &getblocktemplate,       true },
2841     { "submitblock",            &submitblock,            false },
2842     { "listsinceblock",         &listsinceblock,         false },
2843     { "dumpprivkey",            &dumpprivkey,            false },
2844     { "importprivkey",          &importprivkey,          false },
2845     { "getcheckpoint",          &getcheckpoint,          true },
2846     { "reservebalance",         &reservebalance,         false},
2847     { "checkwallet",            &checkwallet,            false},
2848     { "repairwallet",           &repairwallet,           false},
2849     { "resendtx",               &resendtx,               false},
2850     { "makekeypair",            &makekeypair,            false},
2851     { "sendalert",              &sendalert,              false},
2852 };
2853
2854 CRPCTable::CRPCTable()
2855 {
2856     unsigned int vcidx;
2857     for (vcidx = 0; vcidx < (sizeof(vRPCCommands) / sizeof(vRPCCommands[0])); vcidx++)
2858     {
2859         const CRPCCommand *pcmd;
2860
2861         pcmd = &vRPCCommands[vcidx];
2862         mapCommands[pcmd->name] = pcmd;
2863     }
2864 }
2865
2866 const CRPCCommand *CRPCTable::operator[](string name) const
2867 {
2868     map<string, const CRPCCommand*>::const_iterator it = mapCommands.find(name);
2869     if (it == mapCommands.end())
2870         return NULL;
2871     return (*it).second;
2872 }
2873
2874 //
2875 // HTTP protocol
2876 //
2877 // This ain't Apache.  We're just using HTTP header for the length field
2878 // and to be compatible with other JSON-RPC implementations.
2879 //
2880
2881 string HTTPPost(const string& strMsg, const map<string,string>& mapRequestHeaders)
2882 {
2883     ostringstream s;
2884     s << "POST / HTTP/1.1\r\n"
2885       << "User-Agent: novacoin-json-rpc/" << FormatFullVersion() << "\r\n"
2886       << "Host: 127.0.0.1\r\n"
2887       << "Content-Type: application/json\r\n"
2888       << "Content-Length: " << strMsg.size() << "\r\n"
2889       << "Connection: close\r\n"
2890       << "Accept: application/json\r\n";
2891     BOOST_FOREACH(const PAIRTYPE(string, string)& item, mapRequestHeaders)
2892         s << item.first << ": " << item.second << "\r\n";
2893     s << "\r\n" << strMsg;
2894
2895     return s.str();
2896 }
2897
2898 string rfc1123Time()
2899 {
2900     char buffer[64];
2901     time_t now;
2902     time(&now);
2903     struct tm* now_gmt = gmtime(&now);
2904     string locale(setlocale(LC_TIME, NULL));
2905     setlocale(LC_TIME, "C"); // we want posix (aka "C") weekday/month strings
2906     strftime(buffer, sizeof(buffer), "%a, %d %b %Y %H:%M:%S +0000", now_gmt);
2907     setlocale(LC_TIME, locale.c_str());
2908     return string(buffer);
2909 }
2910
2911 static string HTTPReply(int nStatus, const string& strMsg)
2912 {
2913     if (nStatus == 401)
2914         return strprintf("HTTP/1.0 401 Authorization Required\r\n"
2915             "Date: %s\r\n"
2916             "Server: novacoin-json-rpc/%s\r\n"
2917             "WWW-Authenticate: Basic realm=\"jsonrpc\"\r\n"
2918             "Content-Type: text/html\r\n"
2919             "Content-Length: 296\r\n"
2920             "\r\n"
2921             "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\r\n"
2922             "\"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd\">\r\n"
2923             "<HTML>\r\n"
2924             "<HEAD>\r\n"
2925             "<TITLE>Error</TITLE>\r\n"
2926             "<META HTTP-EQUIV='Content-Type' CONTENT='text/html; charset=ISO-8859-1'>\r\n"
2927             "</HEAD>\r\n"
2928             "<BODY><H1>401 Unauthorized.</H1></BODY>\r\n"
2929             "</HTML>\r\n", rfc1123Time().c_str(), FormatFullVersion().c_str());
2930     const char *cStatus;
2931          if (nStatus == 200) cStatus = "OK";
2932     else if (nStatus == 400) cStatus = "Bad Request";
2933     else if (nStatus == 403) cStatus = "Forbidden";
2934     else if (nStatus == 404) cStatus = "Not Found";
2935     else if (nStatus == 500) cStatus = "Internal Server Error";
2936     else cStatus = "";
2937     return strprintf(
2938             "HTTP/1.1 %d %s\r\n"
2939             "Date: %s\r\n"
2940             "Connection: close\r\n"
2941             "Content-Length: %d\r\n"
2942             "Content-Type: application/json\r\n"
2943             "Server: novacoin-json-rpc/%s\r\n"
2944             "\r\n"
2945             "%s",
2946         nStatus,
2947         cStatus,
2948         rfc1123Time().c_str(),
2949         strMsg.size(),
2950         FormatFullVersion().c_str(),
2951         strMsg.c_str());
2952 }
2953
2954 int ReadHTTPStatus(std::basic_istream<char>& stream)
2955 {
2956     string str;
2957     getline(stream, str);
2958     vector<string> vWords;
2959     boost::split(vWords, str, boost::is_any_of(" "));
2960     if (vWords.size() < 2)
2961         return 500;
2962     return atoi(vWords[1].c_str());
2963 }
2964
2965 int ReadHTTPHeader(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet)
2966 {
2967     int nLen = 0;
2968     loop
2969     {
2970         string str;
2971         std::getline(stream, str);
2972         if (str.empty() || str == "\r")
2973             break;
2974         string::size_type nColon = str.find(":");
2975         if (nColon != string::npos)
2976         {
2977             string strHeader = str.substr(0, nColon);
2978             boost::trim(strHeader);
2979             boost::to_lower(strHeader);
2980             string strValue = str.substr(nColon+1);
2981             boost::trim(strValue);
2982             mapHeadersRet[strHeader] = strValue;
2983             if (strHeader == "content-length")
2984                 nLen = atoi(strValue.c_str());
2985         }
2986     }
2987     return nLen;
2988 }
2989
2990 int ReadHTTP(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet, string& strMessageRet)
2991 {
2992     mapHeadersRet.clear();
2993     strMessageRet = "";
2994
2995     // Read status
2996     int nStatus = ReadHTTPStatus(stream);
2997
2998     // Read header
2999     int nLen = ReadHTTPHeader(stream, mapHeadersRet);
3000     if (nLen < 0 || nLen > (int)MAX_SIZE)
3001         return 500;
3002
3003     // Read message
3004     if (nLen > 0)
3005     {
3006         vector<char> vch(nLen);
3007         stream.read(&vch[0], nLen);
3008         strMessageRet = string(vch.begin(), vch.end());
3009     }
3010
3011     return nStatus;
3012 }
3013
3014 bool HTTPAuthorized(map<string, string>& mapHeaders)
3015 {
3016     string strAuth = mapHeaders["authorization"];
3017     if (strAuth.substr(0,6) != "Basic ")
3018         return false;
3019     string strUserPass64 = strAuth.substr(6); boost::trim(strUserPass64);
3020     string strUserPass = DecodeBase64(strUserPass64);
3021     return strUserPass == strRPCUserColonPass;
3022 }
3023
3024 //
3025 // JSON-RPC protocol.  Bitcoin speaks version 1.0 for maximum compatibility,
3026 // but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
3027 // unspecified (HTTP errors and contents of 'error').
3028 //
3029 // 1.0 spec: http://json-rpc.org/wiki/specification
3030 // 1.2 spec: http://groups.google.com/group/json-rpc/web/json-rpc-over-http
3031 // http://www.codeproject.com/KB/recipes/JSON_Spirit.aspx
3032 //
3033
3034 string JSONRPCRequest(const string& strMethod, const Array& params, const Value& id)
3035 {
3036     Object request;
3037     request.push_back(Pair("method", strMethod));
3038     request.push_back(Pair("params", params));
3039     request.push_back(Pair("id", id));
3040     return write_string(Value(request), false) + "\n";
3041 }
3042
3043 string JSONRPCReply(const Value& result, const Value& error, const Value& id)
3044 {
3045     Object reply;
3046     if (error.type() != null_type)
3047         reply.push_back(Pair("result", Value::null));
3048     else
3049         reply.push_back(Pair("result", result));
3050     reply.push_back(Pair("error", error));
3051     reply.push_back(Pair("id", id));
3052     return write_string(Value(reply), false) + "\n";
3053 }
3054
3055 void ErrorReply(std::ostream& stream, const Object& objError, const Value& id)
3056 {
3057     // Send error reply from json-rpc error object
3058     int nStatus = 500;
3059     int code = find_value(objError, "code").get_int();
3060     if (code == -32600) nStatus = 400;
3061     else if (code == -32601) nStatus = 404;
3062     string strReply = JSONRPCReply(Value::null, objError, id);
3063     stream << HTTPReply(nStatus, strReply) << std::flush;
3064 }
3065
3066 bool ClientAllowed(const string& strAddress)
3067 {
3068     if (strAddress == asio::ip::address_v4::loopback().to_string())
3069         return true;
3070     const vector<string>& vAllow = mapMultiArgs["-rpcallowip"];
3071     BOOST_FOREACH(string strAllow, vAllow)
3072         if (WildcardMatch(strAddress, strAllow))
3073             return true;
3074     return false;
3075 }
3076
3077 //
3078 // IOStream device that speaks SSL but can also speak non-SSL
3079 //
3080 class SSLIOStreamDevice : public iostreams::device<iostreams::bidirectional> {
3081 public:
3082     SSLIOStreamDevice(SSLStream &streamIn, bool fUseSSLIn) : stream(streamIn)
3083     {
3084         fUseSSL = fUseSSLIn;
3085         fNeedHandshake = fUseSSLIn;
3086     }
3087
3088     void handshake(ssl::stream_base::handshake_type role)
3089     {
3090         if (!fNeedHandshake) return;
3091         fNeedHandshake = false;
3092         stream.handshake(role);
3093     }
3094     std::streamsize read(char* s, std::streamsize n)
3095     {
3096         handshake(ssl::stream_base::server); // HTTPS servers read first
3097         if (fUseSSL) return stream.read_some(asio::buffer(s, n));
3098         return stream.next_layer().read_some(asio::buffer(s, n));
3099     }
3100     std::streamsize write(const char* s, std::streamsize n)
3101     {
3102         handshake(ssl::stream_base::client); // HTTPS clients write first
3103         if (fUseSSL) return asio::write(stream, asio::buffer(s, n));
3104         return asio::write(stream.next_layer(), asio::buffer(s, n));
3105     }
3106     bool connect(const std::string& server, const std::string& port)
3107     {
3108         ip::tcp::resolver resolver(stream.get_io_service());
3109         ip::tcp::resolver::query query(server.c_str(), port.c_str());
3110         ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
3111         ip::tcp::resolver::iterator end;
3112         boost::system::error_code error = asio::error::host_not_found;
3113         while (error && endpoint_iterator != end)
3114         {
3115             stream.lowest_layer().close();
3116             stream.lowest_layer().connect(*endpoint_iterator++, error);
3117         }
3118         if (error)
3119             return false;
3120         return true;
3121     }
3122
3123 private:
3124     bool fNeedHandshake;
3125     bool fUseSSL;
3126     SSLStream& stream;
3127 };
3128
3129 void ThreadRPCServer(void* parg)
3130 {
3131     IMPLEMENT_RANDOMIZE_STACK(ThreadRPCServer(parg));
3132     try
3133     {
3134         vnThreadsRunning[THREAD_RPCSERVER]++;
3135         ThreadRPCServer2(parg);
3136         vnThreadsRunning[THREAD_RPCSERVER]--;
3137     }
3138     catch (std::exception& e) {
3139         vnThreadsRunning[THREAD_RPCSERVER]--;
3140         PrintException(&e, "ThreadRPCServer()");
3141     } catch (...) {
3142         vnThreadsRunning[THREAD_RPCSERVER]--;
3143         PrintException(NULL, "ThreadRPCServer()");
3144     }
3145     printf("ThreadRPCServer exiting\n");
3146 }
3147
3148 void ThreadRPCServer2(void* parg)
3149 {
3150     printf("ThreadRPCServer started\n");
3151
3152     strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"];
3153     if (mapArgs["-rpcpassword"] == "")
3154     {
3155         unsigned char rand_pwd[32];
3156         RAND_bytes(rand_pwd, 32);
3157         string strWhatAmI = "To use novacoind";
3158         if (mapArgs.count("-server"))
3159             strWhatAmI = strprintf(_("To use the %s option"), "\"-server\"");
3160         else if (mapArgs.count("-daemon"))
3161             strWhatAmI = strprintf(_("To use the %s option"), "\"-daemon\"");
3162         ThreadSafeMessageBox(strprintf(
3163             _("%s, you must set a rpcpassword in the configuration file:\n %s\n"
3164               "It is recommended you use the following random password:\n"
3165               "rpcuser=novarpc\n"
3166               "rpcpassword=%s\n"
3167               "(you do not need to remember this password)\n"
3168               "If the file does not exist, create it with owner-readable-only file permissions.\n"),
3169                 strWhatAmI.c_str(),
3170                 GetConfigFile().string().c_str(),
3171                 EncodeBase58(&rand_pwd[0],&rand_pwd[0]+32).c_str()),
3172             _("Error"), wxOK | wxMODAL);
3173         StartShutdown();
3174         return;
3175     }
3176
3177     bool fUseSSL = GetBoolArg("-rpcssl");
3178     asio::ip::address bindAddress = mapArgs.count("-rpcallowip") ? asio::ip::address_v4::any() : asio::ip::address_v4::loopback();
3179
3180     asio::io_service io_service;
3181     ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", RPC_PORT));
3182     ip::tcp::acceptor acceptor(io_service);
3183     try
3184     {
3185         acceptor.open(endpoint.protocol());
3186         acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
3187         acceptor.bind(endpoint);
3188         acceptor.listen(socket_base::max_connections);
3189     }
3190     catch(boost::system::system_error &e)
3191     {
3192         ThreadSafeMessageBox(strprintf(_("An error occured while setting up the RPC port %i for listening: %s"), endpoint.port(), e.what()),
3193                              _("Error"), wxOK | wxMODAL);
3194         StartShutdown();
3195         return;
3196     }
3197
3198     ssl::context context(io_service, ssl::context::sslv23);
3199     if (fUseSSL)
3200     {
3201         context.set_options(ssl::context::no_sslv2);
3202
3203         filesystem::path pathCertFile(GetArg("-rpcsslcertificatechainfile", "server.cert"));
3204         if (!pathCertFile.is_complete()) pathCertFile = filesystem::path(GetDataDir()) / pathCertFile;
3205         if (filesystem::exists(pathCertFile)) context.use_certificate_chain_file(pathCertFile.string());
3206         else printf("ThreadRPCServer ERROR: missing server certificate file %s\n", pathCertFile.string().c_str());
3207
3208         filesystem::path pathPKFile(GetArg("-rpcsslprivatekeyfile", "server.pem"));
3209         if (!pathPKFile.is_complete()) pathPKFile = filesystem::path(GetDataDir()) / pathPKFile;
3210         if (filesystem::exists(pathPKFile)) context.use_private_key_file(pathPKFile.string(), ssl::context::pem);
3211         else printf("ThreadRPCServer ERROR: missing server private key file %s\n", pathPKFile.string().c_str());
3212
3213         string strCiphers = GetArg("-rpcsslciphers", "TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH");
3214         SSL_CTX_set_cipher_list(context.impl(), strCiphers.c_str());
3215     }
3216
3217     loop
3218     {
3219         // Accept connection
3220         SSLStream sslStream(io_service, context);
3221         SSLIOStreamDevice d(sslStream, fUseSSL);
3222         iostreams::stream<SSLIOStreamDevice> stream(d);
3223
3224         ip::tcp::endpoint peer;
3225         vnThreadsRunning[THREAD_RPCSERVER]--;
3226         acceptor.accept(sslStream.lowest_layer(), peer);
3227         vnThreadsRunning[4]++;
3228         if (fShutdown)
3229             return;
3230
3231         // Restrict callers by IP
3232         if (!ClientAllowed(peer.address().to_string()))
3233         {
3234             // Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake.
3235             if (!fUseSSL)
3236                 stream << HTTPReply(403, "") << std::flush;
3237             continue;
3238         }
3239
3240         map<string, string> mapHeaders;
3241         string strRequest;
3242
3243         boost::thread api_caller(ReadHTTP, boost::ref(stream), boost::ref(mapHeaders), boost::ref(strRequest));
3244         if (!api_caller.timed_join(boost::posix_time::seconds(GetArg("-rpctimeout", 30))))
3245         {   // Timed out:
3246             acceptor.cancel();
3247             printf("ThreadRPCServer ReadHTTP timeout\n");
3248             continue;
3249         }
3250
3251         // Check authorization
3252         if (mapHeaders.count("authorization") == 0)
3253         {
3254             stream << HTTPReply(401, "") << std::flush;
3255             continue;
3256         }
3257         if (!HTTPAuthorized(mapHeaders))
3258         {
3259             printf("ThreadRPCServer incorrect password attempt from %s\n",peer.address().to_string().c_str());
3260             /* Deter brute-forcing short passwords.
3261                If this results in a DOS the user really
3262                shouldn't have their RPC port exposed.*/
3263             if (mapArgs["-rpcpassword"].size() < 20)
3264                 Sleep(250);
3265
3266             stream << HTTPReply(401, "") << std::flush;
3267             continue;
3268         }
3269
3270         Value id = Value::null;
3271         try
3272         {
3273             // Parse request
3274             Value valRequest;
3275             if (!read_string(strRequest, valRequest) || valRequest.type() != obj_type)
3276                 throw JSONRPCError(-32700, "Parse error");
3277             const Object& request = valRequest.get_obj();
3278
3279             // Parse id now so errors from here on will have the id
3280             id = find_value(request, "id");
3281
3282             // Parse method
3283             Value valMethod = find_value(request, "method");
3284             if (valMethod.type() == null_type)
3285                 throw JSONRPCError(-32600, "Missing method");
3286             if (valMethod.type() != str_type)
3287                 throw JSONRPCError(-32600, "Method must be a string");
3288             string strMethod = valMethod.get_str();
3289             if (strMethod != "getwork" && strMethod != "getmemorypool")
3290                 printf("ThreadRPCServer method=%s\n", strMethod.c_str());
3291
3292             // Parse params
3293             Value valParams = find_value(request, "params");
3294             Array params;
3295             if (valParams.type() == array_type)
3296                 params = valParams.get_array();
3297             else if (valParams.type() == null_type)
3298                 params = Array();
3299             else
3300                 throw JSONRPCError(-32600, "Params must be an array");
3301
3302             // Find method
3303             const CRPCCommand *pcmd = tableRPC[strMethod];
3304             if (!pcmd)
3305                 throw JSONRPCError(-32601, "Method not found");
3306
3307             // Observe safe mode
3308             string strWarning = GetWarnings("rpc");
3309             if (strWarning != "" && !GetBoolArg("-disablesafemode") &&
3310                 !pcmd->okSafeMode)
3311                 throw JSONRPCError(-2, string("Safe mode: ") + strWarning);
3312
3313             try
3314             {
3315                 // Execute
3316                 Value result;
3317                 {
3318                     LOCK2(cs_main, pwalletMain->cs_wallet);
3319                     result = pcmd->actor(params, false);
3320                 }
3321
3322                 // Send reply
3323                 string strReply = JSONRPCReply(result, Value::null, id);
3324                 stream << HTTPReply(200, strReply) << std::flush;
3325             }
3326             catch (std::exception& e)
3327             {
3328                 ErrorReply(stream, JSONRPCError(-1, e.what()), id);
3329             }
3330         }
3331         catch (Object& objError)
3332         {
3333             ErrorReply(stream, objError, id);
3334         }
3335         catch (std::exception& e)
3336         {
3337             ErrorReply(stream, JSONRPCError(-32700, e.what()), id);
3338         }
3339     }
3340 }
3341
3342
3343
3344
3345 Object CallRPC(const string& strMethod, const Array& params)
3346 {
3347     if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
3348         throw runtime_error(strprintf(
3349             _("You must set rpcpassword=<password> in the configuration file:\n%s\n"
3350               "If the file does not exist, create it with owner-readable-only file permissions."),
3351                 GetConfigFile().string().c_str()));
3352
3353     // Connect to localhost
3354     bool fUseSSL = GetBoolArg("-rpcssl");
3355     asio::io_service io_service;
3356     ssl::context context(io_service, ssl::context::sslv23);
3357     context.set_options(ssl::context::no_sslv2);
3358     SSLStream sslStream(io_service, context);
3359     SSLIOStreamDevice d(sslStream, fUseSSL);
3360     iostreams::stream<SSLIOStreamDevice> stream(d);
3361     if (!d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", CBigNum(RPC_PORT).ToString().c_str())))
3362         throw runtime_error("couldn't connect to server");
3363
3364     // HTTP basic authentication
3365     string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
3366     map<string, string> mapRequestHeaders;
3367     mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64;
3368
3369     // Send request
3370     string strRequest = JSONRPCRequest(strMethod, params, 1);
3371     string strPost = HTTPPost(strRequest, mapRequestHeaders);
3372     stream << strPost << std::flush;
3373
3374     // Receive reply
3375     map<string, string> mapHeaders;
3376     string strReply;
3377     int nStatus = ReadHTTP(stream, mapHeaders, strReply);
3378     if (nStatus == 401)
3379         throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
3380     else if (nStatus >= 400 && nStatus != 400 && nStatus != 404 && nStatus != 500)
3381         throw runtime_error(strprintf("server returned HTTP error %d", nStatus));
3382     else if (strReply.empty())
3383         throw runtime_error("no response from server");
3384
3385     // Parse reply
3386     Value valReply;
3387     if (!read_string(strReply, valReply))
3388         throw runtime_error("couldn't parse reply from server");
3389     const Object& reply = valReply.get_obj();
3390     if (reply.empty())
3391         throw runtime_error("expected reply to have result, error and id properties");
3392
3393     return reply;
3394 }
3395
3396
3397
3398
3399 template<typename T>
3400 void ConvertTo(Value& value)
3401 {
3402     if (value.type() == str_type)
3403     {
3404         // reinterpret string as unquoted json value
3405         Value value2;
3406         if (!read_string(value.get_str(), value2))
3407             throw runtime_error("type mismatch");
3408         value = value2.get_value<T>();
3409     }
3410     else
3411     {
3412         value = value.get_value<T>();
3413     }
3414 }
3415
3416 int CommandLineRPC(int argc, char *argv[])
3417 {
3418     string strPrint;
3419     int nRet = 0;
3420     try
3421     {
3422         // Skip switches
3423         while (argc > 1 && IsSwitchChar(argv[1][0]))
3424         {
3425             argc--;
3426             argv++;
3427         }
3428
3429         // Method
3430         if (argc < 2)
3431             throw runtime_error("too few parameters");
3432         string strMethod = argv[1];
3433
3434         // Parameters default to strings
3435         Array params;
3436         for (int i = 2; i < argc; i++)
3437             params.push_back(argv[i]);
3438         int n = params.size();
3439
3440         //
3441         // Special case non-string parameter types
3442         //
3443         if (strMethod == "setgenerate"            && n > 0) ConvertTo<bool>(params[0]);
3444         if (strMethod == "setgenerate"            && n > 1) ConvertTo<boost::int64_t>(params[1]);
3445         if (strMethod == "sendtoaddress"          && n > 1) ConvertTo<double>(params[1]);
3446         if (strMethod == "settxfee"               && n > 0) ConvertTo<double>(params[0]);
3447         if (strMethod == "getreceivedbyaddress"   && n > 1) ConvertTo<boost::int64_t>(params[1]);
3448         if (strMethod == "getreceivedbyaccount"   && n > 1) ConvertTo<boost::int64_t>(params[1]);
3449         if (strMethod == "listreceivedbyaddress"  && n > 0) ConvertTo<boost::int64_t>(params[0]);
3450         if (strMethod == "listreceivedbyaddress"  && n > 1) ConvertTo<bool>(params[1]);
3451         if (strMethod == "listreceivedbyaccount"  && n > 0) ConvertTo<boost::int64_t>(params[0]);
3452         if (strMethod == "listreceivedbyaccount"  && n > 1) ConvertTo<bool>(params[1]);
3453         if (strMethod == "getbalance"             && n > 1) ConvertTo<boost::int64_t>(params[1]);
3454         if (strMethod == "getblockhash"           && n > 0) ConvertTo<boost::int64_t>(params[0]);
3455         if (strMethod == "getblockbynumber"       && n > 0) ConvertTo<boost::int64_t>(params[0]);
3456         if (strMethod == "getblockbynumber"       && n > 1) ConvertTo<bool>(params[1]);
3457         if (strMethod == "getblock"               && n > 1) ConvertTo<bool>(params[1]);
3458         if (strMethod == "move"                   && n > 2) ConvertTo<double>(params[2]);
3459         if (strMethod == "move"                   && n > 3) ConvertTo<boost::int64_t>(params[3]);
3460         if (strMethod == "sendfrom"               && n > 2) ConvertTo<double>(params[2]);
3461         if (strMethod == "sendfrom"               && n > 3) ConvertTo<boost::int64_t>(params[3]);
3462         if (strMethod == "listtransactions"       && n > 1) ConvertTo<boost::int64_t>(params[1]);
3463         if (strMethod == "listtransactions"       && n > 2) ConvertTo<boost::int64_t>(params[2]);
3464         if (strMethod == "listaccounts"           && n > 0) ConvertTo<boost::int64_t>(params[0]);
3465         if (strMethod == "walletpassphrase"       && n > 1) ConvertTo<boost::int64_t>(params[1]);
3466         if (strMethod == "walletpassphrase"       && n > 2) ConvertTo<bool>(params[2]);
3467         if (strMethod == "listsinceblock"         && n > 1) ConvertTo<boost::int64_t>(params[1]);
3468         if (strMethod == "sendalert"              && n > 2) ConvertTo<boost::int64_t>(params[2]);
3469         if (strMethod == "sendalert"              && n > 3) ConvertTo<boost::int64_t>(params[3]);
3470         if (strMethod == "sendalert"              && n > 4) ConvertTo<boost::int64_t>(params[4]);
3471         if (strMethod == "sendalert"              && n > 5) ConvertTo<boost::int64_t>(params[5]);
3472         if (strMethod == "sendalert"              && n > 6) ConvertTo<boost::int64_t>(params[6]);
3473         if (strMethod == "sendmany"               && n > 1)
3474         {
3475             string s = params[1].get_str();
3476             Value v;
3477             if (!read_string(s, v) || v.type() != obj_type)
3478                 throw runtime_error("type mismatch");
3479             params[1] = v.get_obj();
3480         }
3481         if (strMethod == "sendmany"                && n > 2) ConvertTo<boost::int64_t>(params[2]);
3482         if (strMethod == "reservebalance"          && n > 0) ConvertTo<bool>(params[0]);
3483         if (strMethod == "reservebalance"          && n > 1) ConvertTo<double>(params[1]);
3484         if (strMethod == "addmultisigaddress"      && n > 0) ConvertTo<boost::int64_t>(params[0]);
3485         if (strMethod == "addmultisigaddress"      && n > 1)
3486         {
3487             string s = params[1].get_str();
3488             Value v;
3489             if (!read_string(s, v) || v.type() != array_type)
3490                 throw runtime_error("type mismatch "+s);
3491             params[1] = v.get_array();
3492         }
3493
3494         // Execute
3495         Object reply = CallRPC(strMethod, params);
3496
3497         // Parse reply
3498         const Value& result = find_value(reply, "result");
3499         const Value& error  = find_value(reply, "error");
3500
3501         if (error.type() != null_type)
3502         {
3503             // Error
3504             strPrint = "error: " + write_string(error, false);
3505             int code = find_value(error.get_obj(), "code").get_int();
3506             nRet = abs(code);
3507         }
3508         else
3509         {
3510             // Result
3511             if (result.type() == null_type)
3512                 strPrint = "";
3513             else if (result.type() == str_type)
3514                 strPrint = result.get_str();
3515             else
3516                 strPrint = write_string(result, true);
3517         }
3518     }
3519     catch (std::exception& e)
3520     {
3521         strPrint = string("error: ") + e.what();
3522         nRet = 87;
3523     }
3524     catch (...)
3525     {
3526         PrintException(NULL, "CommandLineRPC()");
3527     }
3528
3529     if (strPrint != "")
3530     {
3531         fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
3532     }
3533     return nRet;
3534 }
3535
3536
3537
3538
3539 #ifdef TEST
3540 int main(int argc, char *argv[])
3541 {
3542 #ifdef _MSC_VER
3543     // Turn off microsoft heap dump noise
3544     _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
3545     _CrtSetReportFile(_CRT_WARN, CreateFile("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0));
3546 #endif
3547     setbuf(stdin, NULL);
3548     setbuf(stdout, NULL);
3549     setbuf(stderr, NULL);
3550
3551     try
3552     {
3553         if (argc >= 2 && string(argv[1]) == "-server")
3554         {
3555             printf("server ready\n");
3556             ThreadRPCServer(NULL);
3557         }
3558         else
3559         {
3560             return CommandLineRPC(argc, argv);
3561         }
3562     }
3563     catch (std::exception& e) {
3564         PrintException(&e, "main()");
3565     } catch (...) {
3566         PrintException(NULL, "main()");
3567     }
3568     return 0;
3569 }
3570 #endif
3571
3572 const CRPCTable tableRPC;