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