Back to home page

Bitcoin sources

 
 

    


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