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