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