Back to home page

Bitcoin sources

 
 

    


File indexing completed on 2020-06-26 13:31:26

0001 // Copyright (c) 2010 Satoshi Nakamoto
0002 // Copyright (c) 2009-2012 The Bitcoin developers
0003 // Distributed under the MIT/X11 software license, see the accompanying
0004 // file license.txt or http://www.opensource.org/licenses/mit-license.php.
0005 
0006 #include "headers.h"
0007 #include "db.h"
0008 #include "net.h"
0009 #include "init.h"
0010 #include "util.h"
0011 #undef printf
0012 #include <boost/asio.hpp>
0013 #include <boost/iostreams/concepts.hpp>
0014 #include <boost/iostreams/stream.hpp>
0015 #include <boost/algorithm/string.hpp>
0016 #include "json/json_spirit_reader_template.h"
0017 #include "json/json_spirit_writer_template.h"
0018 #include "json/json_spirit_utils.h"
0019 #define printf OutputDebugStringF
0020 // MinGW 3.4.5 gets "fatal error: had to relocate PCH" if the json headers are
0021 // precompiled in headers.h.  The problem might be when the pch file goes over
0022 // a certain size around 145MB.  If we need access to json_spirit outside this
0023 // file, we could use the compiled json_spirit option.
0024 
0025 // v0.5.4 RELEASE (keccak)
0026 
0027 using namespace std;
0028 using namespace boost;
0029 using namespace boost::asio;
0030 using namespace json_spirit;
0031 
0032 void ThreadRPCServer2(void* parg);
0033 typedef Value(*rpcfn_type)(const Array& params, bool fHelp);
0034 extern map<string, rpcfn_type> mapCallTable;
0035 
0036 static std::string strRPCUserColonPass;
0037 
0038 static int64 nWalletUnlockTime;
0039 static CCriticalSection cs_nWalletUnlockTime;
0040 
0041 
0042 Object JSONRPCError(int code, const string& message)
0043 {
0044     Object error;
0045     error.push_back(Pair("code", code));
0046     error.push_back(Pair("message", message));
0047     return error;
0048 }
0049 
0050 
0051 void PrintConsole(const std::string &format, ...)
0052 {
0053     char buffer[50000];
0054     int limit = sizeof(buffer);
0055     va_list arg_ptr;
0056     va_start(arg_ptr, format);
0057     int ret = _vsnprintf(buffer, limit, format.c_str(), arg_ptr);
0058     va_end(arg_ptr);
0059     if (ret < 0 || ret >= limit)
0060     {
0061         ret = limit - 1;
0062         buffer[limit-1] = 0;
0063     }
0064     printf("%s", buffer);
0065     fprintf(stdout, "%s", buffer);
0066 }
0067 
0068 
0069 int64 AmountFromValue(const Value& value)
0070 {
0071     double dAmount = value.get_real();
0072     if (dAmount <= 0.0 || dAmount > 21000000.0)
0073         throw JSONRPCError(-3, "Invalid amount");
0074     int64 nAmount = roundint64(dAmount * COIN);
0075     if (!MoneyRange(nAmount))
0076         throw JSONRPCError(-3, "Invalid amount");
0077     return nAmount;
0078 }
0079 
0080 Value ValueFromAmount(int64 amount)
0081 {
0082     return (double)amount / (double)COIN;
0083 }
0084 
0085 void WalletTxToJSON(const CWalletTx& wtx, Object& entry)
0086 {
0087     entry.push_back(Pair("confirmations", wtx.GetDepthInMainChain()));
0088     entry.push_back(Pair("txid", wtx.GetHash().GetHex()));
0089     entry.push_back(Pair("time", (boost::int64_t)wtx.GetTxTime()));
0090     BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue)
0091         entry.push_back(Pair(item.first, item.second));
0092 }
0093 
0094 string AccountFromValue(const Value& value)
0095 {
0096     string strAccount = value.get_str();
0097     if (strAccount == "*")
0098         throw JSONRPCError(-11, "Invalid account name");
0099     return strAccount;
0100 }
0101 
0102 
0103 
0104 ///
0105 /// Note: This interface may still be subject to change.
0106 ///
0107 
0108 
0109 Value help(const Array& params, bool fHelp)
0110 {
0111     if (fHelp || params.size() > 1)
0112         throw runtime_error(
0113             "help [command]\n"
0114             "List commands, or get help for a command.");
0115 
0116     string strCommand;
0117     if (params.size() > 0)
0118         strCommand = params[0].get_str();
0119 
0120     string strRet;
0121     set<rpcfn_type> setDone;
0122     for (map<string, rpcfn_type>::iterator mi = mapCallTable.begin(); mi != mapCallTable.end(); ++mi)
0123     {
0124         string strMethod = (*mi).first;
0125         // We already filter duplicates, but these deprecated screw up the sort order
0126         if (strMethod == "getamountreceived" ||
0127             strMethod == "getallreceived" ||
0128             strMethod == "getblocknumber" || // deprecated
0129             (strMethod.find("label") != string::npos))
0130             continue;
0131         if (strCommand != "" && strMethod != strCommand)
0132             continue;
0133         try
0134         {
0135             Array params;
0136             rpcfn_type pfn = (*mi).second;
0137             if (setDone.insert(pfn).second)
0138                 (*pfn)(params, true);
0139         }
0140         catch (std::exception& e)
0141         {
0142             // Help text is returned in an exception
0143             string strHelp = string(e.what());
0144             if (strCommand == "")
0145                 if (strHelp.find('\n') != -1)
0146                     strHelp = strHelp.substr(0, strHelp.find('\n'));
0147             strRet += strHelp + "\n";
0148         }
0149     }
0150     if (strRet == "")
0151         strRet = strprintf("help: unknown command: %s\n", strCommand.c_str());
0152     strRet = strRet.substr(0,strRet.size()-1);
0153     return strRet;
0154 }
0155 
0156 
0157 Value stop(const Array& params, bool fHelp)
0158 {
0159     if (fHelp || params.size() != 0)
0160         throw runtime_error(
0161             "stop\n"
0162             "Stop bitcoin server.");
0163     // Shutdown will take long enough that the response should get back
0164     CreateThread(Shutdown, NULL);
0165     return "bitcoin server stopping";
0166 }
0167 
0168 
0169 Value getblockcount(const Array& params, bool fHelp)
0170 {
0171     if (fHelp || params.size() != 0)
0172         throw runtime_error(
0173             "getblockcount\n"
0174             "Returns the number of blocks in the longest block chain.");
0175 
0176     return nBestHeight;
0177 }
0178 
0179 
0180 // deprecated
0181 Value getblocknumber(const Array& params, bool fHelp)
0182 {
0183     if (fHelp || params.size() != 0)
0184         throw runtime_error(
0185             "getblocknumber\n"
0186             "Deprecated.  Use getblockcount.");
0187 
0188     return nBestHeight;
0189 }
0190 
0191 
0192 Value getconnectioncount(const Array& params, bool fHelp)
0193 {
0194     if (fHelp || params.size() != 0)
0195         throw runtime_error(
0196             "getconnectioncount\n"
0197             "Returns the number of connections to other nodes.");
0198 
0199     return (int)vNodes.size();
0200 }
0201 
0202 
0203 double GetDifficulty()
0204 {
0205     // Floating point number that is a multiple of the minimum difficulty,
0206     // minimum difficulty = 1.0.
0207 
0208     if (pindexBest == NULL)
0209         return 1.0;
0210     int nShift = (pindexBest->nBits >> 24) & 0xff;
0211 
0212     double dDiff =
0213         (double)0x0000ffff / (double)(pindexBest->nBits & 0x00ffffff);
0214 
0215     while (nShift < 29)
0216     {
0217         dDiff *= 256.0;
0218         nShift++;
0219     }
0220     while (nShift > 29)
0221     {
0222         dDiff /= 256.0;
0223         nShift--;
0224     }
0225 
0226     return dDiff;
0227 }
0228 
0229 Value getdifficulty(const Array& params, bool fHelp)
0230 {
0231     if (fHelp || params.size() != 0)
0232         throw runtime_error(
0233             "getdifficulty\n"
0234             "Returns the proof-of-work difficulty as a multiple of the minimum difficulty.");
0235 
0236     return GetDifficulty();
0237 }
0238 
0239 
0240 Value getgenerate(const Array& params, bool fHelp)
0241 {
0242     if (fHelp || params.size() != 0)
0243         throw runtime_error(
0244             "getgenerate\n"
0245             "Returns true or false.");
0246 
0247     return (bool)fGenerateBitcoins;
0248 }
0249 
0250 
0251 Value setgenerate(const Array& params, bool fHelp)
0252 {
0253     if (fHelp || params.size() < 1 || params.size() > 2)
0254         throw runtime_error(
0255             "setgenerate <generate> [genproclimit]\n"
0256             "<generate> is true or false to turn generation on or off.\n"
0257             "Generation is limited to [genproclimit] processors, -1 is unlimited.");
0258 
0259     bool fGenerate = true;
0260     if (params.size() > 0)
0261         fGenerate = params[0].get_bool();
0262 
0263     if (params.size() > 1)
0264     {
0265         int nGenProcLimit = params[1].get_int();
0266         fLimitProcessors = (nGenProcLimit != -1);
0267         WriteSetting("fLimitProcessors", fLimitProcessors);
0268         if (nGenProcLimit != -1)
0269             WriteSetting("nLimitProcessors", nLimitProcessors = nGenProcLimit);
0270         if (nGenProcLimit == 0)
0271             fGenerate = false;
0272     }
0273 
0274     GenerateBitcoins(fGenerate, pwalletMain);
0275     return Value::null;
0276 }
0277 
0278 
0279 Value gethashespersec(const Array& params, bool fHelp)
0280 {
0281     if (fHelp || params.size() != 0)
0282         throw runtime_error(
0283             "gethashespersec\n"
0284             "Returns a recent hashes per second performance measurement while generating.");
0285 
0286     if (GetTimeMillis() - nHPSTimerStart > 8000)
0287         return (boost::int64_t)0;
0288     return (boost::int64_t)dHashesPerSec;
0289 }
0290 
0291 
0292 Value getinfo(const Array& params, bool fHelp)
0293 {
0294     if (fHelp || params.size() != 0)
0295         throw runtime_error(
0296             "getinfo\n"
0297             "Returns an object containing various state info.");
0298 
0299     Object obj;
0300     obj.push_back(Pair("version",       (int)VERSION));
0301     obj.push_back(Pair("balance",       ValueFromAmount(pwalletMain->GetBalance())));
0302     obj.push_back(Pair("blocks",        (int)nBestHeight));
0303     obj.push_back(Pair("connections",   (int)vNodes.size()));
0304     obj.push_back(Pair("proxy",         (fUseProxy ? addrProxy.ToStringIPPort() : string())));
0305     obj.push_back(Pair("generate",      (bool)fGenerateBitcoins));
0306     obj.push_back(Pair("genproclimit",  (int)(fLimitProcessors ? nLimitProcessors : -1)));
0307     obj.push_back(Pair("difficulty",    (double)GetDifficulty()));
0308     obj.push_back(Pair("hashespersec",  gethashespersec(params, false)));
0309     obj.push_back(Pair("keypoololdest", (boost::int64_t)pwalletMain->GetOldestKeyPoolTime()));
0310     obj.push_back(Pair("keypoolsize",   pwalletMain->GetKeyPoolSize()));
0311     obj.push_back(Pair("paytxfee",      ValueFromAmount(nTransactionFee)));
0312     if (pwalletMain->IsCrypted())
0313         obj.push_back(Pair("unlocked_until", (boost::int64_t)nWalletUnlockTime / 1000));
0314     obj.push_back(Pair("errors",        GetWarnings("statusbar")));
0315     return obj;
0316 }
0317 
0318 
0319 Value getnewaddress(const Array& params, bool fHelp)
0320 {
0321     if (fHelp || params.size() > 1)
0322         throw runtime_error(
0323             "getnewaddress [account]\n"
0324             "Returns a new bitcoin address for receiving payments.  "
0325             "If [account] is specified (recommended), it is added to the address book "
0326             "so payments received with the address will be credited to [account].");
0327 
0328     // Parse the account first so we don't generate a key if there's an error
0329     string strAccount;
0330     if (params.size() > 0)
0331         strAccount = AccountFromValue(params[0]);
0332 
0333     if (!pwalletMain->IsLocked())
0334         pwalletMain->TopUpKeyPool();
0335 
0336     // Generate a new key that is added to wallet
0337     std::vector<unsigned char> newKey;
0338     if (!pwalletMain->GetKeyFromPool(newKey, false))
0339         throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
0340     CBitcoinAddress address(newKey);
0341 
0342     pwalletMain->SetAddressBookName(address, strAccount);
0343 
0344     return address.ToString();
0345 }
0346 
0347 
0348 CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false)
0349 {
0350     CWalletDB walletdb(pwalletMain->strWalletFile);
0351 
0352     CAccount account;
0353     walletdb.ReadAccount(strAccount, account);
0354 
0355     bool bKeyUsed = false;
0356 
0357     // Check if the current key has been used
0358     if (!account.vchPubKey.empty())
0359     {
0360         CScript scriptPubKey;
0361         scriptPubKey.SetBitcoinAddress(account.vchPubKey);
0362         for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
0363              it != pwalletMain->mapWallet.end() && !account.vchPubKey.empty();
0364              ++it)
0365         {
0366             const CWalletTx& wtx = (*it).second;
0367             BOOST_FOREACH(const CTxOut& txout, wtx.vout)
0368                 if (txout.scriptPubKey == scriptPubKey)
0369                     bKeyUsed = true;
0370         }
0371     }
0372 
0373     // Generate a new key
0374     if (account.vchPubKey.empty() || bForceNew || bKeyUsed)
0375     {
0376         if (!pwalletMain->GetKeyFromPool(account.vchPubKey, false))
0377             throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
0378 
0379         pwalletMain->SetAddressBookName(CBitcoinAddress(account.vchPubKey), strAccount);
0380         walletdb.WriteAccount(strAccount, account);
0381     }
0382 
0383     return CBitcoinAddress(account.vchPubKey);
0384 }
0385 
0386 Value getaccountaddress(const Array& params, bool fHelp)
0387 {
0388     if (fHelp || params.size() != 1)
0389         throw runtime_error(
0390             "getaccountaddress <account>\n"
0391             "Returns the current bitcoin address for receiving payments to this account.");
0392 
0393     // Parse the account first so we don't generate a key if there's an error
0394     string strAccount = AccountFromValue(params[0]);
0395 
0396     Value ret;
0397 
0398     ret = GetAccountAddress(strAccount).ToString();
0399 
0400     return ret;
0401 }
0402 
0403 
0404 
0405 Value setaccount(const Array& params, bool fHelp)
0406 {
0407     if (fHelp || params.size() < 1 || params.size() > 2)
0408         throw runtime_error(
0409             "setaccount <bitcoinaddress> <account>\n"
0410             "Sets the account associated with the given address.");
0411 
0412     CBitcoinAddress address(params[0].get_str());
0413     if (!address.IsValid())
0414         throw JSONRPCError(-5, "Invalid bitcoin address");
0415 
0416 
0417     string strAccount;
0418     if (params.size() > 1)
0419         strAccount = AccountFromValue(params[1]);
0420 
0421     // Detect when changing the account of an address that is the 'unused current key' of another account:
0422     if (pwalletMain->mapAddressBook.count(address))
0423     {
0424         string strOldAccount = pwalletMain->mapAddressBook[address];
0425         if (address == GetAccountAddress(strOldAccount))
0426             GetAccountAddress(strOldAccount, true);
0427     }
0428 
0429     pwalletMain->SetAddressBookName(address, strAccount);
0430 
0431     return Value::null;
0432 }
0433 
0434 
0435 Value getaccount(const Array& params, bool fHelp)
0436 {
0437     if (fHelp || params.size() != 1)
0438         throw runtime_error(
0439             "getaccount <bitcoinaddress>\n"
0440             "Returns the account associated with the given address.");
0441 
0442     CBitcoinAddress address(params[0].get_str());
0443     if (!address.IsValid())
0444         throw JSONRPCError(-5, "Invalid bitcoin address");
0445 
0446     string strAccount;
0447     map<CBitcoinAddress, string>::iterator mi = pwalletMain->mapAddressBook.find(address);
0448     if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.empty())
0449         strAccount = (*mi).second;
0450     return strAccount;
0451 }
0452 
0453 
0454 Value getaddressesbyaccount(const Array& params, bool fHelp)
0455 {
0456     if (fHelp || params.size() != 1)
0457         throw runtime_error(
0458             "getaddressesbyaccount <account>\n"
0459             "Returns the list of addresses for the given account.");
0460 
0461     string strAccount = AccountFromValue(params[0]);
0462 
0463     // Find all addresses that have the given account
0464     Array ret;
0465     BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
0466     {
0467         const CBitcoinAddress& address = item.first;
0468         const string& strName = item.second;
0469         if (strName == strAccount)
0470             ret.push_back(address.ToString());
0471     }
0472     return ret;
0473 }
0474 
0475 Value settxfee(const Array& params, bool fHelp)
0476 {
0477     if (fHelp || params.size() < 1 || params.size() > 1)
0478         throw runtime_error(
0479             "settxfee <amount>\n"
0480             "<amount> is a real and is rounded to the nearest 0.00000001");
0481 
0482     // Amount
0483     int64 nAmount = 0;
0484     if (params[0].get_real() != 0.0)
0485         nAmount = AmountFromValue(params[0]);        // rejects 0.0 amounts
0486 
0487     nTransactionFee = nAmount;
0488     return true;
0489 }
0490 
0491 Value sendtoaddress(const Array& params, bool fHelp)
0492 {
0493     if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
0494         throw runtime_error(
0495             "sendtoaddress <bitcoinaddress> <amount> [comment] [comment-to]\n"
0496             "<amount> is a real and is rounded to the nearest 0.00000001\n"
0497             "requires wallet passphrase to be set with walletpassphrase first");
0498     if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
0499         throw runtime_error(
0500             "sendtoaddress <bitcoinaddress> <amount> [comment] [comment-to]\n"
0501             "<amount> is a real and is rounded to the nearest 0.00000001");
0502 
0503     CBitcoinAddress address(params[0].get_str());
0504     if (!address.IsValid())
0505         throw JSONRPCError(-5, "Invalid bitcoin address");
0506 
0507     // Amount
0508     int64 nAmount = AmountFromValue(params[1]);
0509 
0510     // Wallet comments
0511     CWalletTx wtx;
0512     if (params.size() > 2 && params[2].type() != null_type && !params[2].get_str().empty())
0513         wtx.mapValue["comment"] = params[2].get_str();
0514     if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
0515         wtx.mapValue["to"]      = params[3].get_str();
0516 
0517     if (pwalletMain->IsLocked())
0518         throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
0519 
0520     string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
0521     if (strError != "")
0522         throw JSONRPCError(-4, strError);
0523 
0524     return wtx.GetHash().GetHex();
0525 }
0526 
0527 static const string strMessageMagic = "Bitcoin Signed Message:\n";
0528 
0529 Value signmessage(const Array& params, bool fHelp)
0530 {
0531     if (fHelp || params.size() != 2)
0532         throw runtime_error(
0533             "signmessage <bitcoinaddress> <message>\n"
0534             "Sign a message with the private key of an address");
0535 
0536     if (pwalletMain->IsLocked())
0537         throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
0538 
0539     string strAddress = params[0].get_str();
0540     string strMessage = params[1].get_str();
0541 
0542     CBitcoinAddress addr(strAddress);
0543     if (!addr.IsValid())
0544         throw JSONRPCError(-3, "Invalid address");
0545 
0546     CKey key;
0547     if (!pwalletMain->GetKey(addr, key))
0548         throw JSONRPCError(-4, "Private key not available");
0549 
0550     CDataStream ss(SER_GETHASH);
0551     ss << strMessageMagic;
0552     ss << strMessage;
0553 
0554     vector<unsigned char> vchSig;
0555     if (!key.SignCompact(Hash(ss.begin(), ss.end()), vchSig))
0556         throw JSONRPCError(-5, "Sign failed");
0557 
0558     return EncodeBase64(&vchSig[0], vchSig.size());
0559 }
0560 
0561 Value verifymessage(const Array& params, bool fHelp)
0562 {
0563     if (fHelp || params.size() != 3)
0564         throw runtime_error(
0565             "verifymessage <bitcoinaddress> <signature> <message>\n"
0566             "Verify a signed message");
0567 
0568     string strAddress  = params[0].get_str();
0569     string strSign     = params[1].get_str();
0570     string strMessage  = params[2].get_str();
0571 
0572     CBitcoinAddress addr(strAddress);
0573     if (!addr.IsValid())
0574         throw JSONRPCError(-3, "Invalid address");
0575 
0576     bool fInvalid = false;
0577     vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid);
0578 
0579     if (fInvalid)
0580         throw JSONRPCError(-5, "Malformed base64 encoding");
0581 
0582     CDataStream ss(SER_GETHASH);
0583     ss << strMessageMagic;
0584     ss << strMessage;
0585 
0586     CKey key;
0587     if (!key.SetCompactSignature(Hash(ss.begin(), ss.end()), vchSig))
0588         return false;
0589 
0590     return (CBitcoinAddress(key.GetPubKey()) == addr);
0591 }
0592 
0593 
0594 Value getreceivedbyaddress(const Array& params, bool fHelp)
0595 {
0596     if (fHelp || params.size() < 1 || params.size() > 2)
0597         throw runtime_error(
0598             "getreceivedbyaddress <bitcoinaddress> [minconf=1]\n"
0599             "Returns the total amount received by <bitcoinaddress> in transactions with at least [minconf] confirmations.");
0600 
0601     // Bitcoin address
0602     CBitcoinAddress address = CBitcoinAddress(params[0].get_str());
0603     CScript scriptPubKey;
0604     if (!address.IsValid())
0605         throw JSONRPCError(-5, "Invalid bitcoin address");
0606     scriptPubKey.SetBitcoinAddress(address);
0607     if (!IsMine(*pwalletMain,scriptPubKey))
0608         return (double)0.0;
0609 
0610     // Minimum confirmations
0611     int nMinDepth = 1;
0612     if (params.size() > 1)
0613         nMinDepth = params[1].get_int();
0614 
0615     // Tally
0616     int64 nAmount = 0;
0617     for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
0618     {
0619         const CWalletTx& wtx = (*it).second;
0620         if (wtx.IsCoinBase() || !wtx.IsFinal())
0621             continue;
0622 
0623         BOOST_FOREACH(const CTxOut& txout, wtx.vout)
0624             if (txout.scriptPubKey == scriptPubKey)
0625                 if (wtx.GetDepthInMainChain() >= nMinDepth)
0626                     nAmount += txout.nValue;
0627     }
0628 
0629     return  ValueFromAmount(nAmount);
0630 }
0631 
0632 
0633 void GetAccountAddresses(string strAccount, set<CBitcoinAddress>& setAddress)
0634 {
0635     BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
0636     {
0637         const CBitcoinAddress& address = item.first;
0638         const string& strName = item.second;
0639         if (strName == strAccount)
0640             setAddress.insert(address);
0641     }
0642 }
0643 
0644 
0645 Value getreceivedbyaccount(const Array& params, bool fHelp)
0646 {
0647     if (fHelp || params.size() < 1 || params.size() > 2)
0648         throw runtime_error(
0649             "getreceivedbyaccount <account> [minconf=1]\n"
0650             "Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.");
0651 
0652     // Minimum confirmations
0653     int nMinDepth = 1;
0654     if (params.size() > 1)
0655         nMinDepth = params[1].get_int();
0656 
0657     // Get the set of pub keys that have the label
0658     string strAccount = AccountFromValue(params[0]);
0659     set<CBitcoinAddress> setAddress;
0660     GetAccountAddresses(strAccount, setAddress);
0661 
0662     // Tally
0663     int64 nAmount = 0;
0664     for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
0665     {
0666         const CWalletTx& wtx = (*it).second;
0667         if (wtx.IsCoinBase() || !wtx.IsFinal())
0668             continue;
0669 
0670         BOOST_FOREACH(const CTxOut& txout, wtx.vout)
0671         {
0672             CBitcoinAddress address;
0673             if (ExtractAddress(txout.scriptPubKey, pwalletMain, address) && setAddress.count(address))
0674                 if (wtx.GetDepthInMainChain() >= nMinDepth)
0675                     nAmount += txout.nValue;
0676         }
0677     }
0678 
0679     return (double)nAmount / (double)COIN;
0680 }
0681 
0682 
0683 int64 GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth)
0684 {
0685     int64 nBalance = 0;
0686 
0687     // Tally wallet transactions
0688     for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
0689     {
0690         const CWalletTx& wtx = (*it).second;
0691         if (!wtx.IsFinal())
0692             continue;
0693 
0694         int64 nGenerated, nReceived, nSent, nFee;
0695         wtx.GetAccountAmounts(strAccount, nGenerated, nReceived, nSent, nFee);
0696 
0697         if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
0698             nBalance += nReceived;
0699         nBalance += nGenerated - nSent - nFee;
0700     }
0701 
0702     // Tally internal accounting entries
0703     nBalance += walletdb.GetAccountCreditDebit(strAccount);
0704 
0705     return nBalance;
0706 }
0707 
0708 int64 GetAccountBalance(const string& strAccount, int nMinDepth)
0709 {
0710     CWalletDB walletdb(pwalletMain->strWalletFile);
0711     return GetAccountBalance(walletdb, strAccount, nMinDepth);
0712 }
0713 
0714 
0715 Value getbalance(const Array& params, bool fHelp)
0716 {
0717     if (fHelp || params.size() > 2)
0718         throw runtime_error(
0719             "getbalance [account] [minconf=1]\n"
0720             "If [account] is not specified, returns the server's total available balance.\n"
0721             "If [account] is specified, returns the balance in the account.");
0722 
0723     if (params.size() == 0)
0724         return  ValueFromAmount(pwalletMain->GetBalance());
0725 
0726     int nMinDepth = 1;
0727     if (params.size() > 1)
0728         nMinDepth = params[1].get_int();
0729 
0730     if (params[0].get_str() == "*") {
0731         // Calculate total balance a different way from GetBalance()
0732         // (GetBalance() sums up all unspent TxOuts)
0733         // getbalance and getbalance '*' should always return the same number.
0734         int64 nBalance = 0;
0735         for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
0736         {
0737             const CWalletTx& wtx = (*it).second;
0738             if (!wtx.IsFinal())
0739                 continue;
0740 
0741             int64 allGeneratedImmature, allGeneratedMature, allFee;
0742             allGeneratedImmature = allGeneratedMature = allFee = 0;
0743             string strSentAccount;
0744             list<pair<CBitcoinAddress, int64> > listReceived;
0745             list<pair<CBitcoinAddress, int64> > listSent;
0746             wtx.GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount);
0747             if (wtx.GetDepthInMainChain() >= nMinDepth)
0748                 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listReceived)
0749                     nBalance += r.second;
0750             BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listSent)
0751                 nBalance -= r.second;
0752             nBalance -= allFee;
0753             nBalance += allGeneratedMature;
0754         }
0755         return  ValueFromAmount(nBalance);
0756     }
0757 
0758     string strAccount = AccountFromValue(params[0]);
0759 
0760     int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
0761 
0762     return ValueFromAmount(nBalance);
0763 }
0764 
0765 
0766 Value movecmd(const Array& params, bool fHelp)
0767 {
0768     if (fHelp || params.size() < 3 || params.size() > 5)
0769         throw runtime_error(
0770             "move <fromaccount> <toaccount> <amount> [minconf=1] [comment]\n"
0771             "Move from one account in your wallet to another.");
0772 
0773     string strFrom = AccountFromValue(params[0]);
0774     string strTo = AccountFromValue(params[1]);
0775     int64 nAmount = AmountFromValue(params[2]);
0776     if (params.size() > 3)
0777         // unused parameter, used to be nMinDepth, keep type-checking it though
0778         (void)params[3].get_int();
0779     string strComment;
0780     if (params.size() > 4)
0781         strComment = params[4].get_str();
0782 
0783     CWalletDB walletdb(pwalletMain->strWalletFile);
0784     walletdb.TxnBegin();
0785 
0786     int64 nNow = GetAdjustedTime();
0787 
0788     // Debit
0789     CAccountingEntry debit;
0790     debit.strAccount = strFrom;
0791     debit.nCreditDebit = -nAmount;
0792     debit.nTime = nNow;
0793     debit.strOtherAccount = strTo;
0794     debit.strComment = strComment;
0795     walletdb.WriteAccountingEntry(debit);
0796 
0797     // Credit
0798     CAccountingEntry credit;
0799     credit.strAccount = strTo;
0800     credit.nCreditDebit = nAmount;
0801     credit.nTime = nNow;
0802     credit.strOtherAccount = strFrom;
0803     credit.strComment = strComment;
0804     walletdb.WriteAccountingEntry(credit);
0805 
0806     walletdb.TxnCommit();
0807 
0808     return true;
0809 }
0810 
0811 
0812 Value sendfrom(const Array& params, bool fHelp)
0813 {
0814     if (pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
0815         throw runtime_error(
0816             "sendfrom <fromaccount> <tobitcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
0817             "<amount> is a real and is rounded to the nearest 0.00000001\n"
0818             "requires wallet passphrase to be set with walletpassphrase first");
0819     if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
0820         throw runtime_error(
0821             "sendfrom <fromaccount> <tobitcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
0822             "<amount> is a real and is rounded to the nearest 0.00000001");
0823 
0824     string strAccount = AccountFromValue(params[0]);
0825     CBitcoinAddress address(params[1].get_str());
0826     if (!address.IsValid())
0827         throw JSONRPCError(-5, "Invalid bitcoin address");
0828     int64 nAmount = AmountFromValue(params[2]);
0829     int nMinDepth = 1;
0830     if (params.size() > 3)
0831         nMinDepth = params[3].get_int();
0832 
0833     CWalletTx wtx;
0834     wtx.strFromAccount = strAccount;
0835     if (params.size() > 4 && params[4].type() != null_type && !params[4].get_str().empty())
0836         wtx.mapValue["comment"] = params[4].get_str();
0837     if (params.size() > 5 && params[5].type() != null_type && !params[5].get_str().empty())
0838         wtx.mapValue["to"]      = params[5].get_str();
0839 
0840     if (pwalletMain->IsLocked())
0841         throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
0842 
0843     // Check funds
0844     int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
0845     if (nAmount > nBalance)
0846         throw JSONRPCError(-6, "Account has insufficient funds");
0847 
0848     // Send
0849     string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
0850     if (strError != "")
0851         throw JSONRPCError(-4, strError);
0852 
0853     return wtx.GetHash().GetHex();
0854 }
0855 
0856 
0857 Value sendmany(const Array& params, bool fHelp)
0858 {
0859     if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
0860         throw runtime_error(
0861             "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
0862             "amounts are double-precision floating point numbers\n"
0863             "requires wallet passphrase to be set with walletpassphrase first");
0864     if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
0865         throw runtime_error(
0866             "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
0867             "amounts are double-precision floating point numbers");
0868 
0869     string strAccount = AccountFromValue(params[0]);
0870     Object sendTo = params[1].get_obj();
0871     int nMinDepth = 1;
0872     if (params.size() > 2)
0873         nMinDepth = params[2].get_int();
0874 
0875     CWalletTx wtx;
0876     wtx.strFromAccount = strAccount;
0877     if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
0878         wtx.mapValue["comment"] = params[3].get_str();
0879 
0880     set<CBitcoinAddress> setAddress;
0881     vector<pair<CScript, int64> > vecSend;
0882 
0883     int64 totalAmount = 0;
0884     BOOST_FOREACH(const Pair& s, sendTo)
0885     {
0886         CBitcoinAddress address(s.name_);
0887         if (!address.IsValid())
0888             throw JSONRPCError(-5, string("Invalid bitcoin address:")+s.name_);
0889 
0890         if (setAddress.count(address))
0891             throw JSONRPCError(-8, string("Invalid parameter, duplicated address: ")+s.name_);
0892         setAddress.insert(address);
0893 
0894         CScript scriptPubKey;
0895         scriptPubKey.SetBitcoinAddress(address);
0896         int64 nAmount = AmountFromValue(s.value_); 
0897         totalAmount += nAmount;
0898 
0899         vecSend.push_back(make_pair(scriptPubKey, nAmount));
0900     }
0901 
0902     if (pwalletMain->IsLocked())
0903         throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
0904 
0905     // Check funds
0906     int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
0907     if (totalAmount > nBalance)
0908         throw JSONRPCError(-6, "Account has insufficient funds");
0909 
0910     // Send
0911     CReserveKey keyChange(pwalletMain);
0912     int64 nFeeRequired = 0;
0913     bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired);
0914     if (!fCreated)
0915     {
0916         if (totalAmount + nFeeRequired > pwalletMain->GetBalance())
0917             throw JSONRPCError(-6, "Insufficient funds");
0918         throw JSONRPCError(-4, "Transaction creation failed");
0919     }
0920     if (!pwalletMain->CommitTransaction(wtx, keyChange))
0921         throw JSONRPCError(-4, "Transaction commit failed");
0922 
0923     return wtx.GetHash().GetHex();
0924 }
0925 
0926 
0927 struct tallyitem
0928 {
0929     int64 nAmount;
0930     int nConf;
0931     tallyitem()
0932     {
0933         nAmount = 0;
0934         nConf = INT_MAX;
0935     }
0936 };
0937 
0938 Value ListReceived(const Array& params, bool fByAccounts)
0939 {
0940     // Minimum confirmations
0941     int nMinDepth = 1;
0942     if (params.size() > 0)
0943         nMinDepth = params[0].get_int();
0944 
0945     // Whether to include empty accounts
0946     bool fIncludeEmpty = false;
0947     if (params.size() > 1)
0948         fIncludeEmpty = params[1].get_bool();
0949 
0950     // Tally
0951     map<CBitcoinAddress, tallyitem> mapTally;
0952     for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
0953     {
0954         const CWalletTx& wtx = (*it).second;
0955         if (wtx.IsCoinBase() || !wtx.IsFinal())
0956             continue;
0957 
0958         int nDepth = wtx.GetDepthInMainChain();
0959         if (nDepth < nMinDepth)
0960             continue;
0961 
0962         BOOST_FOREACH(const CTxOut& txout, wtx.vout)
0963         {
0964             CBitcoinAddress address;
0965             if (!ExtractAddress(txout.scriptPubKey, pwalletMain, address) || !address.IsValid())
0966                 continue;
0967 
0968             tallyitem& item = mapTally[address];
0969             item.nAmount += txout.nValue;
0970             item.nConf = min(item.nConf, nDepth);
0971         }
0972     }
0973 
0974     // Reply
0975     Array ret;
0976     map<string, tallyitem> mapAccountTally;
0977     BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
0978     {
0979         const CBitcoinAddress& address = item.first;
0980         const string& strAccount = item.second;
0981         map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
0982         if (it == mapTally.end() && !fIncludeEmpty)
0983             continue;
0984 
0985         int64 nAmount = 0;
0986         int nConf = INT_MAX;
0987         if (it != mapTally.end())
0988         {
0989             nAmount = (*it).second.nAmount;
0990             nConf = (*it).second.nConf;
0991         }
0992 
0993         if (fByAccounts)
0994         {
0995             tallyitem& item = mapAccountTally[strAccount];
0996             item.nAmount += nAmount;
0997             item.nConf = min(item.nConf, nConf);
0998         }
0999         else
1000         {
1001             Object obj;
1002             obj.push_back(Pair("address",       address.ToString()));
1003             obj.push_back(Pair("account",       strAccount));
1004             obj.push_back(Pair("amount",        ValueFromAmount(nAmount)));
1005             obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf)));
1006             ret.push_back(obj);
1007         }
1008     }
1009 
1010     if (fByAccounts)
1011     {
1012         for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
1013         {
1014             int64 nAmount = (*it).second.nAmount;
1015             int nConf = (*it).second.nConf;
1016             Object obj;
1017             obj.push_back(Pair("account",       (*it).first));
1018             obj.push_back(Pair("amount",        ValueFromAmount(nAmount)));
1019             obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf)));
1020             ret.push_back(obj);
1021         }
1022     }
1023 
1024     return ret;
1025 }
1026 
1027 Value listreceivedbyaddress(const Array& params, bool fHelp)
1028 {
1029     if (fHelp || params.size() > 2)
1030         throw runtime_error(
1031             "listreceivedbyaddress [minconf=1] [includeempty=false]\n"
1032             "[minconf] is the minimum number of confirmations before payments are included.\n"
1033             "[includeempty] whether to include addresses that haven't received any payments.\n"
1034             "Returns an array of objects containing:\n"
1035             "  \"address\" : receiving address\n"
1036             "  \"account\" : the account of the receiving address\n"
1037             "  \"amount\" : total amount received by the address\n"
1038             "  \"confirmations\" : number of confirmations of the most recent transaction included");
1039 
1040     return ListReceived(params, false);
1041 }
1042 
1043 Value listreceivedbyaccount(const Array& params, bool fHelp)
1044 {
1045     if (fHelp || params.size() > 2)
1046         throw runtime_error(
1047             "listreceivedbyaccount [minconf=1] [includeempty=false]\n"
1048             "[minconf] is the minimum number of confirmations before payments are included.\n"
1049             "[includeempty] whether to include accounts that haven't received any payments.\n"
1050             "Returns an array of objects containing:\n"
1051             "  \"account\" : the account of the receiving addresses\n"
1052             "  \"amount\" : total amount received by addresses with this account\n"
1053             "  \"confirmations\" : number of confirmations of the most recent transaction included");
1054 
1055     return ListReceived(params, true);
1056 }
1057 
1058 void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret)
1059 {
1060     int64 nGeneratedImmature, nGeneratedMature, nFee;
1061     string strSentAccount;
1062     list<pair<CBitcoinAddress, int64> > listReceived;
1063     list<pair<CBitcoinAddress, int64> > listSent;
1064     wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1065 
1066     bool fAllAccounts = (strAccount == string("*"));
1067 
1068     // Generated blocks assigned to account ""
1069     if ((nGeneratedMature+nGeneratedImmature) != 0 && (fAllAccounts || strAccount == ""))
1070     {
1071         Object entry;
1072         entry.push_back(Pair("account", string("")));
1073         if (nGeneratedImmature)
1074         {
1075             entry.push_back(Pair("category", wtx.GetDepthInMainChain() ? "immature" : "orphan"));
1076             entry.push_back(Pair("amount", ValueFromAmount(nGeneratedImmature)));
1077         }
1078         else
1079         {
1080             entry.push_back(Pair("category", "generate"));
1081             entry.push_back(Pair("amount", ValueFromAmount(nGeneratedMature)));
1082         }
1083         if (fLong)
1084             WalletTxToJSON(wtx, entry);
1085         ret.push_back(entry);
1086     }
1087 
1088     // Sent
1089     if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
1090     {
1091         BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1092         {
1093             Object entry;
1094             entry.push_back(Pair("account", strSentAccount));
1095             entry.push_back(Pair("address", s.first.ToString()));
1096             entry.push_back(Pair("category", "send"));
1097             entry.push_back(Pair("amount", ValueFromAmount(-s.second)));
1098             entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
1099             if (fLong)
1100                 WalletTxToJSON(wtx, entry);
1101             ret.push_back(entry);
1102         }
1103     }
1104 
1105     // Received
1106     if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
1107         BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1108         {
1109             string account;
1110             if (pwalletMain->mapAddressBook.count(r.first))
1111                 account = pwalletMain->mapAddressBook[r.first];
1112             if (fAllAccounts || (account == strAccount))
1113             {
1114                 Object entry;
1115                 entry.push_back(Pair("account", account));
1116                 entry.push_back(Pair("address", r.first.ToString()));
1117                 entry.push_back(Pair("category", "receive"));
1118                 entry.push_back(Pair("amount", ValueFromAmount(r.second)));
1119                 if (fLong)
1120                     WalletTxToJSON(wtx, entry);
1121                 ret.push_back(entry);
1122             }
1123         }
1124 }
1125 
1126 void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret)
1127 {
1128     bool fAllAccounts = (strAccount == string("*"));
1129 
1130     if (fAllAccounts || acentry.strAccount == strAccount)
1131     {
1132         Object entry;
1133         entry.push_back(Pair("account", acentry.strAccount));
1134         entry.push_back(Pair("category", "move"));
1135         entry.push_back(Pair("time", (boost::int64_t)acentry.nTime));
1136         entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
1137         entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
1138         entry.push_back(Pair("comment", acentry.strComment));
1139         ret.push_back(entry);
1140     }
1141 }
1142 
1143 Value listtransactions(const Array& params, bool fHelp)
1144 {
1145     if (fHelp || params.size() > 3)
1146         throw runtime_error(
1147             "listtransactions [account] [count=10] [from=0]\n"
1148             "Returns up to [count] most recent transactions skipping the first [from] transactions for account [account].");
1149 
1150     string strAccount = "*";
1151     if (params.size() > 0)
1152         strAccount = params[0].get_str();
1153     int nCount = 10;
1154     if (params.size() > 1)
1155         nCount = params[1].get_int();
1156     int nFrom = 0;
1157     if (params.size() > 2)
1158         nFrom = params[2].get_int();
1159 
1160     Array ret;
1161     CWalletDB walletdb(pwalletMain->strWalletFile);
1162 
1163     // Firs: get all CWalletTx and CAccountingEntry into a sorted-by-time multimap:
1164     typedef pair<CWalletTx*, CAccountingEntry*> TxPair;
1165     typedef multimap<int64, TxPair > TxItems;
1166     TxItems txByTime;
1167 
1168     for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1169     {
1170         CWalletTx* wtx = &((*it).second);
1171         txByTime.insert(make_pair(wtx->GetTxTime(), TxPair(wtx, (CAccountingEntry*)0)));
1172     }
1173     list<CAccountingEntry> acentries;
1174     walletdb.ListAccountCreditDebit(strAccount, acentries);
1175     BOOST_FOREACH(CAccountingEntry& entry, acentries)
1176     {
1177         txByTime.insert(make_pair(entry.nTime, TxPair((CWalletTx*)0, &entry)));
1178     }
1179 
1180     // Now: iterate backwards until we have nCount items to return:
1181     TxItems::reverse_iterator it = txByTime.rbegin();
1182     if (txByTime.size() > nFrom) std::advance(it, nFrom);
1183     for (; it != txByTime.rend(); ++it)
1184     {
1185         CWalletTx *const pwtx = (*it).second.first;
1186         if (pwtx != 0)
1187             ListTransactions(*pwtx, strAccount, 0, true, ret);
1188         CAccountingEntry *const pacentry = (*it).second.second;
1189         if (pacentry != 0)
1190             AcentryToJSON(*pacentry, strAccount, ret);
1191 
1192         if (ret.size() >= nCount) break;
1193     }
1194     // ret is now newest to oldest
1195     
1196     // Make sure we return only last nCount items (sends-to-self might give us an extra):
1197     if (ret.size() > nCount)
1198     {
1199         Array::iterator last = ret.begin();
1200         std::advance(last, nCount);
1201         ret.erase(last, ret.end());
1202     }
1203     std::reverse(ret.begin(), ret.end()); // oldest to newest
1204 
1205     return ret;
1206 }
1207 
1208 Value listaccounts(const Array& params, bool fHelp)
1209 {
1210     if (fHelp || params.size() > 1)
1211         throw runtime_error(
1212             "listaccounts [minconf=1]\n"
1213             "Returns Object that has account names as keys, account balances as values.");
1214 
1215     int nMinDepth = 1;
1216     if (params.size() > 0)
1217         nMinDepth = params[0].get_int();
1218 
1219     map<string, int64> mapAccountBalances;
1220     BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& entry, pwalletMain->mapAddressBook) {
1221         if (pwalletMain->HaveKey(entry.first)) // This address belongs to me
1222             mapAccountBalances[entry.second] = 0;
1223     }
1224 
1225     for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1226     {
1227         const CWalletTx& wtx = (*it).second;
1228         int64 nGeneratedImmature, nGeneratedMature, nFee;
1229         string strSentAccount;
1230         list<pair<CBitcoinAddress, int64> > listReceived;
1231         list<pair<CBitcoinAddress, int64> > listSent;
1232         wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1233         mapAccountBalances[strSentAccount] -= nFee;
1234         BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1235             mapAccountBalances[strSentAccount] -= s.second;
1236         if (wtx.GetDepthInMainChain() >= nMinDepth)
1237         {
1238             mapAccountBalances[""] += nGeneratedMature;
1239             BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1240                 if (pwalletMain->mapAddressBook.count(r.first))
1241                     mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second;
1242                 else
1243                     mapAccountBalances[""] += r.second;
1244         }
1245     }
1246 
1247     list<CAccountingEntry> acentries;
1248     CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
1249     BOOST_FOREACH(const CAccountingEntry& entry, acentries)
1250         mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
1251 
1252     Object ret;
1253     BOOST_FOREACH(const PAIRTYPE(string, int64)& accountBalance, mapAccountBalances) {
1254         ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
1255     }
1256     return ret;
1257 }
1258 
1259 Value listsinceblock(const Array& params, bool fHelp)
1260 {
1261     if (fHelp)
1262         throw runtime_error(
1263             "listsinceblock [blockid] [target-confirmations]\n"
1264             "Get all transactions in blocks since block [blockid], or all transactions if omitted");
1265 
1266     CBlockIndex *pindex = NULL;
1267     int target_confirms = 1;
1268 
1269     if (params.size() > 0)
1270     {
1271         uint256 blockId = 0;
1272 
1273         blockId.SetHex(params[0].get_str());
1274         pindex = CBlockLocator(blockId).GetBlockIndex();
1275     }
1276 
1277     if (params.size() > 1)
1278     {
1279         target_confirms = params[1].get_int();
1280 
1281         if (target_confirms < 1)
1282             throw JSONRPCError(-8, "Invalid parameter");
1283     }
1284 
1285     int depth = pindex ? (1 + nBestHeight - pindex->nHeight) : -1;
1286 
1287     Array transactions;
1288 
1289     for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++)
1290     {
1291         CWalletTx tx = (*it).second;
1292 
1293         if (depth == -1 || tx.GetDepthInMainChain() < depth)
1294             ListTransactions(tx, "*", 0, true, transactions);
1295     }
1296 
1297     uint256 lastblock;
1298 
1299     if (target_confirms == 1)
1300     {
1301         printf("oops!\n");
1302         lastblock = hashBestChain;
1303     }
1304     else
1305     {
1306         int target_height = pindexBest->nHeight + 1 - target_confirms;
1307 
1308         CBlockIndex *block;
1309         for (block = pindexBest;
1310              block && block->nHeight > target_height;
1311              block = block->pprev)  { }
1312 
1313         lastblock = block ? block->GetBlockHash() : 0;
1314     }
1315 
1316     Object ret;
1317     ret.push_back(Pair("transactions", transactions));
1318     ret.push_back(Pair("lastblock", lastblock.GetHex()));
1319 
1320     return ret;
1321 }
1322 
1323 Value gettransaction(const Array& params, bool fHelp)
1324 {
1325     if (fHelp || params.size() != 1)
1326         throw runtime_error(
1327             "gettransaction <txid>\n"
1328             "Get detailed information about <txid>");
1329 
1330     uint256 hash;
1331     hash.SetHex(params[0].get_str());
1332 
1333     Object entry;
1334 
1335     if (!pwalletMain->mapWallet.count(hash))
1336         throw JSONRPCError(-5, "Invalid or non-wallet transaction id");
1337     const CWalletTx& wtx = pwalletMain->mapWallet[hash];
1338 
1339     int64 nCredit = wtx.GetCredit();
1340     int64 nDebit = wtx.GetDebit();
1341     int64 nNet = nCredit - nDebit;
1342     int64 nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0);
1343 
1344     entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
1345     if (wtx.IsFromMe())
1346         entry.push_back(Pair("fee", ValueFromAmount(nFee)));
1347 
1348     WalletTxToJSON(pwalletMain->mapWallet[hash], entry);
1349 
1350     Array details;
1351     ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details);
1352     entry.push_back(Pair("details", details));
1353 
1354     return entry;
1355 }
1356 
1357 
1358 Value backupwallet(const Array& params, bool fHelp)
1359 {
1360     if (fHelp || params.size() != 1)
1361         throw runtime_error(
1362             "backupwallet <destination>\n"
1363             "Safely copies wallet.dat to destination, which can be a directory or a path with filename.");
1364 
1365     string strDest = params[0].get_str();
1366     BackupWallet(*pwalletMain, strDest);
1367 
1368     return Value::null;
1369 }
1370 
1371 
1372 Value keypoolrefill(const Array& params, bool fHelp)
1373 {
1374     if (pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1375         throw runtime_error(
1376             "keypoolrefill\n"
1377             "Fills the keypool, requires wallet passphrase to be set.");
1378     if (!pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1379         throw runtime_error(
1380             "keypoolrefill\n"
1381             "Fills the keypool.");
1382 
1383     if (pwalletMain->IsLocked())
1384         throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
1385 
1386     pwalletMain->TopUpKeyPool();
1387 
1388     if (pwalletMain->GetKeyPoolSize() < GetArg("-keypool", 100))
1389         throw JSONRPCError(-4, "Error refreshing keypool.");
1390 
1391     return Value::null;
1392 }
1393 
1394 
1395 void ThreadTopUpKeyPool(void* parg)
1396 {
1397     pwalletMain->TopUpKeyPool();
1398 }
1399 
1400 void ThreadCleanWalletPassphrase(void* parg)
1401 {
1402     int64 nMyWakeTime = GetTimeMillis() + *((int64*)parg) * 1000;
1403 
1404     ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1405 
1406     if (nWalletUnlockTime == 0)
1407     {
1408         nWalletUnlockTime = nMyWakeTime;
1409 
1410         do
1411         {
1412             if (nWalletUnlockTime==0)
1413                 break;
1414             int64 nToSleep = nWalletUnlockTime - GetTimeMillis();
1415             if (nToSleep <= 0)
1416                 break;
1417 
1418             LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1419             Sleep(nToSleep);
1420             ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1421 
1422         } while(1);
1423 
1424         if (nWalletUnlockTime)
1425         {
1426             nWalletUnlockTime = 0;
1427             pwalletMain->Lock();
1428         }
1429     }
1430     else
1431     {
1432         if (nWalletUnlockTime < nMyWakeTime)
1433             nWalletUnlockTime = nMyWakeTime;
1434     }
1435 
1436     LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1437 
1438     delete (int64*)parg;
1439 }
1440 
1441 Value walletpassphrase(const Array& params, bool fHelp)
1442 {
1443     if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1444         throw runtime_error(
1445             "walletpassphrase <passphrase> <timeout>\n"
1446             "Stores the wallet decryption key in memory for <timeout> seconds.");
1447     if (fHelp)
1448         return true;
1449     if (!pwalletMain->IsCrypted())
1450         throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
1451 
1452     if (!pwalletMain->IsLocked())
1453         throw JSONRPCError(-17, "Error: Wallet is already unlocked.");
1454 
1455     // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
1456     SecureString strWalletPass;
1457     strWalletPass.reserve(100);
1458     // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1459     // Alternately, find a way to make params[0] mlock()'d to begin with.
1460     strWalletPass = params[0].get_str().c_str();
1461 
1462     if (strWalletPass.length() > 0)
1463     {
1464         if (!pwalletMain->Unlock(strWalletPass))
1465             throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1466     }
1467     else
1468         throw runtime_error(
1469             "walletpassphrase <passphrase> <timeout>\n"
1470             "Stores the wallet decryption key in memory for <timeout> seconds.");
1471 
1472     CreateThread(ThreadTopUpKeyPool, NULL);
1473     int64* pnSleepTime = new int64(params[1].get_int64());
1474     CreateThread(ThreadCleanWalletPassphrase, pnSleepTime);
1475 
1476     return Value::null;
1477 }
1478 
1479 
1480 Value walletpassphrasechange(const Array& params, bool fHelp)
1481 {
1482     if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1483         throw runtime_error(
1484             "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1485             "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1486     if (fHelp)
1487         return true;
1488     if (!pwalletMain->IsCrypted())
1489         throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
1490 
1491     // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
1492     // Alternately, find a way to make params[0] mlock()'d to begin with.
1493     SecureString strOldWalletPass;
1494     strOldWalletPass.reserve(100);
1495     strOldWalletPass = params[0].get_str().c_str();
1496 
1497     SecureString strNewWalletPass;
1498     strNewWalletPass.reserve(100);
1499     strNewWalletPass = params[1].get_str().c_str();
1500 
1501     if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
1502         throw runtime_error(
1503             "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1504             "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1505 
1506     if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
1507         throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1508 
1509     return Value::null;
1510 }
1511 
1512 
1513 Value walletlock(const Array& params, bool fHelp)
1514 {
1515     if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
1516         throw runtime_error(
1517             "walletlock\n"
1518             "Removes the wallet encryption key from memory, locking the wallet.\n"
1519             "After calling this method, you will need to call walletpassphrase again\n"
1520             "before being able to call any methods which require the wallet to be unlocked.");
1521     if (fHelp)
1522         return true;
1523     if (!pwalletMain->IsCrypted())
1524         throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletlock was called.");
1525 
1526     CRITICAL_BLOCK(cs_nWalletUnlockTime)
1527     {
1528         pwalletMain->Lock();
1529         nWalletUnlockTime = 0;
1530     }
1531 
1532     return Value::null;
1533 }
1534 
1535 
1536 Value encryptwallet(const Array& params, bool fHelp)
1537 {
1538     if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
1539         throw runtime_error(
1540             "encryptwallet <passphrase>\n"
1541             "Encrypts the wallet with <passphrase>.");
1542     if (fHelp)
1543         return true;
1544     if (pwalletMain->IsCrypted())
1545         throw JSONRPCError(-15, "Error: running with an encrypted wallet, but encryptwallet was called.");
1546 
1547     // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1548     // Alternately, find a way to make params[0] mlock()'d to begin with.
1549     SecureString strWalletPass;
1550     strWalletPass.reserve(100);
1551     strWalletPass = params[0].get_str().c_str();
1552 
1553     if (strWalletPass.length() < 1)
1554         throw runtime_error(
1555             "encryptwallet <passphrase>\n"
1556             "Encrypts the wallet with <passphrase>.");
1557 
1558     if (!pwalletMain->EncryptWallet(strWalletPass))
1559         throw JSONRPCError(-16, "Error: Failed to encrypt the wallet.");
1560 
1561     // BDB seems to have a bad habit of writing old data into
1562     // slack space in .dat files; that is bad if the old data is
1563     // unencrypted private keys.  So:
1564     CreateThread(Shutdown, NULL);
1565     return "wallet encrypted; bitcoin server stopping, restart to run with encrypted wallet";
1566 }
1567 
1568 
1569 Value validateaddress(const Array& params, bool fHelp)
1570 {
1571     if (fHelp || params.size() != 1)
1572         throw runtime_error(
1573             "validateaddress <bitcoinaddress>\n"
1574             "Return information about <bitcoinaddress>.");
1575 
1576     CBitcoinAddress address(params[0].get_str());
1577     bool isValid = address.IsValid();
1578 
1579     Object ret;
1580     ret.push_back(Pair("isvalid", isValid));
1581     if (isValid)
1582     {
1583         // Call Hash160ToAddress() so we always return current ADDRESSVERSION
1584         // version of the address:
1585         string currentAddress = address.ToString();
1586         ret.push_back(Pair("address", currentAddress));
1587         ret.push_back(Pair("ismine", (pwalletMain->HaveKey(address) > 0)));
1588         if (pwalletMain->mapAddressBook.count(address))
1589             ret.push_back(Pair("account", pwalletMain->mapAddressBook[address]));
1590     }
1591     return ret;
1592 }
1593 
1594 
1595 Value getwork(const Array& params, bool fHelp)
1596 {
1597     if (fHelp || params.size() > 1)
1598         throw runtime_error(
1599             "getwork [data]\n"
1600             "If [data] is not specified, returns formatted hash data to work on:\n"
1601             "  \"midstate\" : precomputed hash state after hashing the first half of the data (DEPRECATED)\n" // deprecated
1602             "  \"data\" : block data\n"
1603             "  \"hash1\" : formatted hash buffer for second hash (DEPRECATED)\n" // deprecated
1604             "  \"target\" : little endian hash target\n"
1605             "If [data] is specified, tries to solve the block and returns true if it was successful.");
1606 
1607     if (vNodes.empty())
1608         throw JSONRPCError(-9, "Bitcoin is not connected!");
1609 
1610     if (IsInitialBlockDownload())
1611         throw JSONRPCError(-10, "Bitcoin is downloading blocks...");
1612 
1613     typedef map<uint256, pair<CBlock*, CScript> > mapNewBlock_t;
1614     static mapNewBlock_t mapNewBlock;
1615     static vector<CBlock*> vNewBlock;
1616     static CReserveKey reservekey(pwalletMain);
1617 
1618     if (params.size() == 0)
1619     {
1620         // Update block
1621         static unsigned int nTransactionsUpdatedLast;
1622         static CBlockIndex* pindexPrev;
1623         static int64 nStart;
1624         static CBlock* pblock;
1625         if (pindexPrev != pindexBest ||
1626             (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60))
1627         {
1628             if (pindexPrev != pindexBest)
1629             {
1630                 // Deallocate old blocks since they're obsolete now
1631                 mapNewBlock.clear();
1632                 BOOST_FOREACH(CBlock* pblock, vNewBlock)
1633                     delete pblock;
1634                 vNewBlock.clear();
1635             }
1636             nTransactionsUpdatedLast = nTransactionsUpdated;
1637             pindexPrev = pindexBest;
1638             nStart = GetTime();
1639 
1640             // Create new block
1641             pblock = CreateNewBlock(reservekey);
1642             if (!pblock)
1643                 throw JSONRPCError(-7, "Out of memory");
1644             vNewBlock.push_back(pblock);
1645         }
1646 
1647         // Update nTime
1648         pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
1649         pblock->nNonce = 0;
1650 
1651         // Update nExtraNonce
1652         static unsigned int nExtraNonce = 0;
1653         IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
1654 
1655         // Save
1656         mapNewBlock[pblock->hashMerkleRoot] = make_pair(pblock, pblock->vtx[0].vin[0].scriptSig);
1657 
1658         // Prebuild hash buffers
1659         char pmidstate[32];
1660         char pdata[128];
1661         char phash1[64];
1662         FormatHashBuffers(pblock, pmidstate, pdata, phash1);
1663 
1664         uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
1665 
1666         Object result;
1667         result.push_back(Pair("midstate", HexStr(BEGIN(pmidstate), END(pmidstate)))); // deprecated
1668         result.push_back(Pair("data",     HexStr(BEGIN(pdata), END(pdata))));
1669         result.push_back(Pair("hash1",    HexStr(BEGIN(phash1), END(phash1)))); // deprecated
1670         result.push_back(Pair("target",   HexStr(BEGIN(hashTarget), END(hashTarget))));
1671         return result;
1672     }
1673     else
1674     {
1675         // Parse parameters
1676         vector<unsigned char> vchData = ParseHex(params[0].get_str());
1677         if (vchData.size() != 128)
1678             throw JSONRPCError(-8, "Invalid parameter");
1679         CBlock* pdata = (CBlock*)&vchData[0];
1680 
1681         // Byte reverse
1682         for (int i = 0; i < 128/4; i++)
1683             ((unsigned int*)pdata)[i] = ByteReverse(((unsigned int*)pdata)[i]);
1684 
1685         // Get saved block
1686         if (!mapNewBlock.count(pdata->hashMerkleRoot))
1687             return false;
1688         CBlock* pblock = mapNewBlock[pdata->hashMerkleRoot].first;
1689 
1690         pblock->nTime = pdata->nTime;
1691         pblock->nNonce = pdata->nNonce;
1692         pblock->vtx[0].vin[0].scriptSig = mapNewBlock[pdata->hashMerkleRoot].second;
1693         pblock->hashMerkleRoot = pblock->BuildMerkleTree();
1694 
1695         return CheckWork(pblock, *pwalletMain, reservekey);
1696     }
1697 }
1698 
1699 
1700 Value getmemorypool(const Array& params, bool fHelp)
1701 {
1702     if (fHelp || params.size() > 1)
1703         throw runtime_error(
1704             "getmemorypool [data]\n"
1705             "If [data] is not specified, returns data needed to construct a block to work on:\n"
1706             "  \"version\" : block version\n"
1707             "  \"previousblockhash\" : hash of current highest block\n"
1708             "  \"transactions\" : contents of non-coinbase transactions that should be included in the next block\n"
1709             "  \"coinbasevalue\" : maximum allowable input to coinbase transaction, including the generation award and transaction fees\n"
1710             "  \"time\" : timestamp appropriate for next block\n"
1711             "  \"bits\" : compressed target of next block\n"
1712             "If [data] is specified, tries to solve the block and returns true if it was successful.");
1713 
1714     if (params.size() == 0)
1715     {
1716         if (vNodes.empty())
1717             throw JSONRPCError(-9, "Bitcoin is not connected!");
1718 
1719         if (IsInitialBlockDownload())
1720             throw JSONRPCError(-10, "Bitcoin is downloading blocks...");
1721 
1722         static CReserveKey reservekey(pwalletMain);
1723 
1724         // Update block
1725         static unsigned int nTransactionsUpdatedLast;
1726         static CBlockIndex* pindexPrev;
1727         static int64 nStart;
1728         static CBlock* pblock;
1729         if (pindexPrev != pindexBest ||
1730             (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 5))
1731         {
1732             nTransactionsUpdatedLast = nTransactionsUpdated;
1733             pindexPrev = pindexBest;
1734             nStart = GetTime();
1735 
1736             // Create new block
1737             if(pblock)
1738                 delete pblock;
1739             pblock = CreateNewBlock(reservekey);
1740             if (!pblock)
1741                 throw JSONRPCError(-7, "Out of memory");
1742         }
1743 
1744         // Update nTime
1745         pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
1746         pblock->nNonce = 0;
1747 
1748         Array transactions;
1749         BOOST_FOREACH(CTransaction tx, pblock->vtx) {
1750             if(tx.IsCoinBase())
1751                 continue;
1752 
1753             CDataStream ssTx;
1754             ssTx << tx;
1755 
1756             transactions.push_back(HexStr(ssTx.begin(), ssTx.end()));
1757         }
1758 
1759         Object result;
1760         result.push_back(Pair("version", pblock->nVersion));
1761         result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex()));
1762         result.push_back(Pair("transactions", transactions));
1763         result.push_back(Pair("coinbasevalue", (boost::int64_t)pblock->vtx[0].vout[0].nValue));
1764         result.push_back(Pair("time", (boost::int64_t)pblock->nTime));
1765 
1766         union {
1767             int32_t nBits;
1768             char cBits[4];
1769         } uBits;
1770         uBits.nBits = htonl((int32_t)pblock->nBits);
1771         result.push_back(Pair("bits", HexStr(BEGIN(uBits.cBits), END(uBits.cBits))));
1772 
1773         return result;
1774     }
1775     else
1776     {
1777         // Parse parameters
1778         CDataStream ssBlock(ParseHex(params[0].get_str()));
1779         CBlock pblock;
1780         ssBlock >> pblock;
1781 
1782         return ProcessBlock(NULL, &pblock);
1783     }
1784 }
1785 
1786 
1787 Value dumpblock(const Array& params, bool fHelp)
1788 {
1789     if (fHelp || params.size() != 2)
1790         throw runtime_error(
1791             "dumpblock <height> <filename>\n"
1792             "Emit the block at <height> to <filename>.");
1793 
1794     int want_height = 0;
1795     if (params.size() > 0)
1796         want_height = params[0].get_int();
1797 
1798     if (want_height > nBestHeight)
1799         throw runtime_error("Requested block exceeds current nBestHeight!\n");
1800 
1801     // path to dump block to
1802     string filename = params[1].get_str();
1803 
1804     // this is O(n^2)...
1805     // possibly could be improved if we descend from best height if requested height is closer to it
1806     for (map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.begin(); mi != mapBlockIndex.end(); ++mi)
1807     {
1808         CBlockIndex *pindex = (*mi).second;
1809     if (pindex->nHeight == want_height) {
1810         CBlock block;
1811         block.ReadFromDisk(pindex);
1812         printf("Dumping block %d to %s\n", want_height, filename.c_str());
1813         CAutoFile fileout = fopen(filename.c_str(), "wb+");
1814         fileout << block;
1815         return true;
1816     }
1817     }
1818     return false;
1819 }
1820 
1821 
1822 Value eatblock(const Array& params, bool fHelp)
1823 {
1824     if (fHelp || params.size() < 1 || params.size() > 1)
1825         throw runtime_error(
1826             "eatblock <filename>\n"
1827             "Load a candidate for the next block directly from <filename>.");
1828 
1829     if (!fCanEat)
1830         throw runtime_error(
1831             "'eatblock' is only permitted if bitcoind was started with -caneat flag!");
1832 
1833     // path to load block from
1834     string filename = params[0].get_str();
1835     
1836     printf("Attempting to create block #%d from file %s\n", nBestHeight + 1, filename.c_str());
1837     CAutoFile filein = fopen(filename.c_str(), "rb");
1838     CBlock block;
1839     filein >> block;
1840     return ProcessBlock(NULL, &block); // note that 'true' even if it was rejected (bastard, etc)
1841 } // ... but will return 'false' if we already have the block.
1842 
1843 
1844 Value importprivkey(const Array& params, bool fHelp)
1845 {
1846     if (fHelp || params.size() < 1 || params.size() > 2)
1847         throw runtime_error(
1848             "importprivkey <bitcoinprivkey> [label]\n"
1849             "Adds a private key (as returned by dumpprivkey) to your wallet.");
1850 
1851     string strSecret = params[0].get_str();
1852     string strLabel = "";
1853     if (params.size() > 1)
1854         strLabel = params[1].get_str();
1855     CBitcoinSecret vchSecret;
1856     bool fGood = vchSecret.SetString(strSecret);
1857 
1858     if (!fGood) throw JSONRPCError(-5,"Invalid private key");
1859 
1860     CKey key;
1861     CSecret secret = vchSecret.GetSecret();
1862     key.SetSecret(secret);
1863     CBitcoinAddress vchAddress = CBitcoinAddress(key.GetPubKey());
1864 
1865     CRITICAL_BLOCK(cs_main)
1866     CRITICAL_BLOCK(pwalletMain->cs_wallet)
1867     {
1868         pwalletMain->MarkDirty();
1869         pwalletMain->SetAddressBookName(vchAddress, strLabel);
1870 
1871         if (!pwalletMain->AddKey(key))
1872             throw JSONRPCError(-4,"Error adding key to wallet");
1873 
1874         pwalletMain->ScanForWalletTransactions(pindexGenesisBlock, true);
1875         pwalletMain->ReacceptWalletTransactions();
1876     }
1877 
1878     return Value::null;
1879 }
1880 
1881 Value dumpprivkey(const Array& params, bool fHelp)
1882 {
1883     if (fHelp || params.size() != 1)
1884         throw runtime_error(
1885             "dumpprivkey <bitcoinaddress>\n"
1886             "Reveals the private key corresponding to <bitcoinaddress>.");
1887 
1888     string strAddress = params[0].get_str();
1889     CBitcoinAddress address;
1890     if (!address.SetString(strAddress))
1891         throw JSONRPCError(-5, "Invalid bitcoin address");
1892     CSecret vchSecret;
1893     if (!pwalletMain->GetSecret(address, vchSecret))
1894         throw JSONRPCError(-4,"Private key for address " + strAddress + " is not known");
1895     return CBitcoinSecret(vchSecret).ToString();
1896 }
1897 
1898 
1899 //
1900 // Call Table
1901 //
1902 
1903 pair<string, rpcfn_type> pCallTable[] =
1904 {
1905     make_pair("help",                   &help),
1906     make_pair("stop",                   &stop),
1907     make_pair("getblockcount",          &getblockcount),
1908     make_pair("getblocknumber",         &getblocknumber),
1909     make_pair("getconnectioncount",     &getconnectioncount),
1910     make_pair("getdifficulty",          &getdifficulty),
1911     make_pair("getgenerate",            &getgenerate),
1912     make_pair("setgenerate",            &setgenerate),
1913     make_pair("gethashespersec",        &gethashespersec),
1914     make_pair("getinfo",                &getinfo),
1915     make_pair("getnewaddress",          &getnewaddress),
1916     make_pair("getaccountaddress",      &getaccountaddress),
1917     make_pair("setaccount",             &setaccount),
1918     make_pair("getaccount",             &getaccount),
1919     make_pair("getaddressesbyaccount",  &getaddressesbyaccount),
1920     make_pair("sendtoaddress",          &sendtoaddress),
1921     make_pair("getreceivedbyaddress",   &getreceivedbyaddress),
1922     make_pair("getreceivedbyaccount",   &getreceivedbyaccount),
1923     make_pair("listreceivedbyaddress",  &listreceivedbyaddress),
1924     make_pair("listreceivedbyaccount",  &listreceivedbyaccount),
1925     make_pair("backupwallet",           &backupwallet),
1926     make_pair("keypoolrefill",          &keypoolrefill),
1927     make_pair("walletpassphrase",       &walletpassphrase),
1928     make_pair("walletpassphrasechange", &walletpassphrasechange),
1929     make_pair("walletlock",             &walletlock),
1930     make_pair("encryptwallet",          &encryptwallet),
1931     make_pair("validateaddress",        &validateaddress),
1932     make_pair("getbalance",             &getbalance),
1933     make_pair("move",                   &movecmd),
1934     make_pair("sendfrom",               &sendfrom),
1935     make_pair("sendmany",               &sendmany),
1936     make_pair("gettransaction",         &gettransaction),
1937     make_pair("listtransactions",       &listtransactions),
1938     make_pair("signmessage",           &signmessage),
1939     make_pair("verifymessage",         &verifymessage),
1940     make_pair("getwork",                &getwork),
1941     make_pair("listaccounts",           &listaccounts),
1942     make_pair("settxfee",               &settxfee),
1943     make_pair("getmemorypool",          &getmemorypool),
1944     make_pair("listsinceblock",        &listsinceblock),
1945     make_pair("dumpblock",              &dumpblock),
1946     make_pair("eatblock",               &eatblock),
1947     make_pair("importprivkey",          &importprivkey),
1948     make_pair("dumpprivkey",            &dumpprivkey),
1949 };
1950 map<string, rpcfn_type> mapCallTable(pCallTable, pCallTable + sizeof(pCallTable)/sizeof(pCallTable[0]));
1951 
1952 string pAllowInSafeMode[] =
1953 {
1954     "help",
1955     "stop",
1956     "getblockcount",
1957     "getblocknumber",  // deprecated
1958     "getconnectioncount",
1959     "getdifficulty",
1960     "getgenerate",
1961     "setgenerate",
1962     "gethashespersec",
1963     "getinfo",
1964     "getnewaddress",
1965     "getaccountaddress",
1966     "getaccount",
1967     "getaddressesbyaccount",
1968     "backupwallet",
1969     "keypoolrefill",
1970     "walletpassphrase",
1971     "walletlock",
1972     "validateaddress",
1973     "getwork",
1974     "getmemorypool",
1975     "dumpblock",
1976 };
1977 set<string> setAllowInSafeMode(pAllowInSafeMode, pAllowInSafeMode + sizeof(pAllowInSafeMode)/sizeof(pAllowInSafeMode[0]));
1978 
1979 
1980 
1981 
1982 //
1983 // HTTP protocol
1984 //
1985 // This ain't Apache.  We're just using HTTP header for the length field
1986 // and to be compatible with other JSON-RPC implementations.
1987 //
1988 
1989 string HTTPPost(const string& strMsg, const map<string,string>& mapRequestHeaders)
1990 {
1991     ostringstream s;
1992     s << "POST / HTTP/1.1\r\n"
1993       << "User-Agent: bitcoin-json-rpc/" << FormatFullVersion() << "\r\n"
1994       << "Host: 127.0.0.1\r\n"
1995       << "Content-Type: application/json\r\n"
1996       << "Content-Length: " << strMsg.size() << "\r\n"
1997       << "Connection: close\r\n"
1998       << "Accept: application/json\r\n";
1999     BOOST_FOREACH(const PAIRTYPE(string, string)& item, mapRequestHeaders)
2000         s << item.first << ": " << item.second << "\r\n";
2001     s << "\r\n" << strMsg;
2002 
2003     return s.str();
2004 }
2005 
2006 string rfc1123Time()
2007 {
2008     char buffer[64];
2009     time_t now;
2010     time(&now);
2011     struct tm* now_gmt = gmtime(&now);
2012     string locale(setlocale(LC_TIME, NULL));
2013     setlocale(LC_TIME, "C"); // we want posix (aka "C") weekday/month strings
2014     strftime(buffer, sizeof(buffer), "%a, %d %b %Y %H:%M:%S +0000", now_gmt);
2015     setlocale(LC_TIME, locale.c_str());
2016     return string(buffer);
2017 }
2018 
2019 static string HTTPReply(int nStatus, const string& strMsg)
2020 {
2021     if (nStatus == 401)
2022         return strprintf("HTTP/1.0 401 Authorization Required\r\n"
2023             "Date: %s\r\n"
2024             "Server: bitcoin-json-rpc/%s\r\n"
2025             "WWW-Authenticate: Basic realm=\"jsonrpc\"\r\n"
2026             "Content-Type: text/html\r\n"
2027             "Content-Length: 296\r\n"
2028             "\r\n"
2029             "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\r\n"
2030             "\"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd\">\r\n"
2031             "<HTML>\r\n"
2032             "<HEAD>\r\n"
2033             "<TITLE>Error</TITLE>\r\n"
2034             "<META HTTP-EQUIV='Content-Type' CONTENT='text/html; charset=ISO-8859-1'>\r\n"
2035             "</HEAD>\r\n"
2036             "<BODY><H1>401 Unauthorized.</H1></BODY>\r\n"
2037             "</HTML>\r\n", rfc1123Time().c_str(), FormatFullVersion().c_str());
2038     const char *cStatus;
2039          if (nStatus == 200) cStatus = "OK";
2040     else if (nStatus == 400) cStatus = "Bad Request";
2041     else if (nStatus == 403) cStatus = "Forbidden";
2042     else if (nStatus == 404) cStatus = "Not Found";
2043     else if (nStatus == 500) cStatus = "Internal Server Error";
2044     else cStatus = "";
2045     return strprintf(
2046             "HTTP/1.1 %d %s\r\n"
2047             "Date: %s\r\n"
2048             "Connection: close\r\n"
2049             "Content-Length: %d\r\n"
2050             "Content-Type: application/json\r\n"
2051             "Server: bitcoin-json-rpc/%s\r\n"
2052             "\r\n"
2053             "%s",
2054         nStatus,
2055         cStatus,
2056         rfc1123Time().c_str(),
2057         strMsg.size(),
2058         FormatFullVersion().c_str(),
2059         strMsg.c_str());
2060 }
2061 
2062 int ReadHTTPStatus(std::basic_istream<char>& stream)
2063 {
2064     string str;
2065     getline(stream, str);
2066     vector<string> vWords;
2067     boost::split(vWords, str, boost::is_any_of(" "));
2068     if (vWords.size() < 2)
2069         return 500;
2070     return atoi(vWords[1].c_str());
2071 }
2072 
2073 int ReadHTTPHeader(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet)
2074 {
2075     int nLen = 0;
2076     loop
2077     {
2078         string str;
2079         std::getline(stream, str);
2080         if (str.empty() || str == "\r")
2081             break;
2082         string::size_type nColon = str.find(":");
2083         if (nColon != string::npos)
2084         {
2085             string strHeader = str.substr(0, nColon);
2086             boost::trim(strHeader);
2087             boost::to_lower(strHeader);
2088             string strValue = str.substr(nColon+1);
2089             boost::trim(strValue);
2090             mapHeadersRet[strHeader] = strValue;
2091             if (strHeader == "content-length")
2092                 nLen = atoi(strValue.c_str());
2093         }
2094     }
2095     return nLen;
2096 }
2097 
2098 int ReadHTTP(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet, string& strMessageRet)
2099 {
2100     mapHeadersRet.clear();
2101     strMessageRet = "";
2102 
2103     // Read status
2104     int nStatus = ReadHTTPStatus(stream);
2105 
2106     // Read header
2107     int nLen = ReadHTTPHeader(stream, mapHeadersRet);
2108     if (nLen < 0 || nLen > MAX_SIZE)
2109         return 500;
2110 
2111     // Read message
2112     if (nLen > 0)
2113     {
2114         vector<char> vch(nLen);
2115         stream.read(&vch[0], nLen);
2116         strMessageRet = string(vch.begin(), vch.end());
2117     }
2118 
2119     return nStatus;
2120 }
2121 
2122 bool HTTPAuthorized(map<string, string>& mapHeaders)
2123 {
2124     string strAuth = mapHeaders["authorization"];
2125     if (strAuth.substr(0,6) != "Basic ")
2126         return false;
2127     string strUserPass64 = strAuth.substr(6); boost::trim(strUserPass64);
2128     string strUserPass = DecodeBase64(strUserPass64);
2129     return strUserPass == strRPCUserColonPass;
2130 }
2131 
2132 //
2133 // JSON-RPC protocol.  Bitcoin speaks version 1.0 for maximum compatibility,
2134 // but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
2135 // unspecified (HTTP errors and contents of 'error').
2136 //
2137 // 1.0 spec: http://json-rpc.org/wiki/specification
2138 // 1.2 spec: http://groups.google.com/group/json-rpc/web/json-rpc-over-http
2139 // http://www.codeproject.com/KB/recipes/JSON_Spirit.aspx
2140 //
2141 
2142 string JSONRPCRequest(const string& strMethod, const Array& params, const Value& id)
2143 {
2144     Object request;
2145     request.push_back(Pair("method", strMethod));
2146     request.push_back(Pair("params", params));
2147     request.push_back(Pair("id", id));
2148     return write_string(Value(request), false) + "\n";
2149 }
2150 
2151 string JSONRPCReply(const Value& result, const Value& error, const Value& id)
2152 {
2153     Object reply;
2154     if (error.type() != null_type)
2155         reply.push_back(Pair("result", Value::null));
2156     else
2157         reply.push_back(Pair("result", result));
2158     reply.push_back(Pair("error", error));
2159     reply.push_back(Pair("id", id));
2160     return write_string(Value(reply), false) + "\n";
2161 }
2162 
2163 void ErrorReply(std::ostream& stream, const Object& objError, const Value& id)
2164 {
2165     // Send error reply from json-rpc error object
2166     int nStatus = 500;
2167     int code = find_value(objError, "code").get_int();
2168     if (code == -32600) nStatus = 400;
2169     else if (code == -32601) nStatus = 404;
2170     string strReply = JSONRPCReply(Value::null, objError, id);
2171     stream << HTTPReply(nStatus, strReply) << std::flush;
2172 }
2173 
2174 bool ClientAllowed(const string& strAddress)
2175 {
2176     if (strAddress == asio::ip::address_v4::loopback().to_string())
2177         return true;
2178     const vector<string>& vAllow = mapMultiArgs["-rpcallowip"];
2179     BOOST_FOREACH(string strAllow, vAllow)
2180         if (WildcardMatch(strAddress, strAllow))
2181             return true;
2182     return false;
2183 }
2184 
2185 void ThreadRPCServer(void* parg)
2186 {
2187     IMPLEMENT_RANDOMIZE_STACK(ThreadRPCServer(parg));
2188     try
2189     {
2190         vnThreadsRunning[4]++;
2191         ThreadRPCServer2(parg);
2192         vnThreadsRunning[4]--;
2193     }
2194     catch (std::exception& e) {
2195         vnThreadsRunning[4]--;
2196         PrintException(&e, "ThreadRPCServer()");
2197     } catch (...) {
2198         vnThreadsRunning[4]--;
2199         PrintException(NULL, "ThreadRPCServer()");
2200     }
2201     printf("ThreadRPCServer exiting\n");
2202 }
2203 
2204 void ThreadRPCServer2(void* parg)
2205 {
2206     printf("ThreadRPCServer started\n");
2207 
2208     strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"];
2209     if (strRPCUserColonPass == ":")
2210     {
2211         unsigned char rand_pwd[32];
2212         RAND_bytes(rand_pwd, 32);
2213         string strWhatAmI = "To use bitcoind";
2214         if (mapArgs.count("-server"))
2215             strWhatAmI = strprintf(_("To use the %s option"), "\"-server\"");
2216         else if (mapArgs.count("-daemon"))
2217             strWhatAmI = strprintf(_("To use the %s option"), "\"-daemon\"");
2218         PrintConsole(
2219             _("Error: %s, you must set a rpcpassword in the configuration file:\n %s\n"
2220               "It is recommended you use the following random password:\n"
2221               "rpcuser=bitcoinrpc\n"
2222               "rpcpassword=%s\n"
2223               "(you do not need to remember this password)\n"
2224               "If the file does not exist, create it with owner-readable-only file permissions.\n"),
2225                 strWhatAmI.c_str(),
2226                 GetConfigFile().c_str(),
2227                 EncodeBase58(&rand_pwd[0],&rand_pwd[0]+32).c_str());
2228         CreateThread(Shutdown, NULL);
2229         return;
2230     }
2231 
2232     asio::ip::address bindAddress = mapArgs.count("-rpcallowip") ? asio::ip::address_v4::any() : asio::ip::address_v4::loopback();
2233 
2234     asio::io_service io_service;
2235     ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", 8332));
2236     ip::tcp::acceptor acceptor(io_service, endpoint);
2237 
2238     acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
2239 
2240     loop
2241     {
2242         // Accept connection
2243         ip::tcp::iostream stream;
2244 
2245         ip::tcp::endpoint peer;
2246         vnThreadsRunning[4]--;
2247         acceptor.accept(*stream.rdbuf(), peer);
2248         vnThreadsRunning[4]++;
2249         if (fShutdown)
2250             return;
2251 
2252         // Restrict callers by IP
2253         if (!ClientAllowed(peer.address().to_string()))
2254         {
2255         // snipsnipsnip
2256             // Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake.
2257             //if (!fUseSSL)
2258             stream << HTTPReply(403, "") << std::flush;
2259             continue;
2260         }
2261 
2262         map<string, string> mapHeaders;
2263         string strRequest;
2264 
2265         boost::thread api_caller(ReadHTTP, boost::ref(stream), boost::ref(mapHeaders), boost::ref(strRequest));
2266         if (!api_caller.timed_join(boost::posix_time::seconds(GetArg("-rpctimeout", 30))))
2267         {   // Timed out:
2268             acceptor.cancel();
2269             printf("ThreadRPCServer ReadHTTP timeout\n");
2270             continue;
2271         }
2272 
2273         // Check authorization
2274         if (mapHeaders.count("authorization") == 0)
2275         {
2276             stream << HTTPReply(401, "") << std::flush;
2277             continue;
2278         }
2279         if (!HTTPAuthorized(mapHeaders))
2280         {
2281             printf("ThreadRPCServer incorrect password attempt from %s\n",peer.address().to_string().c_str());
2282             /* Deter brute-forcing short passwords.
2283                If this results in a DOS the user really
2284                shouldn't have their RPC port exposed.*/
2285             if (mapArgs["-rpcpassword"].size() < 20)
2286                 Sleep(250);
2287 
2288             stream << HTTPReply(401, "") << std::flush;
2289             continue;
2290         }
2291 
2292         Value id = Value::null;
2293         try
2294         {
2295             // Parse request
2296             Value valRequest;
2297             if (!read_string(strRequest, valRequest) || valRequest.type() != obj_type)
2298                 throw JSONRPCError(-32700, "Parse error");
2299             const Object& request = valRequest.get_obj();
2300 
2301             // Parse id now so errors from here on will have the id
2302             id = find_value(request, "id");
2303 
2304             // Parse method
2305             Value valMethod = find_value(request, "method");
2306             if (valMethod.type() == null_type)
2307                 throw JSONRPCError(-32600, "Missing method");
2308             if (valMethod.type() != str_type)
2309                 throw JSONRPCError(-32600, "Method must be a string");
2310             string strMethod = valMethod.get_str();
2311             if (strMethod != "getwork" && strMethod != "getmemorypool")
2312                 printf("ThreadRPCServer method=%s\n", strMethod.c_str());
2313 
2314             // Parse params
2315             Value valParams = find_value(request, "params");
2316             Array params;
2317             if (valParams.type() == array_type)
2318                 params = valParams.get_array();
2319             else if (valParams.type() == null_type)
2320                 params = Array();
2321             else
2322                 throw JSONRPCError(-32600, "Params must be an array");
2323 
2324             // Find method
2325             map<string, rpcfn_type>::iterator mi = mapCallTable.find(strMethod);
2326             if (mi == mapCallTable.end())
2327                 throw JSONRPCError(-32601, "Method not found");
2328 
2329             // Observe safe mode
2330             string strWarning = GetWarnings("rpc");
2331             if (strWarning != "" && !GetBoolArg("-disablesafemode") && !setAllowInSafeMode.count(strMethod))
2332                 throw JSONRPCError(-2, string("Safe mode: ") + strWarning);
2333 
2334             try
2335             {
2336                 // Execute
2337                 Value result;
2338                 CRITICAL_BLOCK(cs_main)
2339                 CRITICAL_BLOCK(pwalletMain->cs_wallet)
2340                     result = (*(*mi).second)(params, false);
2341 
2342                 // Send reply
2343                 string strReply = JSONRPCReply(result, Value::null, id);
2344                 stream << HTTPReply(200, strReply) << std::flush;
2345             }
2346             catch (std::exception& e)
2347             {
2348                 ErrorReply(stream, JSONRPCError(-1, e.what()), id);
2349             }
2350         }
2351         catch (Object& objError)
2352         {
2353             ErrorReply(stream, objError, id);
2354         }
2355         catch (std::exception& e)
2356         {
2357             ErrorReply(stream, JSONRPCError(-32700, e.what()), id);
2358         }
2359     }
2360 }
2361 
2362 
2363 
2364 
2365 Object CallRPC(const string& strMethod, const Array& params)
2366 {
2367     if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
2368         throw runtime_error(strprintf(
2369             _("You must set rpcpassword=<password> in the configuration file:\n%s\n"
2370               "If the file does not exist, create it with owner-readable-only file permissions."),
2371                 GetConfigFile().c_str()));
2372 
2373     // Connect to localhost
2374     ip::tcp::iostream stream(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332"));
2375     if (stream.fail())
2376         throw runtime_error("couldn't connect to server");
2377 
2378     // HTTP basic authentication
2379     string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
2380     map<string, string> mapRequestHeaders;
2381     mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64;
2382 
2383     // Send request
2384     string strRequest = JSONRPCRequest(strMethod, params, 1);
2385     string strPost = HTTPPost(strRequest, mapRequestHeaders);
2386     stream << strPost << std::flush;
2387 
2388     // Receive reply
2389     map<string, string> mapHeaders;
2390     string strReply;
2391     int nStatus = ReadHTTP(stream, mapHeaders, strReply);
2392     if (nStatus == 401)
2393         throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
2394     else if (nStatus >= 400 && nStatus != 400 && nStatus != 404 && nStatus != 500)
2395         throw runtime_error(strprintf("server returned HTTP error %d", nStatus));
2396     else if (strReply.empty())
2397         throw runtime_error("no response from server");
2398 
2399     // Parse reply
2400     Value valReply;
2401     if (!read_string(strReply, valReply))
2402         throw runtime_error("couldn't parse reply from server");
2403     const Object& reply = valReply.get_obj();
2404     if (reply.empty())
2405         throw runtime_error("expected reply to have result, error and id properties");
2406 
2407     return reply;
2408 }
2409 
2410 
2411 
2412 
2413 template<typename T>
2414 void ConvertTo(Value& value)
2415 {
2416     if (value.type() == str_type)
2417     {
2418         // reinterpret string as unquoted json value
2419         Value value2;
2420         if (!read_string(value.get_str(), value2))
2421             throw runtime_error("type mismatch");
2422         value = value2.get_value<T>();
2423     }
2424     else
2425     {
2426         value = value.get_value<T>();
2427     }
2428 }
2429 
2430 int CommandLineRPC(int argc, char *argv[])
2431 {
2432     string strPrint;
2433     int nRet = 0;
2434     try
2435     {
2436         // Skip switches
2437         while (argc > 1 && IsSwitchChar(argv[1][0]))
2438         {
2439             argc--;
2440             argv++;
2441         }
2442 
2443         // Method
2444         if (argc < 2)
2445             throw runtime_error("too few parameters");
2446         string strMethod = argv[1];
2447 
2448         // Parameters default to strings
2449         Array params;
2450         for (int i = 2; i < argc; i++)
2451             params.push_back(argv[i]);
2452         int n = params.size();
2453 
2454         //
2455         // Special case non-string parameter types
2456         //
2457         if (strMethod == "setgenerate"            && n > 0) ConvertTo<bool>(params[0]);
2458         if (strMethod == "setgenerate"            && n > 1) ConvertTo<boost::int64_t>(params[1]);
2459         if (strMethod == "sendtoaddress"          && n > 1) ConvertTo<double>(params[1]);
2460         if (strMethod == "settxfee"               && n > 0) ConvertTo<double>(params[0]);
2461         if (strMethod == "getreceivedbyaddress"   && n > 1) ConvertTo<boost::int64_t>(params[1]);
2462         if (strMethod == "getreceivedbyaccount"   && n > 1) ConvertTo<boost::int64_t>(params[1]);
2463         if (strMethod == "listreceivedbyaddress"  && n > 0) ConvertTo<boost::int64_t>(params[0]);
2464         if (strMethod == "listreceivedbyaddress"  && n > 1) ConvertTo<bool>(params[1]);
2465         if (strMethod == "listreceivedbyaccount"  && n > 0) ConvertTo<boost::int64_t>(params[0]);
2466         if (strMethod == "listreceivedbyaccount"  && n > 1) ConvertTo<bool>(params[1]);
2467         if (strMethod == "getbalance"             && n > 1) ConvertTo<boost::int64_t>(params[1]);
2468         if (strMethod == "move"                   && n > 2) ConvertTo<double>(params[2]);
2469         if (strMethod == "move"                   && n > 3) ConvertTo<boost::int64_t>(params[3]);
2470         if (strMethod == "sendfrom"               && n > 2) ConvertTo<double>(params[2]);
2471         if (strMethod == "sendfrom"               && n > 3) ConvertTo<boost::int64_t>(params[3]);
2472         if (strMethod == "listtransactions"       && n > 1) ConvertTo<boost::int64_t>(params[1]);
2473         if (strMethod == "listtransactions"       && n > 2) ConvertTo<boost::int64_t>(params[2]);
2474         if (strMethod == "listaccounts"           && n > 0) ConvertTo<boost::int64_t>(params[0]);
2475         if (strMethod == "walletpassphrase"       && n > 1) ConvertTo<boost::int64_t>(params[1]);
2476         if (strMethod == "listsinceblock"         && n > 1) ConvertTo<boost::int64_t>(params[1]);
2477     if (strMethod == "dumpblock"              && n > 0) ConvertTo<boost::int64_t>(params[0]);
2478         if (strMethod == "sendmany"               && n > 1)
2479         {
2480             string s = params[1].get_str();
2481             Value v;
2482             if (!read_string(s, v) || v.type() != obj_type)
2483                 throw runtime_error("type mismatch");
2484             params[1] = v.get_obj();
2485         }
2486         if (strMethod == "sendmany"                && n > 2) ConvertTo<boost::int64_t>(params[2]);
2487 
2488         // Execute
2489         Object reply = CallRPC(strMethod, params);
2490 
2491         // Parse reply
2492         const Value& result = find_value(reply, "result");
2493         const Value& error  = find_value(reply, "error");
2494 
2495         if (error.type() != null_type)
2496         {
2497             // Error
2498             strPrint = "error: " + write_string(error, false);
2499             int code = find_value(error.get_obj(), "code").get_int();
2500             nRet = abs(code);
2501         }
2502         else
2503         {
2504             // Result
2505             if (result.type() == null_type)
2506                 strPrint = "";
2507             else if (result.type() == str_type)
2508                 strPrint = result.get_str();
2509             else
2510                 strPrint = write_string(result, true);
2511         }
2512     }
2513     catch (std::exception& e)
2514     {
2515         strPrint = string("error: ") + e.what();
2516         nRet = 87;
2517     }
2518     catch (...)
2519     {
2520         PrintException(NULL, "CommandLineRPC()");
2521     }
2522 
2523     if (strPrint != "")
2524     {
2525         fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
2526     }
2527     return nRet;
2528 }
2529 
2530 
2531 
2532 
2533 #ifdef TEST
2534 int main(int argc, char *argv[])
2535 {
2536     setbuf(stdin, NULL);
2537     setbuf(stdout, NULL);
2538     setbuf(stderr, NULL);
2539 
2540     try
2541     {
2542         if (argc >= 2 && string(argv[1]) == "-server")
2543         {
2544             printf("server ready\n");
2545             ThreadRPCServer(NULL);
2546         }
2547         else
2548         {
2549             return CommandLineRPC(argc, argv);
2550         }
2551     }
2552     catch (std::exception& e) {
2553         PrintException(&e, "main()");
2554     } catch (...) {
2555         PrintException(NULL, "main()");
2556     }
2557     return 0;
2558 }
2559 #endif