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