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