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