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