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