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