Update to 0.3.0 (New upstream + new RPC calls)
[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 getwork(const Array& params, bool fHelp)
1810 {
1811     if (fHelp || params.size() > 1)
1812         throw runtime_error(
1813             "getwork [data]\n"
1814             "If [data] is not specified, returns formatted hash data to work on:\n"
1815             "  \"midstate\" : precomputed hash state after hashing the first half of the data (DEPRECATED)\n" // deprecated
1816             "  \"data\" : block data\n"
1817             "  \"hash1\" : formatted hash buffer for second hash (DEPRECATED)\n" // deprecated
1818             "  \"target\" : little endian hash target\n"
1819             "If [data] is specified, tries to solve the block and returns true if it was successful.");
1820
1821     if (vNodes.empty())
1822         throw JSONRPCError(-9, "NovaCoin is not connected!");
1823
1824     if (IsInitialBlockDownload())
1825         throw JSONRPCError(-10, "NovaCoin is downloading blocks...");
1826
1827     typedef map<uint256, pair<CBlock*, CScript> > mapNewBlock_t;
1828     static mapNewBlock_t mapNewBlock;
1829     static vector<CBlock*> vNewBlock;
1830     static CReserveKey reservekey(pwalletMain);
1831
1832     if (params.size() == 0)
1833     {
1834         // Update block
1835         static unsigned int nTransactionsUpdatedLast;
1836         static CBlockIndex* pindexPrev;
1837         static int64 nStart;
1838         static CBlock* pblock;
1839         if (pindexPrev != pindexBest ||
1840             (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60))
1841         {
1842             if (pindexPrev != pindexBest)
1843             {
1844                 // Deallocate old blocks since they're obsolete now
1845                 mapNewBlock.clear();
1846                 BOOST_FOREACH(CBlock* pblock, vNewBlock)
1847                     delete pblock;
1848                 vNewBlock.clear();
1849             }
1850             nTransactionsUpdatedLast = nTransactionsUpdated;
1851             pindexPrev = pindexBest;
1852             nStart = GetTime();
1853
1854             // Create new block
1855             pblock = CreateNewBlock(pwalletMain);
1856             if (!pblock)
1857                 throw JSONRPCError(-7, "Out of memory");
1858             vNewBlock.push_back(pblock);
1859         }
1860
1861         // Update nTime
1862         pblock->UpdateTime(pindexPrev);
1863         pblock->nNonce = 0;
1864
1865         // Update nExtraNonce
1866         static unsigned int nExtraNonce = 0;
1867         IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
1868
1869         // Save
1870         mapNewBlock[pblock->hashMerkleRoot] = make_pair(pblock, pblock->vtx[0].vin[0].scriptSig);
1871
1872         // Prebuild hash buffers
1873         char pmidstate[32];
1874         char pdata[128];
1875         char phash1[64];
1876         FormatHashBuffers(pblock, pmidstate, pdata, phash1);
1877
1878         uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
1879
1880         Object result;
1881         result.push_back(Pair("midstate", HexStr(BEGIN(pmidstate), END(pmidstate)))); // deprecated
1882         result.push_back(Pair("data",     HexStr(BEGIN(pdata), END(pdata))));
1883         result.push_back(Pair("hash1",    HexStr(BEGIN(phash1), END(phash1)))); // deprecated
1884         result.push_back(Pair("target",   HexStr(BEGIN(hashTarget), END(hashTarget))));
1885         return result;
1886     }
1887     else
1888     {
1889         // Parse parameters
1890         vector<unsigned char> vchData = ParseHex(params[0].get_str());
1891         if (vchData.size() != 128)
1892             throw JSONRPCError(-8, "Invalid parameter");
1893         CBlock* pdata = (CBlock*)&vchData[0];
1894
1895         // Byte reverse
1896         for (int i = 0; i < 128/4; i++)
1897             ((unsigned int*)pdata)[i] = ByteReverse(((unsigned int*)pdata)[i]);
1898
1899         // Get saved block
1900         if (!mapNewBlock.count(pdata->hashMerkleRoot))
1901             return false;
1902         CBlock* pblock = mapNewBlock[pdata->hashMerkleRoot].first;
1903
1904         pblock->nTime = pdata->nTime;
1905         pblock->nNonce = pdata->nNonce;
1906         pblock->vtx[0].vin[0].scriptSig = mapNewBlock[pdata->hashMerkleRoot].second;
1907         pblock->hashMerkleRoot = pblock->BuildMerkleTree();
1908         if (!pblock->SignBlock(*pwalletMain))
1909             throw JSONRPCError(-100, "Unable to sign block, wallet locked?");
1910
1911         return CheckWork(pblock, *pwalletMain, reservekey);
1912     }
1913 }
1914
1915 Value getblocktemplate(const Array& params, bool fHelp)
1916 {
1917     if (fHelp || params.size() > 1)
1918         throw runtime_error(
1919             "getblocktemplate [params]\n"
1920             "Returns data needed to construct a block to work on:\n"
1921             "  \"version\" : block version\n"
1922             "  \"previousblockhash\" : hash of current highest block\n"
1923             "  \"transactions\" : contents of non-coinbase transactions that should be included in the next block\n"
1924             "  \"coinbaseaux\" : data that should be included in coinbase\n"
1925             "  \"coinbasevalue\" : maximum allowable input to coinbase transaction, including the generation award and transaction fees\n"
1926             "  \"target\" : hash target\n"
1927             "  \"mintime\" : minimum timestamp appropriate for next block\n"
1928             "  \"curtime\" : current timestamp\n"
1929             "  \"mutable\" : list of ways the block template may be changed\n"
1930             "  \"noncerange\" : range of valid nonces\n"
1931             "  \"sigoplimit\" : limit of sigops in blocks\n"
1932             "  \"sizelimit\" : limit of block size\n"
1933             "  \"bits\" : compressed target of next block\n"
1934             "  \"height\" : height of the next block\n"
1935             "See https://en.bitcoin.it/wiki/BIP_0022 for full specification.");
1936
1937     std::string strMode = "template";
1938     if (params.size() > 0)
1939     {
1940         const Object& oparam = params[0].get_obj();
1941         const Value& modeval = find_value(oparam, "mode");
1942         if (modeval.type() == str_type)
1943             strMode = modeval.get_str();
1944         else
1945             throw JSONRPCError(-8, "Invalid mode");
1946     }
1947
1948     if (strMode != "template")
1949         throw JSONRPCError(-8, "Invalid mode");
1950
1951     if (vNodes.empty())
1952         throw JSONRPCError(-9, "NovaCoin is not connected!");
1953
1954     if (IsInitialBlockDownload())
1955         throw JSONRPCError(-10, "NovaCoin is downloading blocks...");
1956
1957     static CReserveKey reservekey(pwalletMain);
1958
1959     // Update block
1960     static unsigned int nTransactionsUpdatedLast;
1961     static CBlockIndex* pindexPrev;
1962     static int64 nStart;
1963     static CBlock* pblock;
1964     if (pindexPrev != pindexBest ||
1965         (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 5))
1966     {
1967         // Clear pindexPrev so future calls make a new block, despite any failures from here on
1968         pindexPrev = NULL;
1969
1970         // Store the pindexBest used before CreateNewBlock, to avoid races
1971         nTransactionsUpdatedLast = nTransactionsUpdated;
1972         CBlockIndex* pindexPrevNew = pindexBest;
1973         nStart = GetTime();
1974
1975         // Create new block
1976         if(pblock)
1977         {
1978             delete pblock;
1979             pblock = NULL;
1980         }
1981         pblock = CreateNewBlock(pwalletMain);
1982         if (!pblock)
1983             throw JSONRPCError(-7, "Out of memory");
1984
1985         // Need to update only after we know CreateNewBlock succeeded
1986         pindexPrev = pindexPrevNew;
1987     }
1988
1989     // Update nTime
1990     pblock->UpdateTime(pindexPrev);
1991     pblock->nNonce = 0;
1992
1993     Array transactions;
1994     map<uint256, int64_t> setTxIndex;
1995     int i = 0;
1996     CTxDB txdb("r");
1997     BOOST_FOREACH (CTransaction& tx, pblock->vtx)
1998     {
1999         uint256 txHash = tx.GetHash();
2000         setTxIndex[txHash] = i++;
2001
2002         if (tx.IsCoinBase() || tx.IsCoinStake())
2003             continue;
2004
2005         Object entry;
2006
2007         CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
2008         ssTx << tx;
2009         entry.push_back(Pair("data", HexStr(ssTx.begin(), ssTx.end())));
2010
2011         entry.push_back(Pair("hash", txHash.GetHex()));
2012
2013         MapPrevTx mapInputs;
2014         map<uint256, CTxIndex> mapUnused;
2015         bool fInvalid = false;
2016         if (tx.FetchInputs(txdb, mapUnused, false, false, mapInputs, fInvalid))
2017         {
2018             entry.push_back(Pair("fee", (int64_t)(tx.GetValueIn(mapInputs) - tx.GetValueOut())));
2019
2020             Array deps;
2021             BOOST_FOREACH (MapPrevTx::value_type& inp, mapInputs)
2022             {
2023                 if (setTxIndex.count(inp.first))
2024                     deps.push_back(setTxIndex[inp.first]);
2025             }
2026             entry.push_back(Pair("depends", deps));
2027
2028             int64_t nSigOps = tx.GetLegacySigOpCount();
2029             nSigOps += tx.GetP2SHSigOpCount(mapInputs);
2030             entry.push_back(Pair("sigops", nSigOps));
2031         }
2032
2033         transactions.push_back(entry);
2034     }
2035
2036     Object aux;
2037     aux.push_back(Pair("flags", HexStr(COINBASE_FLAGS.begin(), COINBASE_FLAGS.end())));
2038
2039     uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
2040
2041     static Array aMutable;
2042     if (aMutable.empty())
2043     {
2044         aMutable.push_back("time");
2045         aMutable.push_back("transactions");
2046         aMutable.push_back("prevblock");
2047     }
2048
2049     Object result;
2050     result.push_back(Pair("version", pblock->nVersion));
2051     result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex()));
2052     result.push_back(Pair("transactions", transactions));
2053     result.push_back(Pair("coinbaseaux", aux));
2054     result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue));
2055     result.push_back(Pair("target", hashTarget.GetHex()));
2056     result.push_back(Pair("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1));
2057     result.push_back(Pair("mutable", aMutable));
2058     result.push_back(Pair("noncerange", "00000000ffffffff"));
2059     result.push_back(Pair("sigoplimit", (int64_t)MAX_BLOCK_SIGOPS));
2060     result.push_back(Pair("sizelimit", (int64_t)MAX_BLOCK_SIZE));
2061     result.push_back(Pair("curtime", (int64_t)pblock->nTime));
2062     result.push_back(Pair("bits", HexBits(pblock->nBits)));
2063     result.push_back(Pair("height", (int64_t)(pindexPrev->nHeight+1)));
2064
2065     return result;
2066 }
2067
2068 Value submitblock(const Array& params, bool fHelp)
2069 {
2070     if (fHelp || params.size() < 1 || params.size() > 2)
2071         throw runtime_error(
2072             "submitblock <hex data> [optional-params-obj]\n"
2073             "[optional-params-obj] parameter is currently ignored.\n"
2074             "Attempts to submit new block to network.\n"
2075             "See https://en.bitcoin.it/wiki/BIP_0022 for full specification.");
2076
2077     vector<unsigned char> blockData(ParseHex(params[0].get_str()));
2078     CDataStream ssBlock(blockData, SER_NETWORK, PROTOCOL_VERSION);
2079     CBlock block;
2080     try {
2081         ssBlock >> block;
2082     }
2083     catch (std::exception &e) {
2084         throw JSONRPCError(-22, "Block decode failed");
2085     }
2086
2087     static CReserveKey reservekey(pwalletMain);
2088
2089     if(!block.SignBlock(*pwalletMain))
2090         throw JSONRPCError(-100, "Unable to sign block, wallet locked?");
2091
2092     bool fAccepted = CheckWork(&block, *pwalletMain, reservekey);
2093     if (!fAccepted)
2094         return "rejected";
2095
2096     return Value::null;
2097 }
2098
2099
2100 Value getmemorypool(const Array& params, bool fHelp)
2101 {
2102     if (fHelp || params.size() > 1)
2103         throw runtime_error(
2104             "getmemorypool [data]\n"
2105             "If [data] is not specified, returns data needed to construct a block to work on:\n"
2106             "  \"version\" : block version\n"
2107             "  \"previousblockhash\" : hash of current highest block\n"
2108             "  \"transactions\" : contents of non-coinbase transactions that should be included in the next block\n"
2109             "  \"coinbasevalue\" : maximum allowable input to coinbase transaction, including the generation award and transaction fees\n"
2110             "  \"coinbaseflags\" : data that should be included in coinbase so support for new features can be judged\n"
2111             "  \"time\" : timestamp appropriate for next block\n"
2112             "  \"mintime\" : minimum timestamp appropriate for next block\n"
2113             "  \"curtime\" : current timestamp\n"
2114             "  \"bits\" : compressed target of next block\n"
2115             "If [data] is specified, tries to solve the block and returns true if it was successful.");
2116
2117     if (params.size() == 0)
2118     {
2119         if (vNodes.empty())
2120             throw JSONRPCError(-9, "NovaCoin is not connected!");
2121
2122         if (IsInitialBlockDownload())
2123             throw JSONRPCError(-10, "NovaCoin is downloading blocks...");
2124
2125         static CReserveKey reservekey(pwalletMain);
2126
2127         // Update block
2128         static unsigned int nTransactionsUpdatedLast;
2129         static CBlockIndex* pindexPrev;
2130         static int64 nStart;
2131         static CBlock* pblock;
2132         if (pindexPrev != pindexBest ||
2133             (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 5))
2134         {
2135             nTransactionsUpdatedLast = nTransactionsUpdated;
2136             pindexPrev = pindexBest;
2137             nStart = GetTime();
2138
2139             // Create new block
2140             if(pblock)
2141                 delete pblock;
2142             pblock = CreateNewBlock(pwalletMain);
2143             if (!pblock)
2144                 throw JSONRPCError(-7, "Out of memory");
2145         }
2146
2147         // Update nTime
2148         pblock->UpdateTime(pindexPrev);
2149         pblock->nNonce = 0;
2150
2151         Array transactions;
2152         BOOST_FOREACH(CTransaction tx, pblock->vtx) {
2153             if(tx.IsCoinBase() || tx.IsCoinStake())
2154                 continue;
2155
2156             CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
2157             ssTx << tx;
2158
2159             transactions.push_back(HexStr(ssTx.begin(), ssTx.end()));
2160         }
2161
2162         Object result;
2163         result.push_back(Pair("version", pblock->nVersion));
2164         result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex()));
2165         result.push_back(Pair("transactions", transactions));
2166         result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue));
2167         result.push_back(Pair("coinbaseflags", HexStr(COINBASE_FLAGS.begin(), COINBASE_FLAGS.end())));
2168         result.push_back(Pair("time", (int64_t)pblock->nTime));
2169         result.push_back(Pair("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1));
2170         result.push_back(Pair("curtime", (int64_t)GetAdjustedTime()));
2171         result.push_back(Pair("bits", HexBits(pblock->nBits)));
2172
2173         return result;
2174     }
2175     else
2176     {
2177         // Parse parameters
2178         CDataStream ssBlock(ParseHex(params[0].get_str()), SER_NETWORK, PROTOCOL_VERSION);
2179         CBlock pblock;
2180         ssBlock >> pblock;
2181
2182         static CReserveKey reservekey(pwalletMain);
2183
2184         if(!pblock.SignBlock(*pwalletMain))
2185             throw JSONRPCError(-100, "Unable to sign block, wallet locked?");
2186
2187         return CheckWork(&pblock, *pwalletMain, reservekey);
2188     }
2189 }
2190
2191 Value getnewpubkey(const Array& params, bool fHelp)
2192 {
2193     if (fHelp || params.size() > 1)
2194         throw runtime_error(
2195             "getnewpubkey [account]\n"
2196             "Returns new public key for coinbase generation.");
2197
2198     // Parse the account first so we don't generate a key if there's an error
2199     string strAccount;
2200     if (params.size() > 0)
2201         strAccount = AccountFromValue(params[0]);
2202
2203     if (!pwalletMain->IsLocked())
2204         pwalletMain->TopUpKeyPool();
2205
2206     // Generate a new key that is added to wallet
2207     std::vector<unsigned char> newKey = pwalletMain->GenerateNewKey(false);
2208
2209     if(!newKey.size())
2210         throw JSONRPCError(-12, "Error: Unable to create key");
2211
2212     CBitcoinAddress address(newKey);
2213     pwalletMain->SetAddressBookName(address, strAccount);
2214
2215     return HexStr(newKey.begin(), newKey.end());
2216 }
2217
2218 Value getblockhash(const Array& params, bool fHelp)
2219 {
2220     if (fHelp || params.size() != 1)
2221         throw runtime_error(
2222             "getblockhash <index>\n"
2223             "Returns hash of block in best-block-chain at <index>.");
2224
2225     int nHeight = params[0].get_int();
2226     if (nHeight < 0 || nHeight > nBestHeight)
2227         throw runtime_error("Block number out of range.");
2228
2229     CBlock block;
2230     CBlockIndex* pblockindex = mapBlockIndex[hashBestChain];
2231     while (pblockindex->nHeight > nHeight)
2232         pblockindex = pblockindex->pprev;
2233     return pblockindex->phashBlock->GetHex();
2234 }
2235
2236 Value getblock(const Array& params, bool fHelp)
2237 {
2238     if (fHelp || params.size() < 1 || params.size() > 2)
2239         throw runtime_error(
2240             "getblock <hash> [txinfo]\n"
2241             "txinfo optional to print more detailed tx info\n"
2242             "Returns details of a block with given block-hash.");
2243
2244     std::string strHash = params[0].get_str();
2245     uint256 hash(strHash);
2246
2247     if (mapBlockIndex.count(hash) == 0)
2248         throw JSONRPCError(-5, "Block not found");
2249
2250     CBlock block;
2251     CBlockIndex* pblockindex = mapBlockIndex[hash];
2252     block.ReadFromDisk(pblockindex, true);
2253
2254     return blockToJSON(block, pblockindex, params.size() > 1 ? params[1].get_bool() : false);
2255 }
2256
2257 Value getblockbynumber(const Array& params, bool fHelp)
2258 {
2259     if (fHelp || params.size() < 1 || params.size() > 2)
2260         throw runtime_error(
2261             "getblock <number> [txinfo]\n"
2262             "txinfo optional to print more detailed tx info\n"
2263             "Returns details of a block with given block-number.");
2264
2265     int nHeight = params[0].get_int();
2266     if (nHeight < 0 || nHeight > nBestHeight)
2267         throw runtime_error("Block number out of range.");
2268
2269     CBlock block;
2270     CBlockIndex* pblockindex = mapBlockIndex[hashBestChain];
2271     while (pblockindex->nHeight > nHeight)
2272         pblockindex = pblockindex->pprev;
2273
2274     uint256 hash = *pblockindex->phashBlock;
2275
2276     pblockindex = mapBlockIndex[hash];
2277     block.ReadFromDisk(pblockindex, true);
2278
2279     return blockToJSON(block, pblockindex, params.size() > 1 ? params[1].get_bool() : false);
2280 }
2281
2282 // ppcoin: get information of sync-checkpoint
2283 Value getcheckpoint(const Array& params, bool fHelp)
2284 {
2285     if (fHelp || params.size() != 0)
2286         throw runtime_error(
2287             "getcheckpoint\n"
2288             "Show info of synchronized checkpoint.\n");
2289
2290     Object result;
2291     CBlockIndex* pindexCheckpoint;
2292     
2293     result.push_back(Pair("synccheckpoint", Checkpoints::hashSyncCheckpoint.ToString().c_str()));
2294     pindexCheckpoint = mapBlockIndex[Checkpoints::hashSyncCheckpoint];        
2295     result.push_back(Pair("height", pindexCheckpoint->nHeight));
2296     result.push_back(Pair("timestamp", DateTimeStrFormat(pindexCheckpoint->GetBlockTime()).c_str()));
2297     if (mapArgs.count("-checkpointkey"))
2298         result.push_back(Pair("checkpointmaster", true));
2299
2300     return result;
2301 }
2302
2303
2304 // ppcoin: reserve balance from being staked for network protection
2305 Value reservebalance(const Array& params, bool fHelp)
2306 {
2307     if (fHelp || params.size() > 2)
2308         throw runtime_error(
2309             "reservebalance [<reserve> [amount]]\n"
2310             "<reserve> is true or false to turn balance reserve on or off.\n"
2311             "<amount> is a real and rounded to cent.\n"
2312             "Set reserve amount not participating in network protection.\n"
2313             "If no parameters provided current setting is printed.\n");
2314
2315     if (params.size() > 0)
2316     {
2317         bool fReserve = params[0].get_bool();
2318         if (fReserve)
2319         {
2320             if (params.size() == 1)
2321                 throw runtime_error("must provide amount to reserve balance.\n");
2322             int64 nAmount = AmountFromValue(params[1]);
2323             nAmount = (nAmount / CENT) * CENT;  // round to cent
2324             if (nAmount < 0)
2325                 throw runtime_error("amount cannot be negative.\n");
2326             mapArgs["-reservebalance"] = FormatMoney(nAmount).c_str();
2327         }
2328         else
2329         {
2330             if (params.size() > 1)
2331                 throw runtime_error("cannot specify amount to turn off reserve.\n");
2332             mapArgs["-reservebalance"] = "0";
2333         }
2334     }
2335
2336     Object result;
2337     int64 nReserveBalance = 0;
2338     if (mapArgs.count("-reservebalance") && !ParseMoney(mapArgs["-reservebalance"], nReserveBalance))
2339         throw runtime_error("invalid reserve balance amount\n");
2340     result.push_back(Pair("reserve", (nReserveBalance > 0)));
2341     result.push_back(Pair("amount", ValueFromAmount(nReserveBalance)));
2342     return result;
2343 }
2344
2345
2346 // ppcoin: check wallet integrity
2347 Value checkwallet(const Array& params, bool fHelp)
2348 {
2349     if (fHelp || params.size() > 0)
2350         throw runtime_error(
2351             "checkwallet\n"
2352             "Check wallet for integrity.\n");
2353
2354     int nMismatchSpent;
2355     int64 nBalanceInQuestion;
2356     pwalletMain->FixSpentCoins(nMismatchSpent, nBalanceInQuestion, true);
2357     Object result;
2358     if (nMismatchSpent == 0)
2359         result.push_back(Pair("wallet check passed", true));
2360     else
2361     {
2362         result.push_back(Pair("mismatched spent coins", nMismatchSpent));
2363         result.push_back(Pair("amount in question", ValueFromAmount(nBalanceInQuestion)));
2364     }
2365     return result;
2366 }
2367
2368
2369 // ppcoin: repair wallet
2370 Value repairwallet(const Array& params, bool fHelp)
2371 {
2372     if (fHelp || params.size() > 0)
2373         throw runtime_error(
2374             "repairwallet\n"
2375             "Repair wallet if checkwallet reports any problem.\n");
2376
2377     int nMismatchSpent;
2378     int64 nBalanceInQuestion;
2379     pwalletMain->FixSpentCoins(nMismatchSpent, nBalanceInQuestion);
2380     Object result;
2381     if (nMismatchSpent == 0)
2382         result.push_back(Pair("wallet check passed", true));
2383     else
2384     {
2385         result.push_back(Pair("mismatched spent coins", nMismatchSpent));
2386         result.push_back(Pair("amount affected by repair", ValueFromAmount(nBalanceInQuestion)));
2387     }
2388     return result;
2389 }
2390
2391 // ppcoin: make a public-private key pair
2392 Value makekeypair(const Array& params, bool fHelp)
2393 {
2394     if (fHelp || params.size() > 1)
2395         throw runtime_error(
2396             "makekeypair [prefix]\n"
2397             "Make a public/private key pair.\n"
2398             "[prefix] is optional preferred prefix for the public key.\n");
2399
2400     string strPrefix = "";
2401     if (params.size() > 0)
2402         strPrefix = params[0].get_str();
2403  
2404     CKey key;
2405     int nCount = 0;
2406     do
2407     {
2408         key.MakeNewKey(false);
2409         nCount++;
2410     } while (nCount < 10000 && strPrefix != HexStr(key.GetPubKey()).substr(0, strPrefix.size()));
2411
2412     if (strPrefix != HexStr(key.GetPubKey()).substr(0, strPrefix.size()))
2413         return Value::null;
2414
2415     CPrivKey vchPrivKey = key.GetPrivKey();
2416     Object result;
2417     result.push_back(Pair("PrivateKey", HexStr<CPrivKey::iterator>(vchPrivKey.begin(), vchPrivKey.end())));
2418     result.push_back(Pair("PublicKey", HexStr(key.GetPubKey())));
2419     return result;
2420 }
2421
2422 extern CCriticalSection cs_mapAlerts;
2423 extern map<uint256, CAlert> mapAlerts;
2424
2425 // ppcoin: send alert.  
2426 // There is a known deadlock situation with ThreadMessageHandler
2427 // ThreadMessageHandler: holds cs_vSend and acquiring cs_main in SendMessages()
2428 // ThreadRPCServer: holds cs_main and acquiring cs_vSend in alert.RelayTo()/PushMessage()/BeginMessage()
2429 Value sendalert(const Array& params, bool fHelp)
2430 {
2431     if (fHelp || params.size() < 6)
2432         throw runtime_error(
2433             "sendalert <message> <privatekey> <minver> <maxver> <priority> <id> [cancelupto]\n"
2434             "<message> is the alert text message\n"
2435             "<privatekey> is hex string of alert master private key\n"
2436             "<minver> is the minimum applicable internal client version\n"
2437             "<maxver> is the maximum applicable internal client version\n"
2438             "<priority> is integer priority number\n"
2439             "<id> is the alert id\n"
2440             "[cancelupto] cancels all alert id's up to this number\n"
2441             "Returns true or false.");
2442
2443     CAlert alert;
2444     CKey key;
2445
2446     alert.strStatusBar = params[0].get_str();
2447     alert.nMinVer = params[2].get_int();
2448     alert.nMaxVer = params[3].get_int();
2449     alert.nPriority = params[4].get_int();
2450     alert.nID = params[5].get_int();
2451     if (params.size() > 6)
2452         alert.nCancel = params[6].get_int();
2453     alert.nVersion = PROTOCOL_VERSION;
2454     alert.nRelayUntil = GetAdjustedTime() + 365*24*60*60;
2455     alert.nExpiration = GetAdjustedTime() + 365*24*60*60;
2456
2457     CDataStream sMsg(SER_NETWORK, PROTOCOL_VERSION);
2458     sMsg << (CUnsignedAlert)alert;
2459     alert.vchMsg = vector<unsigned char>(sMsg.begin(), sMsg.end());
2460     
2461     vector<unsigned char> vchPrivKey = ParseHex(params[1].get_str());
2462     key.SetPrivKey(CPrivKey(vchPrivKey.begin(), vchPrivKey.end())); // if key is not correct openssl may crash
2463     if (!key.Sign(Hash(alert.vchMsg.begin(), alert.vchMsg.end()), alert.vchSig))
2464         throw runtime_error(
2465             "Unable to sign alert, check private key?\n");  
2466     if(!alert.ProcessAlert()) 
2467         throw runtime_error(
2468             "Failed to process alert.\n");
2469     // Relay alert
2470     {
2471         LOCK(cs_vNodes);
2472         BOOST_FOREACH(CNode* pnode, vNodes)
2473             alert.RelayTo(pnode);
2474     }
2475
2476     Object result;
2477     result.push_back(Pair("strStatusBar", alert.strStatusBar));
2478     result.push_back(Pair("nVersion", alert.nVersion));
2479     result.push_back(Pair("nMinVer", alert.nMinVer));
2480     result.push_back(Pair("nMaxVer", alert.nMaxVer));
2481     result.push_back(Pair("nPriority", alert.nPriority));
2482     result.push_back(Pair("nID", alert.nID));
2483     if (alert.nCancel > 0)
2484         result.push_back(Pair("nCancel", alert.nCancel));
2485     return result;
2486 }
2487
2488
2489
2490 //
2491 // Call Table
2492 //
2493
2494
2495 static const CRPCCommand vRPCCommands[] =
2496 { //  name                      function                 safe mode?
2497   //  ------------------------  -----------------------  ----------
2498     { "help",                   &help,                   true },
2499     { "stop",                   &stop,                   true },
2500     { "getblockcount",          &getblockcount,          true },
2501     { "getblocknumber",         &getblocknumber,         true },
2502     { "getconnectioncount",     &getconnectioncount,     true },
2503     { "getdifficulty",          &getdifficulty,          true },
2504     { "getgenerate",            &getgenerate,            true },
2505     { "setgenerate",            &setgenerate,            true },
2506     { "gethashespersec",        &gethashespersec,        true },
2507     { "getinfo",                &getinfo,                true },
2508     { "getmininginfo",          &getmininginfo,          true },
2509     { "getnewaddress",          &getnewaddress,          true },
2510     { "getnewpubkey",           &getnewpubkey,           true },
2511     { "getaccountaddress",      &getaccountaddress,      true },
2512     { "setaccount",             &setaccount,             true },
2513     { "getaccount",             &getaccount,             false },
2514     { "getaddressesbyaccount",  &getaddressesbyaccount,  true },
2515     { "sendtoaddress",          &sendtoaddress,          false },
2516     { "getreceivedbyaddress",   &getreceivedbyaddress,   false },
2517     { "getreceivedbyaccount",   &getreceivedbyaccount,   false },
2518     { "listreceivedbyaddress",  &listreceivedbyaddress,  false },
2519     { "listreceivedbyaccount",  &listreceivedbyaccount,  false },
2520     { "backupwallet",           &backupwallet,           true },
2521     { "keypoolrefill",          &keypoolrefill,          true },
2522     { "walletpassphrase",       &walletpassphrase,       true },
2523     { "walletpassphrasechange", &walletpassphrasechange, false },
2524     { "walletlock",             &walletlock,             true },
2525     { "encryptwallet",          &encryptwallet,          false },
2526     { "validateaddress",        &validateaddress,        true },
2527     { "getbalance",             &getbalance,             false },
2528     { "move",                   &movecmd,                false },
2529     { "sendfrom",               &sendfrom,               false },
2530     { "sendmany",               &sendmany,               false },
2531     { "addmultisigaddress",     &addmultisigaddress,     false },
2532     { "getblock",               &getblock,               false },
2533     { "getblockhash",           &getblockhash,           false },
2534     { "getblockbynumber",       &getblockbynumber,       false },
2535     { "gettransaction",         &gettransaction,         false },
2536     { "listtransactions",       &listtransactions,       false },
2537     { "signmessage",            &signmessage,            false },
2538     { "verifymessage",          &verifymessage,          false },
2539     { "getwork",                &getwork,                true },
2540     { "listaccounts",           &listaccounts,           false },
2541     { "settxfee",               &settxfee,               false },
2542     { "getmemorypool",          &getmemorypool,          true },
2543     { "getblocktemplate",       &getblocktemplate,       true },
2544     { "submitblock",            &submitblock,            false },
2545     { "listsinceblock",         &listsinceblock,         false },
2546     { "dumpprivkey",            &dumpprivkey,            false },
2547     { "importprivkey",          &importprivkey,          false },
2548     { "getcheckpoint",          &getcheckpoint,          true },
2549     { "reservebalance",         &reservebalance,         false},
2550     { "checkwallet",            &checkwallet,            false},
2551     { "repairwallet",           &repairwallet,           false},
2552     { "makekeypair",            &makekeypair,            false},
2553     { "sendalert",              &sendalert,              false},
2554 };
2555
2556 CRPCTable::CRPCTable()
2557 {
2558     unsigned int vcidx;
2559     for (vcidx = 0; vcidx < (sizeof(vRPCCommands) / sizeof(vRPCCommands[0])); vcidx++)
2560     {
2561         const CRPCCommand *pcmd;
2562
2563         pcmd = &vRPCCommands[vcidx];
2564         mapCommands[pcmd->name] = pcmd;
2565     }
2566 }
2567
2568 const CRPCCommand *CRPCTable::operator[](string name) const
2569 {
2570     map<string, const CRPCCommand*>::const_iterator it = mapCommands.find(name);
2571     if (it == mapCommands.end())
2572         return NULL;
2573     return (*it).second;
2574 }
2575
2576 //
2577 // HTTP protocol
2578 //
2579 // This ain't Apache.  We're just using HTTP header for the length field
2580 // and to be compatible with other JSON-RPC implementations.
2581 //
2582
2583 string HTTPPost(const string& strMsg, const map<string,string>& mapRequestHeaders)
2584 {
2585     ostringstream s;
2586     s << "POST / HTTP/1.1\r\n"
2587       << "User-Agent: novacoin-json-rpc/" << FormatFullVersion() << "\r\n"
2588       << "Host: 127.0.0.1\r\n"
2589       << "Content-Type: application/json\r\n"
2590       << "Content-Length: " << strMsg.size() << "\r\n"
2591       << "Connection: close\r\n"
2592       << "Accept: application/json\r\n";
2593     BOOST_FOREACH(const PAIRTYPE(string, string)& item, mapRequestHeaders)
2594         s << item.first << ": " << item.second << "\r\n";
2595     s << "\r\n" << strMsg;
2596
2597     return s.str();
2598 }
2599
2600 string rfc1123Time()
2601 {
2602     char buffer[64];
2603     time_t now;
2604     time(&now);
2605     struct tm* now_gmt = gmtime(&now);
2606     string locale(setlocale(LC_TIME, NULL));
2607     setlocale(LC_TIME, "C"); // we want posix (aka "C") weekday/month strings
2608     strftime(buffer, sizeof(buffer), "%a, %d %b %Y %H:%M:%S +0000", now_gmt);
2609     setlocale(LC_TIME, locale.c_str());
2610     return string(buffer);
2611 }
2612
2613 static string HTTPReply(int nStatus, const string& strMsg)
2614 {
2615     if (nStatus == 401)
2616         return strprintf("HTTP/1.0 401 Authorization Required\r\n"
2617             "Date: %s\r\n"
2618             "Server: novacoin-json-rpc/%s\r\n"
2619             "WWW-Authenticate: Basic realm=\"jsonrpc\"\r\n"
2620             "Content-Type: text/html\r\n"
2621             "Content-Length: 296\r\n"
2622             "\r\n"
2623             "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\r\n"
2624             "\"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd\">\r\n"
2625             "<HTML>\r\n"
2626             "<HEAD>\r\n"
2627             "<TITLE>Error</TITLE>\r\n"
2628             "<META HTTP-EQUIV='Content-Type' CONTENT='text/html; charset=ISO-8859-1'>\r\n"
2629             "</HEAD>\r\n"
2630             "<BODY><H1>401 Unauthorized.</H1></BODY>\r\n"
2631             "</HTML>\r\n", rfc1123Time().c_str(), FormatFullVersion().c_str());
2632     const char *cStatus;
2633          if (nStatus == 200) cStatus = "OK";
2634     else if (nStatus == 400) cStatus = "Bad Request";
2635     else if (nStatus == 403) cStatus = "Forbidden";
2636     else if (nStatus == 404) cStatus = "Not Found";
2637     else if (nStatus == 500) cStatus = "Internal Server Error";
2638     else cStatus = "";
2639     return strprintf(
2640             "HTTP/1.1 %d %s\r\n"
2641             "Date: %s\r\n"
2642             "Connection: close\r\n"
2643             "Content-Length: %d\r\n"
2644             "Content-Type: application/json\r\n"
2645             "Server: novacoin-json-rpc/%s\r\n"
2646             "\r\n"
2647             "%s",
2648         nStatus,
2649         cStatus,
2650         rfc1123Time().c_str(),
2651         strMsg.size(),
2652         FormatFullVersion().c_str(),
2653         strMsg.c_str());
2654 }
2655
2656 int ReadHTTPStatus(std::basic_istream<char>& stream)
2657 {
2658     string str;
2659     getline(stream, str);
2660     vector<string> vWords;
2661     boost::split(vWords, str, boost::is_any_of(" "));
2662     if (vWords.size() < 2)
2663         return 500;
2664     return atoi(vWords[1].c_str());
2665 }
2666
2667 int ReadHTTPHeader(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet)
2668 {
2669     int nLen = 0;
2670     loop
2671     {
2672         string str;
2673         std::getline(stream, str);
2674         if (str.empty() || str == "\r")
2675             break;
2676         string::size_type nColon = str.find(":");
2677         if (nColon != string::npos)
2678         {
2679             string strHeader = str.substr(0, nColon);
2680             boost::trim(strHeader);
2681             boost::to_lower(strHeader);
2682             string strValue = str.substr(nColon+1);
2683             boost::trim(strValue);
2684             mapHeadersRet[strHeader] = strValue;
2685             if (strHeader == "content-length")
2686                 nLen = atoi(strValue.c_str());
2687         }
2688     }
2689     return nLen;
2690 }
2691
2692 int ReadHTTP(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet, string& strMessageRet)
2693 {
2694     mapHeadersRet.clear();
2695     strMessageRet = "";
2696
2697     // Read status
2698     int nStatus = ReadHTTPStatus(stream);
2699
2700     // Read header
2701     int nLen = ReadHTTPHeader(stream, mapHeadersRet);
2702     if (nLen < 0 || nLen > (int)MAX_SIZE)
2703         return 500;
2704
2705     // Read message
2706     if (nLen > 0)
2707     {
2708         vector<char> vch(nLen);
2709         stream.read(&vch[0], nLen);
2710         strMessageRet = string(vch.begin(), vch.end());
2711     }
2712
2713     return nStatus;
2714 }
2715
2716 bool HTTPAuthorized(map<string, string>& mapHeaders)
2717 {
2718     string strAuth = mapHeaders["authorization"];
2719     if (strAuth.substr(0,6) != "Basic ")
2720         return false;
2721     string strUserPass64 = strAuth.substr(6); boost::trim(strUserPass64);
2722     string strUserPass = DecodeBase64(strUserPass64);
2723     return strUserPass == strRPCUserColonPass;
2724 }
2725
2726 //
2727 // JSON-RPC protocol.  Bitcoin speaks version 1.0 for maximum compatibility,
2728 // but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
2729 // unspecified (HTTP errors and contents of 'error').
2730 //
2731 // 1.0 spec: http://json-rpc.org/wiki/specification
2732 // 1.2 spec: http://groups.google.com/group/json-rpc/web/json-rpc-over-http
2733 // http://www.codeproject.com/KB/recipes/JSON_Spirit.aspx
2734 //
2735
2736 string JSONRPCRequest(const string& strMethod, const Array& params, const Value& id)
2737 {
2738     Object request;
2739     request.push_back(Pair("method", strMethod));
2740     request.push_back(Pair("params", params));
2741     request.push_back(Pair("id", id));
2742     return write_string(Value(request), false) + "\n";
2743 }
2744
2745 string JSONRPCReply(const Value& result, const Value& error, const Value& id)
2746 {
2747     Object reply;
2748     if (error.type() != null_type)
2749         reply.push_back(Pair("result", Value::null));
2750     else
2751         reply.push_back(Pair("result", result));
2752     reply.push_back(Pair("error", error));
2753     reply.push_back(Pair("id", id));
2754     return write_string(Value(reply), false) + "\n";
2755 }
2756
2757 void ErrorReply(std::ostream& stream, const Object& objError, const Value& id)
2758 {
2759     // Send error reply from json-rpc error object
2760     int nStatus = 500;
2761     int code = find_value(objError, "code").get_int();
2762     if (code == -32600) nStatus = 400;
2763     else if (code == -32601) nStatus = 404;
2764     string strReply = JSONRPCReply(Value::null, objError, id);
2765     stream << HTTPReply(nStatus, strReply) << std::flush;
2766 }
2767
2768 bool ClientAllowed(const string& strAddress)
2769 {
2770     if (strAddress == asio::ip::address_v4::loopback().to_string())
2771         return true;
2772     const vector<string>& vAllow = mapMultiArgs["-rpcallowip"];
2773     BOOST_FOREACH(string strAllow, vAllow)
2774         if (WildcardMatch(strAddress, strAllow))
2775             return true;
2776     return false;
2777 }
2778
2779 //
2780 // IOStream device that speaks SSL but can also speak non-SSL
2781 //
2782 class SSLIOStreamDevice : public iostreams::device<iostreams::bidirectional> {
2783 public:
2784     SSLIOStreamDevice(SSLStream &streamIn, bool fUseSSLIn) : stream(streamIn)
2785     {
2786         fUseSSL = fUseSSLIn;
2787         fNeedHandshake = fUseSSLIn;
2788     }
2789
2790     void handshake(ssl::stream_base::handshake_type role)
2791     {
2792         if (!fNeedHandshake) return;
2793         fNeedHandshake = false;
2794         stream.handshake(role);
2795     }
2796     std::streamsize read(char* s, std::streamsize n)
2797     {
2798         handshake(ssl::stream_base::server); // HTTPS servers read first
2799         if (fUseSSL) return stream.read_some(asio::buffer(s, n));
2800         return stream.next_layer().read_some(asio::buffer(s, n));
2801     }
2802     std::streamsize write(const char* s, std::streamsize n)
2803     {
2804         handshake(ssl::stream_base::client); // HTTPS clients write first
2805         if (fUseSSL) return asio::write(stream, asio::buffer(s, n));
2806         return asio::write(stream.next_layer(), asio::buffer(s, n));
2807     }
2808     bool connect(const std::string& server, const std::string& port)
2809     {
2810         ip::tcp::resolver resolver(stream.get_io_service());
2811         ip::tcp::resolver::query query(server.c_str(), port.c_str());
2812         ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
2813         ip::tcp::resolver::iterator end;
2814         boost::system::error_code error = asio::error::host_not_found;
2815         while (error && endpoint_iterator != end)
2816         {
2817             stream.lowest_layer().close();
2818             stream.lowest_layer().connect(*endpoint_iterator++, error);
2819         }
2820         if (error)
2821             return false;
2822         return true;
2823     }
2824
2825 private:
2826     bool fNeedHandshake;
2827     bool fUseSSL;
2828     SSLStream& stream;
2829 };
2830
2831 void ThreadRPCServer(void* parg)
2832 {
2833     IMPLEMENT_RANDOMIZE_STACK(ThreadRPCServer(parg));
2834     try
2835     {
2836         vnThreadsRunning[THREAD_RPCSERVER]++;
2837         ThreadRPCServer2(parg);
2838         vnThreadsRunning[THREAD_RPCSERVER]--;
2839     }
2840     catch (std::exception& e) {
2841         vnThreadsRunning[THREAD_RPCSERVER]--;
2842         PrintException(&e, "ThreadRPCServer()");
2843     } catch (...) {
2844         vnThreadsRunning[THREAD_RPCSERVER]--;
2845         PrintException(NULL, "ThreadRPCServer()");
2846     }
2847     printf("ThreadRPCServer exiting\n");
2848 }
2849
2850 void ThreadRPCServer2(void* parg)
2851 {
2852     printf("ThreadRPCServer started\n");
2853
2854     strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"];
2855     if (mapArgs["-rpcpassword"] == "")
2856     {
2857         unsigned char rand_pwd[32];
2858         RAND_bytes(rand_pwd, 32);
2859         string strWhatAmI = "To use novacoind";
2860         if (mapArgs.count("-server"))
2861             strWhatAmI = strprintf(_("To use the %s option"), "\"-server\"");
2862         else if (mapArgs.count("-daemon"))
2863             strWhatAmI = strprintf(_("To use the %s option"), "\"-daemon\"");
2864         ThreadSafeMessageBox(strprintf(
2865             _("%s, you must set a rpcpassword in the configuration file:\n %s\n"
2866               "It is recommended you use the following random password:\n"
2867               "rpcuser=novarpc\n"
2868               "rpcpassword=%s\n"
2869               "(you do not need to remember this password)\n"
2870               "If the file does not exist, create it with owner-readable-only file permissions.\n"),
2871                 strWhatAmI.c_str(),
2872                 GetConfigFile().string().c_str(),
2873                 EncodeBase58(&rand_pwd[0],&rand_pwd[0]+32).c_str()),
2874             _("Error"), wxOK | wxMODAL);
2875         StartShutdown();
2876         return;
2877     }
2878
2879     bool fUseSSL = GetBoolArg("-rpcssl");
2880     asio::ip::address bindAddress = mapArgs.count("-rpcallowip") ? asio::ip::address_v4::any() : asio::ip::address_v4::loopback();
2881
2882     asio::io_service io_service;
2883     ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", RPC_PORT));
2884     ip::tcp::acceptor acceptor(io_service);
2885     try
2886     {
2887         acceptor.open(endpoint.protocol());
2888         acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
2889         acceptor.bind(endpoint);
2890         acceptor.listen(socket_base::max_connections);
2891     }
2892     catch(boost::system::system_error &e)
2893     {
2894         ThreadSafeMessageBox(strprintf(_("An error occured while setting up the RPC port %i for listening: %s"), endpoint.port(), e.what()),
2895                              _("Error"), wxOK | wxMODAL);
2896         StartShutdown();
2897         return;
2898     }
2899
2900     ssl::context context(io_service, ssl::context::sslv23);
2901     if (fUseSSL)
2902     {
2903         context.set_options(ssl::context::no_sslv2);
2904
2905         filesystem::path pathCertFile(GetArg("-rpcsslcertificatechainfile", "server.cert"));
2906         if (!pathCertFile.is_complete()) pathCertFile = filesystem::path(GetDataDir()) / pathCertFile;
2907         if (filesystem::exists(pathCertFile)) context.use_certificate_chain_file(pathCertFile.string());
2908         else printf("ThreadRPCServer ERROR: missing server certificate file %s\n", pathCertFile.string().c_str());
2909
2910         filesystem::path pathPKFile(GetArg("-rpcsslprivatekeyfile", "server.pem"));
2911         if (!pathPKFile.is_complete()) pathPKFile = filesystem::path(GetDataDir()) / pathPKFile;
2912         if (filesystem::exists(pathPKFile)) context.use_private_key_file(pathPKFile.string(), ssl::context::pem);
2913         else printf("ThreadRPCServer ERROR: missing server private key file %s\n", pathPKFile.string().c_str());
2914
2915         string strCiphers = GetArg("-rpcsslciphers", "TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH");
2916         SSL_CTX_set_cipher_list(context.impl(), strCiphers.c_str());
2917     }
2918
2919     loop
2920     {
2921         // Accept connection
2922         SSLStream sslStream(io_service, context);
2923         SSLIOStreamDevice d(sslStream, fUseSSL);
2924         iostreams::stream<SSLIOStreamDevice> stream(d);
2925
2926         ip::tcp::endpoint peer;
2927         vnThreadsRunning[THREAD_RPCSERVER]--;
2928         acceptor.accept(sslStream.lowest_layer(), peer);
2929         vnThreadsRunning[4]++;
2930         if (fShutdown)
2931             return;
2932
2933         // Restrict callers by IP
2934         if (!ClientAllowed(peer.address().to_string()))
2935         {
2936             // Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake.
2937             if (!fUseSSL)
2938                 stream << HTTPReply(403, "") << std::flush;
2939             continue;
2940         }
2941
2942         map<string, string> mapHeaders;
2943         string strRequest;
2944
2945         boost::thread api_caller(ReadHTTP, boost::ref(stream), boost::ref(mapHeaders), boost::ref(strRequest));
2946         if (!api_caller.timed_join(boost::posix_time::seconds(GetArg("-rpctimeout", 30))))
2947         {   // Timed out:
2948             acceptor.cancel();
2949             printf("ThreadRPCServer ReadHTTP timeout\n");
2950             continue;
2951         }
2952
2953         // Check authorization
2954         if (mapHeaders.count("authorization") == 0)
2955         {
2956             stream << HTTPReply(401, "") << std::flush;
2957             continue;
2958         }
2959         if (!HTTPAuthorized(mapHeaders))
2960         {
2961             printf("ThreadRPCServer incorrect password attempt from %s\n",peer.address().to_string().c_str());
2962             /* Deter brute-forcing short passwords.
2963                If this results in a DOS the user really
2964                shouldn't have their RPC port exposed.*/
2965             if (mapArgs["-rpcpassword"].size() < 20)
2966                 Sleep(250);
2967
2968             stream << HTTPReply(401, "") << std::flush;
2969             continue;
2970         }
2971
2972         Value id = Value::null;
2973         try
2974         {
2975             // Parse request
2976             Value valRequest;
2977             if (!read_string(strRequest, valRequest) || valRequest.type() != obj_type)
2978                 throw JSONRPCError(-32700, "Parse error");
2979             const Object& request = valRequest.get_obj();
2980
2981             // Parse id now so errors from here on will have the id
2982             id = find_value(request, "id");
2983
2984             // Parse method
2985             Value valMethod = find_value(request, "method");
2986             if (valMethod.type() == null_type)
2987                 throw JSONRPCError(-32600, "Missing method");
2988             if (valMethod.type() != str_type)
2989                 throw JSONRPCError(-32600, "Method must be a string");
2990             string strMethod = valMethod.get_str();
2991             if (strMethod != "getwork" && strMethod != "getmemorypool")
2992                 printf("ThreadRPCServer method=%s\n", strMethod.c_str());
2993
2994             // Parse params
2995             Value valParams = find_value(request, "params");
2996             Array params;
2997             if (valParams.type() == array_type)
2998                 params = valParams.get_array();
2999             else if (valParams.type() == null_type)
3000                 params = Array();
3001             else
3002                 throw JSONRPCError(-32600, "Params must be an array");
3003
3004             // Find method
3005             const CRPCCommand *pcmd = tableRPC[strMethod];
3006             if (!pcmd)
3007                 throw JSONRPCError(-32601, "Method not found");
3008
3009             // Observe safe mode
3010             string strWarning = GetWarnings("rpc");
3011             if (strWarning != "" && !GetBoolArg("-disablesafemode") &&
3012                 !pcmd->okSafeMode)
3013                 throw JSONRPCError(-2, string("Safe mode: ") + strWarning);
3014
3015             try
3016             {
3017                 // Execute
3018                 Value result;
3019                 {
3020                     LOCK2(cs_main, pwalletMain->cs_wallet);
3021                     result = pcmd->actor(params, false);
3022                 }
3023
3024                 // Send reply
3025                 string strReply = JSONRPCReply(result, Value::null, id);
3026                 stream << HTTPReply(200, strReply) << std::flush;
3027             }
3028             catch (std::exception& e)
3029             {
3030                 ErrorReply(stream, JSONRPCError(-1, e.what()), id);
3031             }
3032         }
3033         catch (Object& objError)
3034         {
3035             ErrorReply(stream, objError, id);
3036         }
3037         catch (std::exception& e)
3038         {
3039             ErrorReply(stream, JSONRPCError(-32700, e.what()), id);
3040         }
3041     }
3042 }
3043
3044
3045
3046
3047 Object CallRPC(const string& strMethod, const Array& params)
3048 {
3049     if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
3050         throw runtime_error(strprintf(
3051             _("You must set rpcpassword=<password> in the configuration file:\n%s\n"
3052               "If the file does not exist, create it with owner-readable-only file permissions."),
3053                 GetConfigFile().string().c_str()));
3054
3055     // Connect to localhost
3056     bool fUseSSL = GetBoolArg("-rpcssl");
3057     asio::io_service io_service;
3058     ssl::context context(io_service, ssl::context::sslv23);
3059     context.set_options(ssl::context::no_sslv2);
3060     SSLStream sslStream(io_service, context);
3061     SSLIOStreamDevice d(sslStream, fUseSSL);
3062     iostreams::stream<SSLIOStreamDevice> stream(d);
3063     if (!d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", CBigNum(RPC_PORT).ToString().c_str())))
3064         throw runtime_error("couldn't connect to server");
3065
3066     // HTTP basic authentication
3067     string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
3068     map<string, string> mapRequestHeaders;
3069     mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64;
3070
3071     // Send request
3072     string strRequest = JSONRPCRequest(strMethod, params, 1);
3073     string strPost = HTTPPost(strRequest, mapRequestHeaders);
3074     stream << strPost << std::flush;
3075
3076     // Receive reply
3077     map<string, string> mapHeaders;
3078     string strReply;
3079     int nStatus = ReadHTTP(stream, mapHeaders, strReply);
3080     if (nStatus == 401)
3081         throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
3082     else if (nStatus >= 400 && nStatus != 400 && nStatus != 404 && nStatus != 500)
3083         throw runtime_error(strprintf("server returned HTTP error %d", nStatus));
3084     else if (strReply.empty())
3085         throw runtime_error("no response from server");
3086
3087     // Parse reply
3088     Value valReply;
3089     if (!read_string(strReply, valReply))
3090         throw runtime_error("couldn't parse reply from server");
3091     const Object& reply = valReply.get_obj();
3092     if (reply.empty())
3093         throw runtime_error("expected reply to have result, error and id properties");
3094
3095     return reply;
3096 }
3097
3098
3099
3100
3101 template<typename T>
3102 void ConvertTo(Value& value)
3103 {
3104     if (value.type() == str_type)
3105     {
3106         // reinterpret string as unquoted json value
3107         Value value2;
3108         if (!read_string(value.get_str(), value2))
3109             throw runtime_error("type mismatch");
3110         value = value2.get_value<T>();
3111     }
3112     else
3113     {
3114         value = value.get_value<T>();
3115     }
3116 }
3117
3118 int CommandLineRPC(int argc, char *argv[])
3119 {
3120     string strPrint;
3121     int nRet = 0;
3122     try
3123     {
3124         // Skip switches
3125         while (argc > 1 && IsSwitchChar(argv[1][0]))
3126         {
3127             argc--;
3128             argv++;
3129         }
3130
3131         // Method
3132         if (argc < 2)
3133             throw runtime_error("too few parameters");
3134         string strMethod = argv[1];
3135
3136         // Parameters default to strings
3137         Array params;
3138         for (int i = 2; i < argc; i++)
3139             params.push_back(argv[i]);
3140         int n = params.size();
3141
3142         //
3143         // Special case non-string parameter types
3144         //
3145         if (strMethod == "setgenerate"            && n > 0) ConvertTo<bool>(params[0]);
3146         if (strMethod == "setgenerate"            && n > 1) ConvertTo<boost::int64_t>(params[1]);
3147         if (strMethod == "sendtoaddress"          && n > 1) ConvertTo<double>(params[1]);
3148         if (strMethod == "settxfee"               && n > 0) ConvertTo<double>(params[0]);
3149         if (strMethod == "getreceivedbyaddress"   && n > 1) ConvertTo<boost::int64_t>(params[1]);
3150         if (strMethod == "getreceivedbyaccount"   && n > 1) ConvertTo<boost::int64_t>(params[1]);
3151         if (strMethod == "listreceivedbyaddress"  && n > 0) ConvertTo<boost::int64_t>(params[0]);
3152         if (strMethod == "listreceivedbyaddress"  && n > 1) ConvertTo<bool>(params[1]);
3153         if (strMethod == "listreceivedbyaccount"  && n > 0) ConvertTo<boost::int64_t>(params[0]);
3154         if (strMethod == "listreceivedbyaccount"  && n > 1) ConvertTo<bool>(params[1]);
3155         if (strMethod == "getbalance"             && n > 1) ConvertTo<boost::int64_t>(params[1]);
3156         if (strMethod == "getblockhash"           && n > 0) ConvertTo<boost::int64_t>(params[0]);
3157         if (strMethod == "getblockbynumber"       && n > 0) ConvertTo<boost::int64_t>(params[0]);
3158         if (strMethod == "getblockbynumber"       && n > 1) ConvertTo<bool>(params[1]);
3159         if (strMethod == "getblock"               && n > 1) ConvertTo<bool>(params[1]);
3160         if (strMethod == "move"                   && n > 2) ConvertTo<double>(params[2]);
3161         if (strMethod == "move"                   && n > 3) ConvertTo<boost::int64_t>(params[3]);
3162         if (strMethod == "sendfrom"               && n > 2) ConvertTo<double>(params[2]);
3163         if (strMethod == "sendfrom"               && n > 3) ConvertTo<boost::int64_t>(params[3]);
3164         if (strMethod == "listtransactions"       && n > 1) ConvertTo<boost::int64_t>(params[1]);
3165         if (strMethod == "listtransactions"       && n > 2) ConvertTo<boost::int64_t>(params[2]);
3166         if (strMethod == "listaccounts"           && n > 0) ConvertTo<boost::int64_t>(params[0]);
3167         if (strMethod == "walletpassphrase"       && n > 1) ConvertTo<boost::int64_t>(params[1]);
3168         if (strMethod == "walletpassphrase"       && n > 2) ConvertTo<bool>(params[2]);
3169         if (strMethod == "listsinceblock"         && n > 1) ConvertTo<boost::int64_t>(params[1]);
3170         if (strMethod == "sendalert"              && n > 2) ConvertTo<boost::int64_t>(params[2]);
3171         if (strMethod == "sendalert"              && n > 3) ConvertTo<boost::int64_t>(params[3]);
3172         if (strMethod == "sendalert"              && n > 4) ConvertTo<boost::int64_t>(params[4]);
3173         if (strMethod == "sendalert"              && n > 5) ConvertTo<boost::int64_t>(params[5]);
3174         if (strMethod == "sendalert"              && n > 6) ConvertTo<boost::int64_t>(params[6]);
3175         if (strMethod == "sendmany"               && n > 1)
3176         {
3177             string s = params[1].get_str();
3178             Value v;
3179             if (!read_string(s, v) || v.type() != obj_type)
3180                 throw runtime_error("type mismatch");
3181             params[1] = v.get_obj();
3182         }
3183         if (strMethod == "sendmany"                && n > 2) ConvertTo<boost::int64_t>(params[2]);
3184         if (strMethod == "reservebalance"          && n > 0) ConvertTo<bool>(params[0]);
3185         if (strMethod == "reservebalance"          && n > 1) ConvertTo<double>(params[1]);
3186         if (strMethod == "addmultisigaddress"      && n > 0) ConvertTo<boost::int64_t>(params[0]);
3187         if (strMethod == "addmultisigaddress"      && n > 1)
3188         {
3189             string s = params[1].get_str();
3190             Value v;
3191             if (!read_string(s, v) || v.type() != array_type)
3192                 throw runtime_error("type mismatch "+s);
3193             params[1] = v.get_array();
3194         }
3195
3196         // Execute
3197         Object reply = CallRPC(strMethod, params);
3198
3199         // Parse reply
3200         const Value& result = find_value(reply, "result");
3201         const Value& error  = find_value(reply, "error");
3202
3203         if (error.type() != null_type)
3204         {
3205             // Error
3206             strPrint = "error: " + write_string(error, false);
3207             int code = find_value(error.get_obj(), "code").get_int();
3208             nRet = abs(code);
3209         }
3210         else
3211         {
3212             // Result
3213             if (result.type() == null_type)
3214                 strPrint = "";
3215             else if (result.type() == str_type)
3216                 strPrint = result.get_str();
3217             else
3218                 strPrint = write_string(result, true);
3219         }
3220     }
3221     catch (std::exception& e)
3222     {
3223         strPrint = string("error: ") + e.what();
3224         nRet = 87;
3225     }
3226     catch (...)
3227     {
3228         PrintException(NULL, "CommandLineRPC()");
3229     }
3230
3231     if (strPrint != "")
3232     {
3233         fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
3234     }
3235     return nRet;
3236 }
3237
3238
3239
3240
3241 #ifdef TEST
3242 int main(int argc, char *argv[])
3243 {
3244 #ifdef _MSC_VER
3245     // Turn off microsoft heap dump noise
3246     _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
3247     _CrtSetReportFile(_CRT_WARN, CreateFile("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0));
3248 #endif
3249     setbuf(stdin, NULL);
3250     setbuf(stdout, NULL);
3251     setbuf(stderr, NULL);
3252
3253     try
3254     {
3255         if (argc >= 2 && string(argv[1]) == "-server")
3256         {
3257             printf("server ready\n");
3258             ThreadRPCServer(NULL);
3259         }
3260         else
3261         {
3262             return CommandLineRPC(argc, argv);
3263         }
3264     }
3265     catch (std::exception& e) {
3266         PrintException(&e, "main()");
3267     } catch (...) {
3268         PrintException(NULL, "main()");
3269     }
3270     return 0;
3271 }
3272 #endif
3273
3274 const CRPCTable tableRPC;