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