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