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