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