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