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"
mod6_privkey_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
mod6_manifest 25 // v0.5.4 RELEASE (keccak)
mod6_manifest 26
genesis 27 using namespace std;
genesis 28 using namespace boost;
genesis 29 using namespace boost::asio;
genesis 30 using namespace json_spirit;
genesis 31
genesis 32 void ThreadRPCServer2(void* parg);
genesis 33 typedef Value(*rpcfn_type)(const Array& params, bool fHelp);
genesis 34 extern map<string, rpcfn_type> mapCallTable;
genesis 35
genesis 36 static std::string strRPCUserColonPass;
genesis 37
genesis 38 static int64 nWalletUnlockTime;
genesis 39 static CCriticalSection cs_nWalletUnlockTime;
genesis 40
genesis 41
genesis 42 Object JSONRPCError(int code, const string& message)
genesis 43 {
genesis 44 Object error;
genesis 45 error.push_back(Pair("code", code));
genesis 46 error.push_back(Pair("message", message));
genesis 47 return error;
genesis 48 }
genesis 49
genesis 50
genesis 51 void PrintConsole(const std::string &format, ...)
genesis 52 {
genesis 53 char buffer[50000];
genesis 54 int limit = sizeof(buffer);
genesis 55 va_list arg_ptr;
genesis 56 va_start(arg_ptr, format);
genesis 57 int ret = _vsnprintf(buffer, limit, format.c_str(), arg_ptr);
genesis 58 va_end(arg_ptr);
genesis 59 if (ret < 0 || ret >= limit)
genesis 60 {
genesis 61 ret = limit - 1;
genesis 62 buffer[limit-1] = 0;
genesis 63 }
genesis 64 printf("%s", buffer);
genesis 65 fprintf(stdout, "%s", buffer);
genesis 66 }
genesis 67
genesis 68
genesis 69 int64 AmountFromValue(const Value& value)
genesis 70 {
genesis 71 double dAmount = value.get_real();
genesis 72 if (dAmount <= 0.0 || dAmount > 21000000.0)
genesis 73 throw JSONRPCError(-3, "Invalid amount");
genesis 74 int64 nAmount = roundint64(dAmount * COIN);
genesis 75 if (!MoneyRange(nAmount))
genesis 76 throw JSONRPCError(-3, "Invalid amount");
genesis 77 return nAmount;
genesis 78 }
genesis 79
genesis 80 Value ValueFromAmount(int64 amount)
genesis 81 {
genesis 82 return (double)amount / (double)COIN;
genesis 83 }
genesis 84
genesis 85 void WalletTxToJSON(const CWalletTx& wtx, Object& entry)
genesis 86 {
genesis 87 entry.push_back(Pair("confirmations", wtx.GetDepthInMainChain()));
genesis 88 entry.push_back(Pair("txid", wtx.GetHash().GetHex()));
genesis 89 entry.push_back(Pair("time", (boost::int64_t)wtx.GetTxTime()));
genesis 90 BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue)
genesis 91 entry.push_back(Pair(item.first, item.second));
genesis 92 }
genesis 93
genesis 94 string AccountFromValue(const Value& value)
genesis 95 {
genesis 96 string strAccount = value.get_str();
genesis 97 if (strAccount == "*")
genesis 98 throw JSONRPCError(-11, "Invalid account name");
genesis 99 return strAccount;
genesis 100 }
genesis 101
genesis 102
genesis 103
genesis 104 ///
genesis 105 /// Note: This interface may still be subject to change.
genesis 106 ///
genesis 107
genesis 108
genesis 109 Value help(const Array& params, bool fHelp)
genesis 110 {
genesis 111 if (fHelp || params.size() > 1)
genesis 112 throw runtime_error(
genesis 113 "help [command]\n"
genesis 114 "List commands, or get help for a command.");
genesis 115
genesis 116 string strCommand;
genesis 117 if (params.size() > 0)
genesis 118 strCommand = params[0].get_str();
genesis 119
genesis 120 string strRet;
genesis 121 set<rpcfn_type> setDone;
genesis 122 for (map<string, rpcfn_type>::iterator mi = mapCallTable.begin(); mi != mapCallTable.end(); ++mi)
genesis 123 {
genesis 124 string strMethod = (*mi).first;
genesis 125 // We already filter duplicates, but these deprecated screw up the sort order
genesis 126 if (strMethod == "getamountreceived" ||
genesis 127 strMethod == "getallreceived" ||
genesis 128 strMethod == "getblocknumber" || // deprecated
genesis 129 (strMethod.find("label") != string::npos))
genesis 130 continue;
genesis 131 if (strCommand != "" && strMethod != strCommand)
genesis 132 continue;
genesis 133 try
genesis 134 {
genesis 135 Array params;
genesis 136 rpcfn_type pfn = (*mi).second;
genesis 137 if (setDone.insert(pfn).second)
genesis 138 (*pfn)(params, true);
genesis 139 }
genesis 140 catch (std::exception& e)
genesis 141 {
genesis 142 // Help text is returned in an exception
genesis 143 string strHelp = string(e.what());
genesis 144 if (strCommand == "")
genesis 145 if (strHelp.find('\n') != -1)
genesis 146 strHelp = strHelp.substr(0, strHelp.find('\n'));
genesis 147 strRet += strHelp + "\n";
genesis 148 }
genesis 149 }
genesis 150 if (strRet == "")
genesis 151 strRet = strprintf("help: unknown command: %s\n", strCommand.c_str());
genesis 152 strRet = strRet.substr(0,strRet.size()-1);
genesis 153 return strRet;
genesis 154 }
genesis 155
genesis 156
genesis 157 Value stop(const Array& params, bool fHelp)
genesis 158 {
genesis 159 if (fHelp || params.size() != 0)
genesis 160 throw runtime_error(
genesis 161 "stop\n"
genesis 162 "Stop bitcoin server.");
genesis 163 // Shutdown will take long enough that the response should get back
genesis 164 CreateThread(Shutdown, NULL);
genesis 165 return "bitcoin server stopping";
genesis 166 }
genesis 167
genesis 168
genesis 169 Value getblockcount(const Array& params, bool fHelp)
genesis 170 {
genesis 171 if (fHelp || params.size() != 0)
genesis 172 throw runtime_error(
genesis 173 "getblockcount\n"
genesis 174 "Returns the number of blocks in the longest block chain.");
genesis 175
genesis 176 return nBestHeight;
genesis 177 }
genesis 178
genesis 179
genesis 180 // deprecated
genesis 181 Value getblocknumber(const Array& params, bool fHelp)
genesis 182 {
genesis 183 if (fHelp || params.size() != 0)
genesis 184 throw runtime_error(
genesis 185 "getblocknumber\n"
genesis 186 "Deprecated. Use getblockcount.");
genesis 187
genesis 188 return nBestHeight;
genesis 189 }
genesis 190
genesis 191
genesis 192 Value getconnectioncount(const Array& params, bool fHelp)
genesis 193 {
genesis 194 if (fHelp || params.size() != 0)
genesis 195 throw runtime_error(
genesis 196 "getconnectioncount\n"
genesis 197 "Returns the number of connections to other nodes.");
genesis 198
genesis 199 return (int)vNodes.size();
genesis 200 }
genesis 201
genesis 202
genesis 203 double GetDifficulty()
genesis 204 {
genesis 205 // Floating point number that is a multiple of the minimum difficulty,
genesis 206 // minimum difficulty = 1.0.
genesis 207
genesis 208 if (pindexBest == NULL)
genesis 209 return 1.0;
genesis 210 int nShift = (pindexBest->nBits >> 24) & 0xff;
genesis 211
genesis 212 double dDiff =
genesis 213 (double)0x0000ffff / (double)(pindexBest->nBits & 0x00ffffff);
genesis 214
genesis 215 while (nShift < 29)
genesis 216 {
genesis 217 dDiff *= 256.0;
genesis 218 nShift++;
genesis 219 }
genesis 220 while (nShift > 29)
genesis 221 {
genesis 222 dDiff /= 256.0;
genesis 223 nShift--;
genesis 224 }
genesis 225
genesis 226 return dDiff;
genesis 227 }
genesis 228
genesis 229 Value getdifficulty(const Array& params, bool fHelp)
genesis 230 {
genesis 231 if (fHelp || params.size() != 0)
genesis 232 throw runtime_error(
genesis 233 "getdifficulty\n"
genesis 234 "Returns the proof-of-work difficulty as a multiple of the minimum difficulty.");
genesis 235
genesis 236 return GetDifficulty();
genesis 237 }
genesis 238
genesis 239
genesis 240 Value getgenerate(const Array& params, bool fHelp)
genesis 241 {
genesis 242 if (fHelp || params.size() != 0)
genesis 243 throw runtime_error(
genesis 244 "getgenerate\n"
genesis 245 "Returns true or false.");
genesis 246
genesis 247 return (bool)fGenerateBitcoins;
genesis 248 }
genesis 249
genesis 250
genesis 251 Value setgenerate(const Array& params, bool fHelp)
genesis 252 {
genesis 253 if (fHelp || params.size() < 1 || params.size() > 2)
genesis 254 throw runtime_error(
genesis 255 "setgenerate <generate> [genproclimit]\n"
genesis 256 "<generate> is true or false to turn generation on or off.\n"
genesis 257 "Generation is limited to [genproclimit] processors, -1 is unlimited.");
genesis 258
genesis 259 bool fGenerate = true;
genesis 260 if (params.size() > 0)
genesis 261 fGenerate = params[0].get_bool();
genesis 262
genesis 263 if (params.size() > 1)
genesis 264 {
genesis 265 int nGenProcLimit = params[1].get_int();
genesis 266 fLimitProcessors = (nGenProcLimit != -1);
genesis 267 WriteSetting("fLimitProcessors", fLimitProcessors);
genesis 268 if (nGenProcLimit != -1)
genesis 269 WriteSetting("nLimitProcessors", nLimitProcessors = nGenProcLimit);
genesis 270 if (nGenProcLimit == 0)
genesis 271 fGenerate = false;
genesis 272 }
genesis 273
genesis 274 GenerateBitcoins(fGenerate, pwalletMain);
genesis 275 return Value::null;
genesis 276 }
genesis 277
genesis 278
genesis 279 Value gethashespersec(const Array& params, bool fHelp)
genesis 280 {
genesis 281 if (fHelp || params.size() != 0)
genesis 282 throw runtime_error(
genesis 283 "gethashespersec\n"
genesis 284 "Returns a recent hashes per second performance measurement while generating.");
genesis 285
genesis 286 if (GetTimeMillis() - nHPSTimerStart > 8000)
genesis 287 return (boost::int64_t)0;
genesis 288 return (boost::int64_t)dHashesPerSec;
genesis 289 }
genesis 290
genesis 291
genesis 292 Value getinfo(const Array& params, bool fHelp)
genesis 293 {
genesis 294 if (fHelp || params.size() != 0)
genesis 295 throw runtime_error(
genesis 296 "getinfo\n"
genesis 297 "Returns an object containing various state info.");
genesis 298
genesis 299 Object obj;
genesis 300 obj.push_back(Pair("version", (int)VERSION));
genesis 301 obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance())));
genesis 302 obj.push_back(Pair("blocks", (int)nBestHeight));
genesis 303 obj.push_back(Pair("connections", (int)vNodes.size()));
genesis 304 obj.push_back(Pair("proxy", (fUseProxy ? addrProxy.ToStringIPPort() : string())));
genesis 305 obj.push_back(Pair("generate", (bool)fGenerateBitcoins));
genesis 306 obj.push_back(Pair("genproclimit", (int)(fLimitProcessors ? nLimitProcessors : -1)));
genesis 307 obj.push_back(Pair("difficulty", (double)GetDifficulty()));
genesis 308 obj.push_back(Pair("hashespersec", gethashespersec(params, false)));
genesis 309 obj.push_back(Pair("keypoololdest", (boost::int64_t)pwalletMain->GetOldestKeyPoolTime()));
genesis 310 obj.push_back(Pair("keypoolsize", pwalletMain->GetKeyPoolSize()));
genesis 311 obj.push_back(Pair("paytxfee", ValueFromAmount(nTransactionFee)));
genesis 312 if (pwalletMain->IsCrypted())
genesis 313 obj.push_back(Pair("unlocked_until", (boost::int64_t)nWalletUnlockTime / 1000));
genesis 314 obj.push_back(Pair("errors", GetWarnings("statusbar")));
genesis 315 return obj;
genesis 316 }
genesis 317
genesis 318
genesis 319 Value getnewaddress(const Array& params, bool fHelp)
genesis 320 {
genesis 321 if (fHelp || params.size() > 1)
genesis 322 throw runtime_error(
genesis 323 "getnewaddress [account]\n"
genesis 324 "Returns a new bitcoin address for receiving payments. "
genesis 325 "If [account] is specified (recommended), it is added to the address book "
genesis 326 "so payments received with the address will be credited to [account].");
genesis 327
genesis 328 // Parse the account first so we don't generate a key if there's an error
genesis 329 string strAccount;
genesis 330 if (params.size() > 0)
genesis 331 strAccount = AccountFromValue(params[0]);
genesis 332
genesis 333 if (!pwalletMain->IsLocked())
genesis 334 pwalletMain->TopUpKeyPool();
genesis 335
genesis 336 // Generate a new key that is added to wallet
genesis 337 std::vector<unsigned char> newKey;
genesis 338 if (!pwalletMain->GetKeyFromPool(newKey, false))
genesis 339 throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
genesis 340 CBitcoinAddress address(newKey);
genesis 341
genesis 342 pwalletMain->SetAddressBookName(address, strAccount);
genesis 343
genesis 344 return address.ToString();
genesis 345 }
genesis 346
genesis 347
genesis 348 CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false)
genesis 349 {
genesis 350 CWalletDB walletdb(pwalletMain->strWalletFile);
genesis 351
genesis 352 CAccount account;
genesis 353 walletdb.ReadAccount(strAccount, account);
genesis 354
genesis 355 bool bKeyUsed = false;
genesis 356
genesis 357 // Check if the current key has been used
genesis 358 if (!account.vchPubKey.empty())
genesis 359 {
genesis 360 CScript scriptPubKey;
genesis 361 scriptPubKey.SetBitcoinAddress(account.vchPubKey);
genesis 362 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
genesis 363 it != pwalletMain->mapWallet.end() && !account.vchPubKey.empty();
genesis 364 ++it)
genesis 365 {
genesis 366 const CWalletTx& wtx = (*it).second;
genesis 367 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
genesis 368 if (txout.scriptPubKey == scriptPubKey)
genesis 369 bKeyUsed = true;
genesis 370 }
genesis 371 }
genesis 372
genesis 373 // Generate a new key
genesis 374 if (account.vchPubKey.empty() || bForceNew || bKeyUsed)
genesis 375 {
genesis 376 if (!pwalletMain->GetKeyFromPool(account.vchPubKey, false))
genesis 377 throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
genesis 378
genesis 379 pwalletMain->SetAddressBookName(CBitcoinAddress(account.vchPubKey), strAccount);
genesis 380 walletdb.WriteAccount(strAccount, account);
genesis 381 }
genesis 382
genesis 383 return CBitcoinAddress(account.vchPubKey);
genesis 384 }
genesis 385
genesis 386 Value getaccountaddress(const Array& params, bool fHelp)
genesis 387 {
genesis 388 if (fHelp || params.size() != 1)
genesis 389 throw runtime_error(
genesis 390 "getaccountaddress <account>\n"
genesis 391 "Returns the current bitcoin address for receiving payments to this account.");
genesis 392
genesis 393 // Parse the account first so we don't generate a key if there's an error
genesis 394 string strAccount = AccountFromValue(params[0]);
genesis 395
genesis 396 Value ret;
genesis 397
genesis 398 ret = GetAccountAddress(strAccount).ToString();
genesis 399
genesis 400 return ret;
genesis 401 }
genesis 402
genesis 403
genesis 404
genesis 405 Value setaccount(const Array& params, bool fHelp)
genesis 406 {
genesis 407 if (fHelp || params.size() < 1 || params.size() > 2)
genesis 408 throw runtime_error(
genesis 409 "setaccount <bitcoinaddress> <account>\n"
genesis 410 "Sets the account associated with the given address.");
genesis 411
genesis 412 CBitcoinAddress address(params[0].get_str());
genesis 413 if (!address.IsValid())
genesis 414 throw JSONRPCError(-5, "Invalid bitcoin address");
genesis 415
genesis 416
genesis 417 string strAccount;
genesis 418 if (params.size() > 1)
genesis 419 strAccount = AccountFromValue(params[1]);
genesis 420
genesis 421 // Detect when changing the account of an address that is the 'unused current key' of another account:
genesis 422 if (pwalletMain->mapAddressBook.count(address))
genesis 423 {
genesis 424 string strOldAccount = pwalletMain->mapAddressBook[address];
genesis 425 if (address == GetAccountAddress(strOldAccount))
genesis 426 GetAccountAddress(strOldAccount, true);
genesis 427 }
genesis 428
genesis 429 pwalletMain->SetAddressBookName(address, strAccount);
genesis 430
genesis 431 return Value::null;
genesis 432 }
genesis 433
genesis 434
genesis 435 Value getaccount(const Array& params, bool fHelp)
genesis 436 {
genesis 437 if (fHelp || params.size() != 1)
genesis 438 throw runtime_error(
genesis 439 "getaccount <bitcoinaddress>\n"
genesis 440 "Returns the account associated with the given address.");
genesis 441
genesis 442 CBitcoinAddress address(params[0].get_str());
genesis 443 if (!address.IsValid())
genesis 444 throw JSONRPCError(-5, "Invalid bitcoin address");
genesis 445
genesis 446 string strAccount;
genesis 447 map<CBitcoinAddress, string>::iterator mi = pwalletMain->mapAddressBook.find(address);
genesis 448 if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.empty())
genesis 449 strAccount = (*mi).second;
genesis 450 return strAccount;
genesis 451 }
genesis 452
genesis 453
genesis 454 Value getaddressesbyaccount(const Array& params, bool fHelp)
genesis 455 {
genesis 456 if (fHelp || params.size() != 1)
genesis 457 throw runtime_error(
genesis 458 "getaddressesbyaccount <account>\n"
genesis 459 "Returns the list of addresses for the given account.");
genesis 460
genesis 461 string strAccount = AccountFromValue(params[0]);
genesis 462
genesis 463 // Find all addresses that have the given account
genesis 464 Array ret;
genesis 465 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
genesis 466 {
genesis 467 const CBitcoinAddress& address = item.first;
genesis 468 const string& strName = item.second;
genesis 469 if (strName == strAccount)
genesis 470 ret.push_back(address.ToString());
genesis 471 }
genesis 472 return ret;
genesis 473 }
genesis 474
genesis 475 Value settxfee(const Array& params, bool fHelp)
genesis 476 {
genesis 477 if (fHelp || params.size() < 1 || params.size() > 1)
genesis 478 throw runtime_error(
genesis 479 "settxfee <amount>\n"
genesis 480 "<amount> is a real and is rounded to the nearest 0.00000001");
genesis 481
genesis 482 // Amount
genesis 483 int64 nAmount = 0;
genesis 484 if (params[0].get_real() != 0.0)
genesis 485 nAmount = AmountFromValue(params[0]); // rejects 0.0 amounts
genesis 486
genesis 487 nTransactionFee = nAmount;
genesis 488 return true;
genesis 489 }
genesis 490
genesis 491 Value sendtoaddress(const Array& params, bool fHelp)
genesis 492 {
genesis 493 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
genesis 494 throw runtime_error(
genesis 495 "sendtoaddress <bitcoinaddress> <amount> [comment] [comment-to]\n"
genesis 496 "<amount> is a real and is rounded to the nearest 0.00000001\n"
genesis 497 "requires wallet passphrase to be set with walletpassphrase first");
genesis 498 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
genesis 499 throw runtime_error(
genesis 500 "sendtoaddress <bitcoinaddress> <amount> [comment] [comment-to]\n"
genesis 501 "<amount> is a real and is rounded to the nearest 0.00000001");
genesis 502
genesis 503 CBitcoinAddress address(params[0].get_str());
genesis 504 if (!address.IsValid())
genesis 505 throw JSONRPCError(-5, "Invalid bitcoin address");
genesis 506
genesis 507 // Amount
genesis 508 int64 nAmount = AmountFromValue(params[1]);
genesis 509
genesis 510 // Wallet comments
genesis 511 CWalletTx wtx;
genesis 512 if (params.size() > 2 && params[2].type() != null_type && !params[2].get_str().empty())
genesis 513 wtx.mapValue["comment"] = params[2].get_str();
genesis 514 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
genesis 515 wtx.mapValue["to"] = params[3].get_str();
genesis 516
genesis 517 if (pwalletMain->IsLocked())
genesis 518 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
genesis 519
genesis 520 string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
genesis 521 if (strError != "")
genesis 522 throw JSONRPCError(-4, strError);
genesis 523
genesis 524 return wtx.GetHash().GetHex();
genesis 525 }
genesis 526
genesis 527 static const string strMessageMagic = "Bitcoin Signed Message:\n";
genesis 528
genesis 529 Value signmessage(const Array& params, bool fHelp)
genesis 530 {
genesis 531 if (fHelp || params.size() != 2)
genesis 532 throw runtime_error(
genesis 533 "signmessage <bitcoinaddress> <message>\n"
genesis 534 "Sign a message with the private key of an address");
genesis 535
genesis 536 if (pwalletMain->IsLocked())
genesis 537 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
genesis 538
genesis 539 string strAddress = params[0].get_str();
genesis 540 string strMessage = params[1].get_str();
genesis 541
genesis 542 CBitcoinAddress addr(strAddress);
genesis 543 if (!addr.IsValid())
genesis 544 throw JSONRPCError(-3, "Invalid address");
genesis 545
genesis 546 CKey key;
genesis 547 if (!pwalletMain->GetKey(addr, key))
genesis 548 throw JSONRPCError(-4, "Private key not available");
genesis 549
genesis 550 CDataStream ss(SER_GETHASH);
genesis 551 ss << strMessageMagic;
genesis 552 ss << strMessage;
genesis 553
genesis 554 vector<unsigned char> vchSig;
genesis 555 if (!key.SignCompact(Hash(ss.begin(), ss.end()), vchSig))
genesis 556 throw JSONRPCError(-5, "Sign failed");
genesis 557
genesis 558 return EncodeBase64(&vchSig[0], vchSig.size());
genesis 559 }
genesis 560
genesis 561 Value verifymessage(const Array& params, bool fHelp)
genesis 562 {
genesis 563 if (fHelp || params.size() != 3)
genesis 564 throw runtime_error(
genesis 565 "verifymessage <bitcoinaddress> <signature> <message>\n"
genesis 566 "Verify a signed message");
genesis 567
genesis 568 string strAddress = params[0].get_str();
genesis 569 string strSign = params[1].get_str();
genesis 570 string strMessage = params[2].get_str();
genesis 571
genesis 572 CBitcoinAddress addr(strAddress);
genesis 573 if (!addr.IsValid())
genesis 574 throw JSONRPCError(-3, "Invalid address");
genesis 575
genesis 576 bool fInvalid = false;
genesis 577 vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid);
genesis 578
genesis 579 if (fInvalid)
genesis 580 throw JSONRPCError(-5, "Malformed base64 encoding");
genesis 581
genesis 582 CDataStream ss(SER_GETHASH);
genesis 583 ss << strMessageMagic;
genesis 584 ss << strMessage;
genesis 585
genesis 586 CKey key;
genesis 587 if (!key.SetCompactSignature(Hash(ss.begin(), ss.end()), vchSig))
genesis 588 return false;
genesis 589
mod6_privkey_tools 590 return (CBitcoinAddress(key.GetPubKey()) == addr);
genesis 591 }
genesis 592
genesis 593
genesis 594 Value getreceivedbyaddress(const Array& params, bool fHelp)
genesis 595 {
genesis 596 if (fHelp || params.size() < 1 || params.size() > 2)
genesis 597 throw runtime_error(
genesis 598 "getreceivedbyaddress <bitcoinaddress> [minconf=1]\n"
genesis 599 "Returns the total amount received by <bitcoinaddress> in transactions with at least [minconf] confirmations.");
genesis 600
genesis 601 // Bitcoin address
genesis 602 CBitcoinAddress address = CBitcoinAddress(params[0].get_str());
genesis 603 CScript scriptPubKey;
genesis 604 if (!address.IsValid())
genesis 605 throw JSONRPCError(-5, "Invalid bitcoin address");
genesis 606 scriptPubKey.SetBitcoinAddress(address);
genesis 607 if (!IsMine(*pwalletMain,scriptPubKey))
genesis 608 return (double)0.0;
genesis 609
genesis 610 // Minimum confirmations
genesis 611 int nMinDepth = 1;
genesis 612 if (params.size() > 1)
genesis 613 nMinDepth = params[1].get_int();
genesis 614
genesis 615 // Tally
genesis 616 int64 nAmount = 0;
genesis 617 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
genesis 618 {
genesis 619 const CWalletTx& wtx = (*it).second;
genesis 620 if (wtx.IsCoinBase() || !wtx.IsFinal())
genesis 621 continue;
genesis 622
genesis 623 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
genesis 624 if (txout.scriptPubKey == scriptPubKey)
genesis 625 if (wtx.GetDepthInMainChain() >= nMinDepth)
genesis 626 nAmount += txout.nValue;
genesis 627 }
genesis 628
genesis 629 return ValueFromAmount(nAmount);
genesis 630 }
genesis 631
genesis 632
genesis 633 void GetAccountAddresses(string strAccount, set<CBitcoinAddress>& setAddress)
genesis 634 {
genesis 635 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
genesis 636 {
genesis 637 const CBitcoinAddress& address = item.first;
genesis 638 const string& strName = item.second;
genesis 639 if (strName == strAccount)
genesis 640 setAddress.insert(address);
genesis 641 }
genesis 642 }
genesis 643
genesis 644
genesis 645 Value getreceivedbyaccount(const Array& params, bool fHelp)
genesis 646 {
genesis 647 if (fHelp || params.size() < 1 || params.size() > 2)
genesis 648 throw runtime_error(
genesis 649 "getreceivedbyaccount <account> [minconf=1]\n"
genesis 650 "Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.");
genesis 651
genesis 652 // Minimum confirmations
genesis 653 int nMinDepth = 1;
genesis 654 if (params.size() > 1)
genesis 655 nMinDepth = params[1].get_int();
genesis 656
genesis 657 // Get the set of pub keys that have the label
genesis 658 string strAccount = AccountFromValue(params[0]);
genesis 659 set<CBitcoinAddress> setAddress;
genesis 660 GetAccountAddresses(strAccount, setAddress);
genesis 661
genesis 662 // Tally
genesis 663 int64 nAmount = 0;
genesis 664 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
genesis 665 {
genesis 666 const CWalletTx& wtx = (*it).second;
genesis 667 if (wtx.IsCoinBase() || !wtx.IsFinal())
genesis 668 continue;
genesis 669
genesis 670 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
genesis 671 {
genesis 672 CBitcoinAddress address;
genesis 673 if (ExtractAddress(txout.scriptPubKey, pwalletMain, address) && setAddress.count(address))
genesis 674 if (wtx.GetDepthInMainChain() >= nMinDepth)
genesis 675 nAmount += txout.nValue;
genesis 676 }
genesis 677 }
genesis 678
genesis 679 return (double)nAmount / (double)COIN;
genesis 680 }
genesis 681
genesis 682
genesis 683 int64 GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth)
genesis 684 {
genesis 685 int64 nBalance = 0;
genesis 686
genesis 687 // Tally wallet transactions
genesis 688 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
genesis 689 {
genesis 690 const CWalletTx& wtx = (*it).second;
genesis 691 if (!wtx.IsFinal())
genesis 692 continue;
genesis 693
genesis 694 int64 nGenerated, nReceived, nSent, nFee;
genesis 695 wtx.GetAccountAmounts(strAccount, nGenerated, nReceived, nSent, nFee);
genesis 696
genesis 697 if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
genesis 698 nBalance += nReceived;
genesis 699 nBalance += nGenerated - nSent - nFee;
genesis 700 }
genesis 701
genesis 702 // Tally internal accounting entries
genesis 703 nBalance += walletdb.GetAccountCreditDebit(strAccount);
genesis 704
genesis 705 return nBalance;
genesis 706 }
genesis 707
genesis 708 int64 GetAccountBalance(const string& strAccount, int nMinDepth)
genesis 709 {
genesis 710 CWalletDB walletdb(pwalletMain->strWalletFile);
genesis 711 return GetAccountBalance(walletdb, strAccount, nMinDepth);
genesis 712 }
genesis 713
genesis 714
genesis 715 Value getbalance(const Array& params, bool fHelp)
genesis 716 {
genesis 717 if (fHelp || params.size() > 2)
genesis 718 throw runtime_error(
genesis 719 "getbalance [account] [minconf=1]\n"
genesis 720 "If [account] is not specified, returns the server's total available balance.\n"
genesis 721 "If [account] is specified, returns the balance in the account.");
genesis 722
genesis 723 if (params.size() == 0)
genesis 724 return ValueFromAmount(pwalletMain->GetBalance());
genesis 725
genesis 726 int nMinDepth = 1;
genesis 727 if (params.size() > 1)
genesis 728 nMinDepth = params[1].get_int();
genesis 729
genesis 730 if (params[0].get_str() == "*") {
genesis 731 // Calculate total balance a different way from GetBalance()
genesis 732 // (GetBalance() sums up all unspent TxOuts)
genesis 733 // getbalance and getbalance '*' should always return the same number.
genesis 734 int64 nBalance = 0;
genesis 735 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
genesis 736 {
genesis 737 const CWalletTx& wtx = (*it).second;
genesis 738 if (!wtx.IsFinal())
genesis 739 continue;
genesis 740
genesis 741 int64 allGeneratedImmature, allGeneratedMature, allFee;
genesis 742 allGeneratedImmature = allGeneratedMature = allFee = 0;
genesis 743 string strSentAccount;
genesis 744 list<pair<CBitcoinAddress, int64> > listReceived;
genesis 745 list<pair<CBitcoinAddress, int64> > listSent;
genesis 746 wtx.GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount);
genesis 747 if (wtx.GetDepthInMainChain() >= nMinDepth)
genesis 748 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listReceived)
genesis 749 nBalance += r.second;
genesis 750 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listSent)
genesis 751 nBalance -= r.second;
genesis 752 nBalance -= allFee;
genesis 753 nBalance += allGeneratedMature;
genesis 754 }
genesis 755 return ValueFromAmount(nBalance);
genesis 756 }
genesis 757
genesis 758 string strAccount = AccountFromValue(params[0]);
genesis 759
genesis 760 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
genesis 761
genesis 762 return ValueFromAmount(nBalance);
genesis 763 }
genesis 764
genesis 765
genesis 766 Value movecmd(const Array& params, bool fHelp)
genesis 767 {
genesis 768 if (fHelp || params.size() < 3 || params.size() > 5)
genesis 769 throw runtime_error(
genesis 770 "move <fromaccount> <toaccount> <amount> [minconf=1] [comment]\n"
genesis 771 "Move from one account in your wallet to another.");
genesis 772
genesis 773 string strFrom = AccountFromValue(params[0]);
genesis 774 string strTo = AccountFromValue(params[1]);
genesis 775 int64 nAmount = AmountFromValue(params[2]);
genesis 776 if (params.size() > 3)
genesis 777 // unused parameter, used to be nMinDepth, keep type-checking it though
genesis 778 (void)params[3].get_int();
genesis 779 string strComment;
genesis 780 if (params.size() > 4)
genesis 781 strComment = params[4].get_str();
genesis 782
genesis 783 CWalletDB walletdb(pwalletMain->strWalletFile);
genesis 784 walletdb.TxnBegin();
genesis 785
genesis 786 int64 nNow = GetAdjustedTime();
genesis 787
genesis 788 // Debit
genesis 789 CAccountingEntry debit;
genesis 790 debit.strAccount = strFrom;
genesis 791 debit.nCreditDebit = -nAmount;
genesis 792 debit.nTime = nNow;
genesis 793 debit.strOtherAccount = strTo;
genesis 794 debit.strComment = strComment;
genesis 795 walletdb.WriteAccountingEntry(debit);
genesis 796
genesis 797 // Credit
genesis 798 CAccountingEntry credit;
genesis 799 credit.strAccount = strTo;
genesis 800 credit.nCreditDebit = nAmount;
genesis 801 credit.nTime = nNow;
genesis 802 credit.strOtherAccount = strFrom;
genesis 803 credit.strComment = strComment;
genesis 804 walletdb.WriteAccountingEntry(credit);
genesis 805
genesis 806 walletdb.TxnCommit();
genesis 807
genesis 808 return true;
genesis 809 }
genesis 810
genesis 811
genesis 812 Value sendfrom(const Array& params, bool fHelp)
genesis 813 {
genesis 814 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
genesis 815 throw runtime_error(
genesis 816 "sendfrom <fromaccount> <tobitcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
genesis 817 "<amount> is a real and is rounded to the nearest 0.00000001\n"
genesis 818 "requires wallet passphrase to be set with walletpassphrase first");
genesis 819 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
genesis 820 throw runtime_error(
genesis 821 "sendfrom <fromaccount> <tobitcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
genesis 822 "<amount> is a real and is rounded to the nearest 0.00000001");
genesis 823
genesis 824 string strAccount = AccountFromValue(params[0]);
genesis 825 CBitcoinAddress address(params[1].get_str());
genesis 826 if (!address.IsValid())
genesis 827 throw JSONRPCError(-5, "Invalid bitcoin address");
genesis 828 int64 nAmount = AmountFromValue(params[2]);
genesis 829 int nMinDepth = 1;
genesis 830 if (params.size() > 3)
genesis 831 nMinDepth = params[3].get_int();
genesis 832
genesis 833 CWalletTx wtx;
genesis 834 wtx.strFromAccount = strAccount;
genesis 835 if (params.size() > 4 && params[4].type() != null_type && !params[4].get_str().empty())
genesis 836 wtx.mapValue["comment"] = params[4].get_str();
genesis 837 if (params.size() > 5 && params[5].type() != null_type && !params[5].get_str().empty())
genesis 838 wtx.mapValue["to"] = params[5].get_str();
genesis 839
genesis 840 if (pwalletMain->IsLocked())
genesis 841 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
genesis 842
genesis 843 // Check funds
genesis 844 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
genesis 845 if (nAmount > nBalance)
genesis 846 throw JSONRPCError(-6, "Account has insufficient funds");
genesis 847
genesis 848 // Send
genesis 849 string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
genesis 850 if (strError != "")
genesis 851 throw JSONRPCError(-4, strError);
genesis 852
genesis 853 return wtx.GetHash().GetHex();
genesis 854 }
genesis 855
genesis 856
genesis 857 Value sendmany(const Array& params, bool fHelp)
genesis 858 {
genesis 859 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
genesis 860 throw runtime_error(
genesis 861 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
genesis 862 "amounts are double-precision floating point numbers\n"
genesis 863 "requires wallet passphrase to be set with walletpassphrase first");
genesis 864 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
genesis 865 throw runtime_error(
genesis 866 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
genesis 867 "amounts are double-precision floating point numbers");
genesis 868
genesis 869 string strAccount = AccountFromValue(params[0]);
genesis 870 Object sendTo = params[1].get_obj();
genesis 871 int nMinDepth = 1;
genesis 872 if (params.size() > 2)
genesis 873 nMinDepth = params[2].get_int();
genesis 874
genesis 875 CWalletTx wtx;
genesis 876 wtx.strFromAccount = strAccount;
genesis 877 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
genesis 878 wtx.mapValue["comment"] = params[3].get_str();
genesis 879
genesis 880 set<CBitcoinAddress> setAddress;
genesis 881 vector<pair<CScript, int64> > vecSend;
genesis 882
genesis 883 int64 totalAmount = 0;
genesis 884 BOOST_FOREACH(const Pair& s, sendTo)
genesis 885 {
genesis 886 CBitcoinAddress address(s.name_);
genesis 887 if (!address.IsValid())
genesis 888 throw JSONRPCError(-5, string("Invalid bitcoin address:")+s.name_);
genesis 889
genesis 890 if (setAddress.count(address))
genesis 891 throw JSONRPCError(-8, string("Invalid parameter, duplicated address: ")+s.name_);
genesis 892 setAddress.insert(address);
genesis 893
genesis 894 CScript scriptPubKey;
genesis 895 scriptPubKey.SetBitcoinAddress(address);
genesis 896 int64 nAmount = AmountFromValue(s.value_);
genesis 897 totalAmount += nAmount;
genesis 898
genesis 899 vecSend.push_back(make_pair(scriptPubKey, nAmount));
genesis 900 }
genesis 901
genesis 902 if (pwalletMain->IsLocked())
genesis 903 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
genesis 904
genesis 905 // Check funds
genesis 906 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
genesis 907 if (totalAmount > nBalance)
genesis 908 throw JSONRPCError(-6, "Account has insufficient funds");
genesis 909
genesis 910 // Send
genesis 911 CReserveKey keyChange(pwalletMain);
genesis 912 int64 nFeeRequired = 0;
genesis 913 bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired);
genesis 914 if (!fCreated)
genesis 915 {
genesis 916 if (totalAmount + nFeeRequired > pwalletMain->GetBalance())
genesis 917 throw JSONRPCError(-6, "Insufficient funds");
genesis 918 throw JSONRPCError(-4, "Transaction creation failed");
genesis 919 }
genesis 920 if (!pwalletMain->CommitTransaction(wtx, keyChange))
genesis 921 throw JSONRPCError(-4, "Transaction commit failed");
genesis 922
genesis 923 return wtx.GetHash().GetHex();
genesis 924 }
genesis 925
genesis 926
genesis 927 struct tallyitem
genesis 928 {
genesis 929 int64 nAmount;
genesis 930 int nConf;
genesis 931 tallyitem()
genesis 932 {
genesis 933 nAmount = 0;
genesis 934 nConf = INT_MAX;
genesis 935 }
genesis 936 };
genesis 937
genesis 938 Value ListReceived(const Array& params, bool fByAccounts)
genesis 939 {
genesis 940 // Minimum confirmations
genesis 941 int nMinDepth = 1;
genesis 942 if (params.size() > 0)
genesis 943 nMinDepth = params[0].get_int();
genesis 944
genesis 945 // Whether to include empty accounts
genesis 946 bool fIncludeEmpty = false;
genesis 947 if (params.size() > 1)
genesis 948 fIncludeEmpty = params[1].get_bool();
genesis 949
genesis 950 // Tally
genesis 951 map<CBitcoinAddress, tallyitem> mapTally;
genesis 952 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
genesis 953 {
genesis 954 const CWalletTx& wtx = (*it).second;
genesis 955 if (wtx.IsCoinBase() || !wtx.IsFinal())
genesis 956 continue;
genesis 957
genesis 958 int nDepth = wtx.GetDepthInMainChain();
genesis 959 if (nDepth < nMinDepth)
genesis 960 continue;
genesis 961
genesis 962 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
genesis 963 {
genesis 964 CBitcoinAddress address;
genesis 965 if (!ExtractAddress(txout.scriptPubKey, pwalletMain, address) || !address.IsValid())
genesis 966 continue;
genesis 967
genesis 968 tallyitem& item = mapTally[address];
genesis 969 item.nAmount += txout.nValue;
genesis 970 item.nConf = min(item.nConf, nDepth);
genesis 971 }
genesis 972 }
genesis 973
genesis 974 // Reply
genesis 975 Array ret;
genesis 976 map<string, tallyitem> mapAccountTally;
genesis 977 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
genesis 978 {
genesis 979 const CBitcoinAddress& address = item.first;
genesis 980 const string& strAccount = item.second;
genesis 981 map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
genesis 982 if (it == mapTally.end() && !fIncludeEmpty)
genesis 983 continue;
genesis 984
genesis 985 int64 nAmount = 0;
genesis 986 int nConf = INT_MAX;
genesis 987 if (it != mapTally.end())
genesis 988 {
genesis 989 nAmount = (*it).second.nAmount;
genesis 990 nConf = (*it).second.nConf;
genesis 991 }
genesis 992
genesis 993 if (fByAccounts)
genesis 994 {
genesis 995 tallyitem& item = mapAccountTally[strAccount];
genesis 996 item.nAmount += nAmount;
genesis 997 item.nConf = min(item.nConf, nConf);
genesis 998 }
genesis 999 else
genesis 1000 {
genesis 1001 Object obj;
genesis 1002 obj.push_back(Pair("address", address.ToString()));
genesis 1003 obj.push_back(Pair("account", strAccount));
genesis 1004 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
genesis 1005 obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf)));
genesis 1006 ret.push_back(obj);
genesis 1007 }
genesis 1008 }
genesis 1009
genesis 1010 if (fByAccounts)
genesis 1011 {
genesis 1012 for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
genesis 1013 {
genesis 1014 int64 nAmount = (*it).second.nAmount;
genesis 1015 int nConf = (*it).second.nConf;
genesis 1016 Object obj;
genesis 1017 obj.push_back(Pair("account", (*it).first));
genesis 1018 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
genesis 1019 obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf)));
genesis 1020 ret.push_back(obj);
genesis 1021 }
genesis 1022 }
genesis 1023
genesis 1024 return ret;
genesis 1025 }
genesis 1026
genesis 1027 Value listreceivedbyaddress(const Array& params, bool fHelp)
genesis 1028 {
genesis 1029 if (fHelp || params.size() > 2)
genesis 1030 throw runtime_error(
genesis 1031 "listreceivedbyaddress [minconf=1] [includeempty=false]\n"
genesis 1032 "[minconf] is the minimum number of confirmations before payments are included.\n"
genesis 1033 "[includeempty] whether to include addresses that haven't received any payments.\n"
genesis 1034 "Returns an array of objects containing:\n"
genesis 1035 " \"address\" : receiving address\n"
genesis 1036 " \"account\" : the account of the receiving address\n"
genesis 1037 " \"amount\" : total amount received by the address\n"
genesis 1038 " \"confirmations\" : number of confirmations of the most recent transaction included");
genesis 1039
genesis 1040 return ListReceived(params, false);
genesis 1041 }
genesis 1042
genesis 1043 Value listreceivedbyaccount(const Array& params, bool fHelp)
genesis 1044 {
genesis 1045 if (fHelp || params.size() > 2)
genesis 1046 throw runtime_error(
genesis 1047 "listreceivedbyaccount [minconf=1] [includeempty=false]\n"
genesis 1048 "[minconf] is the minimum number of confirmations before payments are included.\n"
genesis 1049 "[includeempty] whether to include accounts that haven't received any payments.\n"
genesis 1050 "Returns an array of objects containing:\n"
genesis 1051 " \"account\" : the account of the receiving addresses\n"
genesis 1052 " \"amount\" : total amount received by addresses with this account\n"
genesis 1053 " \"confirmations\" : number of confirmations of the most recent transaction included");
genesis 1054
genesis 1055 return ListReceived(params, true);
genesis 1056 }
genesis 1057
genesis 1058 void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret)
genesis 1059 {
genesis 1060 int64 nGeneratedImmature, nGeneratedMature, nFee;
genesis 1061 string strSentAccount;
genesis 1062 list<pair<CBitcoinAddress, int64> > listReceived;
genesis 1063 list<pair<CBitcoinAddress, int64> > listSent;
genesis 1064 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
genesis 1065
genesis 1066 bool fAllAccounts = (strAccount == string("*"));
genesis 1067
genesis 1068 // Generated blocks assigned to account ""
genesis 1069 if ((nGeneratedMature+nGeneratedImmature) != 0 && (fAllAccounts || strAccount == ""))
genesis 1070 {
genesis 1071 Object entry;
genesis 1072 entry.push_back(Pair("account", string("")));
genesis 1073 if (nGeneratedImmature)
genesis 1074 {
genesis 1075 entry.push_back(Pair("category", wtx.GetDepthInMainChain() ? "immature" : "orphan"));
genesis 1076 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedImmature)));
genesis 1077 }
genesis 1078 else
genesis 1079 {
genesis 1080 entry.push_back(Pair("category", "generate"));
genesis 1081 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedMature)));
genesis 1082 }
genesis 1083 if (fLong)
genesis 1084 WalletTxToJSON(wtx, entry);
genesis 1085 ret.push_back(entry);
genesis 1086 }
genesis 1087
genesis 1088 // Sent
genesis 1089 if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
genesis 1090 {
genesis 1091 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
genesis 1092 {
genesis 1093 Object entry;
genesis 1094 entry.push_back(Pair("account", strSentAccount));
genesis 1095 entry.push_back(Pair("address", s.first.ToString()));
genesis 1096 entry.push_back(Pair("category", "send"));
genesis 1097 entry.push_back(Pair("amount", ValueFromAmount(-s.second)));
genesis 1098 entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
genesis 1099 if (fLong)
genesis 1100 WalletTxToJSON(wtx, entry);
genesis 1101 ret.push_back(entry);
genesis 1102 }
genesis 1103 }
genesis 1104
genesis 1105 // Received
genesis 1106 if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
genesis 1107 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
genesis 1108 {
genesis 1109 string account;
genesis 1110 if (pwalletMain->mapAddressBook.count(r.first))
genesis 1111 account = pwalletMain->mapAddressBook[r.first];
genesis 1112 if (fAllAccounts || (account == strAccount))
genesis 1113 {
genesis 1114 Object entry;
genesis 1115 entry.push_back(Pair("account", account));
genesis 1116 entry.push_back(Pair("address", r.first.ToString()));
genesis 1117 entry.push_back(Pair("category", "receive"));
genesis 1118 entry.push_back(Pair("amount", ValueFromAmount(r.second)));
genesis 1119 if (fLong)
genesis 1120 WalletTxToJSON(wtx, entry);
genesis 1121 ret.push_back(entry);
genesis 1122 }
genesis 1123 }
genesis 1124 }
genesis 1125
genesis 1126 void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret)
genesis 1127 {
genesis 1128 bool fAllAccounts = (strAccount == string("*"));
genesis 1129
genesis 1130 if (fAllAccounts || acentry.strAccount == strAccount)
genesis 1131 {
genesis 1132 Object entry;
genesis 1133 entry.push_back(Pair("account", acentry.strAccount));
genesis 1134 entry.push_back(Pair("category", "move"));
genesis 1135 entry.push_back(Pair("time", (boost::int64_t)acentry.nTime));
genesis 1136 entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
genesis 1137 entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
genesis 1138 entry.push_back(Pair("comment", acentry.strComment));
genesis 1139 ret.push_back(entry);
genesis 1140 }
genesis 1141 }
genesis 1142
genesis 1143 Value listtransactions(const Array& params, bool fHelp)
genesis 1144 {
genesis 1145 if (fHelp || params.size() > 3)
genesis 1146 throw runtime_error(
genesis 1147 "listtransactions [account] [count=10] [from=0]\n"
genesis 1148 "Returns up to [count] most recent transactions skipping the first [from] transactions for account [account].");
genesis 1149
genesis 1150 string strAccount = "*";
genesis 1151 if (params.size() > 0)
genesis 1152 strAccount = params[0].get_str();
genesis 1153 int nCount = 10;
genesis 1154 if (params.size() > 1)
genesis 1155 nCount = params[1].get_int();
genesis 1156 int nFrom = 0;
genesis 1157 if (params.size() > 2)
genesis 1158 nFrom = params[2].get_int();
genesis 1159
genesis 1160 Array ret;
genesis 1161 CWalletDB walletdb(pwalletMain->strWalletFile);
genesis 1162
genesis 1163 // Firs: get all CWalletTx and CAccountingEntry into a sorted-by-time multimap:
genesis 1164 typedef pair<CWalletTx*, CAccountingEntry*> TxPair;
genesis 1165 typedef multimap<int64, TxPair > TxItems;
genesis 1166 TxItems txByTime;
genesis 1167
genesis 1168 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
genesis 1169 {
genesis 1170 CWalletTx* wtx = &((*it).second);
genesis 1171 txByTime.insert(make_pair(wtx->GetTxTime(), TxPair(wtx, (CAccountingEntry*)0)));
genesis 1172 }
genesis 1173 list<CAccountingEntry> acentries;
genesis 1174 walletdb.ListAccountCreditDebit(strAccount, acentries);
genesis 1175 BOOST_FOREACH(CAccountingEntry& entry, acentries)
genesis 1176 {
genesis 1177 txByTime.insert(make_pair(entry.nTime, TxPair((CWalletTx*)0, &entry)));
genesis 1178 }
genesis 1179
genesis 1180 // Now: iterate backwards until we have nCount items to return:
genesis 1181 TxItems::reverse_iterator it = txByTime.rbegin();
genesis 1182 if (txByTime.size() > nFrom) std::advance(it, nFrom);
genesis 1183 for (; it != txByTime.rend(); ++it)
genesis 1184 {
genesis 1185 CWalletTx *const pwtx = (*it).second.first;
genesis 1186 if (pwtx != 0)
genesis 1187 ListTransactions(*pwtx, strAccount, 0, true, ret);
genesis 1188 CAccountingEntry *const pacentry = (*it).second.second;
genesis 1189 if (pacentry != 0)
genesis 1190 AcentryToJSON(*pacentry, strAccount, ret);
genesis 1191
genesis 1192 if (ret.size() >= nCount) break;
genesis 1193 }
genesis 1194 // ret is now newest to oldest
genesis 1195
genesis 1196 // Make sure we return only last nCount items (sends-to-self might give us an extra):
genesis 1197 if (ret.size() > nCount)
genesis 1198 {
genesis 1199 Array::iterator last = ret.begin();
genesis 1200 std::advance(last, nCount);
genesis 1201 ret.erase(last, ret.end());
genesis 1202 }
genesis 1203 std::reverse(ret.begin(), ret.end()); // oldest to newest
genesis 1204
genesis 1205 return ret;
genesis 1206 }
genesis 1207
genesis 1208 Value listaccounts(const Array& params, bool fHelp)
genesis 1209 {
genesis 1210 if (fHelp || params.size() > 1)
genesis 1211 throw runtime_error(
genesis 1212 "listaccounts [minconf=1]\n"
genesis 1213 "Returns Object that has account names as keys, account balances as values.");
genesis 1214
genesis 1215 int nMinDepth = 1;
genesis 1216 if (params.size() > 0)
genesis 1217 nMinDepth = params[0].get_int();
genesis 1218
genesis 1219 map<string, int64> mapAccountBalances;
genesis 1220 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& entry, pwalletMain->mapAddressBook) {
genesis 1221 if (pwalletMain->HaveKey(entry.first)) // This address belongs to me
genesis 1222 mapAccountBalances[entry.second] = 0;
genesis 1223 }
genesis 1224
genesis 1225 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
genesis 1226 {
genesis 1227 const CWalletTx& wtx = (*it).second;
genesis 1228 int64 nGeneratedImmature, nGeneratedMature, nFee;
genesis 1229 string strSentAccount;
genesis 1230 list<pair<CBitcoinAddress, int64> > listReceived;
genesis 1231 list<pair<CBitcoinAddress, int64> > listSent;
genesis 1232 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
genesis 1233 mapAccountBalances[strSentAccount] -= nFee;
genesis 1234 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
genesis 1235 mapAccountBalances[strSentAccount] -= s.second;
genesis 1236 if (wtx.GetDepthInMainChain() >= nMinDepth)
genesis 1237 {
genesis 1238 mapAccountBalances[""] += nGeneratedMature;
genesis 1239 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
genesis 1240 if (pwalletMain->mapAddressBook.count(r.first))
genesis 1241 mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second;
genesis 1242 else
genesis 1243 mapAccountBalances[""] += r.second;
genesis 1244 }
genesis 1245 }
genesis 1246
genesis 1247 list<CAccountingEntry> acentries;
genesis 1248 CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
genesis 1249 BOOST_FOREACH(const CAccountingEntry& entry, acentries)
genesis 1250 mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
genesis 1251
genesis 1252 Object ret;
genesis 1253 BOOST_FOREACH(const PAIRTYPE(string, int64)& accountBalance, mapAccountBalances) {
genesis 1254 ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
genesis 1255 }
genesis 1256 return ret;
genesis 1257 }
genesis 1258
genesis 1259 Value listsinceblock(const Array& params, bool fHelp)
genesis 1260 {
genesis 1261 if (fHelp)
genesis 1262 throw runtime_error(
genesis 1263 "listsinceblock [blockid] [target-confirmations]\n"
genesis 1264 "Get all transactions in blocks since block [blockid], or all transactions if omitted");
genesis 1265
genesis 1266 CBlockIndex *pindex = NULL;
genesis 1267 int target_confirms = 1;
genesis 1268
genesis 1269 if (params.size() > 0)
genesis 1270 {
genesis 1271 uint256 blockId = 0;
genesis 1272
genesis 1273 blockId.SetHex(params[0].get_str());
genesis 1274 pindex = CBlockLocator(blockId).GetBlockIndex();
genesis 1275 }
genesis 1276
genesis 1277 if (params.size() > 1)
genesis 1278 {
genesis 1279 target_confirms = params[1].get_int();
genesis 1280
genesis 1281 if (target_confirms < 1)
genesis 1282 throw JSONRPCError(-8, "Invalid parameter");
genesis 1283 }
genesis 1284
genesis 1285 int depth = pindex ? (1 + nBestHeight - pindex->nHeight) : -1;
genesis 1286
genesis 1287 Array transactions;
genesis 1288
genesis 1289 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++)
genesis 1290 {
genesis 1291 CWalletTx tx = (*it).second;
genesis 1292
genesis 1293 if (depth == -1 || tx.GetDepthInMainChain() < depth)
genesis 1294 ListTransactions(tx, "*", 0, true, transactions);
genesis 1295 }
genesis 1296
genesis 1297 uint256 lastblock;
genesis 1298
genesis 1299 if (target_confirms == 1)
genesis 1300 {
genesis 1301 printf("oops!\n");
genesis 1302 lastblock = hashBestChain;
genesis 1303 }
genesis 1304 else
genesis 1305 {
genesis 1306 int target_height = pindexBest->nHeight + 1 - target_confirms;
genesis 1307
genesis 1308 CBlockIndex *block;
genesis 1309 for (block = pindexBest;
genesis 1310 block && block->nHeight > target_height;
genesis 1311 block = block->pprev) { }
genesis 1312
genesis 1313 lastblock = block ? block->GetBlockHash() : 0;
genesis 1314 }
genesis 1315
genesis 1316 Object ret;
genesis 1317 ret.push_back(Pair("transactions", transactions));
genesis 1318 ret.push_back(Pair("lastblock", lastblock.GetHex()));
genesis 1319
genesis 1320 return ret;
genesis 1321 }
genesis 1322
genesis 1323 Value gettransaction(const Array& params, bool fHelp)
genesis 1324 {
genesis 1325 if (fHelp || params.size() != 1)
genesis 1326 throw runtime_error(
genesis 1327 "gettransaction <txid>\n"
genesis 1328 "Get detailed information about <txid>");
genesis 1329
genesis 1330 uint256 hash;
genesis 1331 hash.SetHex(params[0].get_str());
genesis 1332
genesis 1333 Object entry;
genesis 1334
genesis 1335 if (!pwalletMain->mapWallet.count(hash))
genesis 1336 throw JSONRPCError(-5, "Invalid or non-wallet transaction id");
genesis 1337 const CWalletTx& wtx = pwalletMain->mapWallet[hash];
genesis 1338
genesis 1339 int64 nCredit = wtx.GetCredit();
genesis 1340 int64 nDebit = wtx.GetDebit();
genesis 1341 int64 nNet = nCredit - nDebit;
genesis 1342 int64 nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0);
genesis 1343
genesis 1344 entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
genesis 1345 if (wtx.IsFromMe())
genesis 1346 entry.push_back(Pair("fee", ValueFromAmount(nFee)));
genesis 1347
genesis 1348 WalletTxToJSON(pwalletMain->mapWallet[hash], entry);
genesis 1349
genesis 1350 Array details;
genesis 1351 ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details);
genesis 1352 entry.push_back(Pair("details", details));
genesis 1353
genesis 1354 return entry;
genesis 1355 }
genesis 1356
genesis 1357
genesis 1358 Value backupwallet(const Array& params, bool fHelp)
genesis 1359 {
genesis 1360 if (fHelp || params.size() != 1)
genesis 1361 throw runtime_error(
genesis 1362 "backupwallet <destination>\n"
genesis 1363 "Safely copies wallet.dat to destination, which can be a directory or a path with filename.");
genesis 1364
genesis 1365 string strDest = params[0].get_str();
genesis 1366 BackupWallet(*pwalletMain, strDest);
genesis 1367
genesis 1368 return Value::null;
genesis 1369 }
genesis 1370
genesis 1371
genesis 1372 Value keypoolrefill(const Array& params, bool fHelp)
genesis 1373 {
genesis 1374 if (pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
genesis 1375 throw runtime_error(
genesis 1376 "keypoolrefill\n"
genesis 1377 "Fills the keypool, requires wallet passphrase to be set.");
genesis 1378 if (!pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
genesis 1379 throw runtime_error(
genesis 1380 "keypoolrefill\n"
genesis 1381 "Fills the keypool.");
genesis 1382
genesis 1383 if (pwalletMain->IsLocked())
genesis 1384 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
genesis 1385
genesis 1386 pwalletMain->TopUpKeyPool();
genesis 1387
genesis 1388 if (pwalletMain->GetKeyPoolSize() < GetArg("-keypool", 100))
genesis 1389 throw JSONRPCError(-4, "Error refreshing keypool.");
genesis 1390
genesis 1391 return Value::null;
genesis 1392 }
genesis 1393
genesis 1394
genesis 1395 void ThreadTopUpKeyPool(void* parg)
genesis 1396 {
genesis 1397 pwalletMain->TopUpKeyPool();
genesis 1398 }
genesis 1399
genesis 1400 void ThreadCleanWalletPassphrase(void* parg)
genesis 1401 {
genesis 1402 int64 nMyWakeTime = GetTimeMillis() + *((int64*)parg) * 1000;
genesis 1403
genesis 1404 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
genesis 1405
genesis 1406 if (nWalletUnlockTime == 0)
genesis 1407 {
genesis 1408 nWalletUnlockTime = nMyWakeTime;
genesis 1409
genesis 1410 do
genesis 1411 {
genesis 1412 if (nWalletUnlockTime==0)
genesis 1413 break;
genesis 1414 int64 nToSleep = nWalletUnlockTime - GetTimeMillis();
genesis 1415 if (nToSleep <= 0)
genesis 1416 break;
genesis 1417
genesis 1418 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
genesis 1419 Sleep(nToSleep);
genesis 1420 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
genesis 1421
genesis 1422 } while(1);
genesis 1423
genesis 1424 if (nWalletUnlockTime)
genesis 1425 {
genesis 1426 nWalletUnlockTime = 0;
genesis 1427 pwalletMain->Lock();
genesis 1428 }
genesis 1429 }
genesis 1430 else
genesis 1431 {
genesis 1432 if (nWalletUnlockTime < nMyWakeTime)
genesis 1433 nWalletUnlockTime = nMyWakeTime;
genesis 1434 }
genesis 1435
genesis 1436 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
genesis 1437
genesis 1438 delete (int64*)parg;
genesis 1439 }
genesis 1440
genesis 1441 Value walletpassphrase(const Array& params, bool fHelp)
genesis 1442 {
genesis 1443 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
genesis 1444 throw runtime_error(
genesis 1445 "walletpassphrase <passphrase> <timeout>\n"
genesis 1446 "Stores the wallet decryption key in memory for <timeout> seconds.");
genesis 1447 if (fHelp)
genesis 1448 return true;
genesis 1449 if (!pwalletMain->IsCrypted())
genesis 1450 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
genesis 1451
genesis 1452 if (!pwalletMain->IsLocked())
genesis 1453 throw JSONRPCError(-17, "Error: Wallet is already unlocked.");
genesis 1454
genesis 1455 // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
genesis 1456 SecureString strWalletPass;
genesis 1457 strWalletPass.reserve(100);
genesis 1458 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
genesis 1459 // Alternately, find a way to make params[0] mlock()'d to begin with.
genesis 1460 strWalletPass = params[0].get_str().c_str();
genesis 1461
genesis 1462 if (strWalletPass.length() > 0)
genesis 1463 {
genesis 1464 if (!pwalletMain->Unlock(strWalletPass))
genesis 1465 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
genesis 1466 }
genesis 1467 else
genesis 1468 throw runtime_error(
genesis 1469 "walletpassphrase <passphrase> <timeout>\n"
genesis 1470 "Stores the wallet decryption key in memory for <timeout> seconds.");
genesis 1471
genesis 1472 CreateThread(ThreadTopUpKeyPool, NULL);
genesis 1473 int64* pnSleepTime = new int64(params[1].get_int64());
genesis 1474 CreateThread(ThreadCleanWalletPassphrase, pnSleepTime);
genesis 1475
genesis 1476 return Value::null;
genesis 1477 }
genesis 1478
genesis 1479
genesis 1480 Value walletpassphrasechange(const Array& params, bool fHelp)
genesis 1481 {
genesis 1482 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
genesis 1483 throw runtime_error(
genesis 1484 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
genesis 1485 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
genesis 1486 if (fHelp)
genesis 1487 return true;
genesis 1488 if (!pwalletMain->IsCrypted())
genesis 1489 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
genesis 1490
genesis 1491 // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
genesis 1492 // Alternately, find a way to make params[0] mlock()'d to begin with.
genesis 1493 SecureString strOldWalletPass;
genesis 1494 strOldWalletPass.reserve(100);
genesis 1495 strOldWalletPass = params[0].get_str().c_str();
genesis 1496
genesis 1497 SecureString strNewWalletPass;
genesis 1498 strNewWalletPass.reserve(100);
genesis 1499 strNewWalletPass = params[1].get_str().c_str();
genesis 1500
genesis 1501 if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
genesis 1502 throw runtime_error(
genesis 1503 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
genesis 1504 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
genesis 1505
genesis 1506 if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
genesis 1507 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
genesis 1508
genesis 1509 return Value::null;
genesis 1510 }
genesis 1511
genesis 1512
genesis 1513 Value walletlock(const Array& params, bool fHelp)
genesis 1514 {
genesis 1515 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
genesis 1516 throw runtime_error(
genesis 1517 "walletlock\n"
genesis 1518 "Removes the wallet encryption key from memory, locking the wallet.\n"
genesis 1519 "After calling this method, you will need to call walletpassphrase again\n"
genesis 1520 "before being able to call any methods which require the wallet to be unlocked.");
genesis 1521 if (fHelp)
genesis 1522 return true;
genesis 1523 if (!pwalletMain->IsCrypted())
genesis 1524 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletlock was called.");
genesis 1525
genesis 1526 CRITICAL_BLOCK(cs_nWalletUnlockTime)
genesis 1527 {
genesis 1528 pwalletMain->Lock();
genesis 1529 nWalletUnlockTime = 0;
genesis 1530 }
genesis 1531
genesis 1532 return Value::null;
genesis 1533 }
genesis 1534
genesis 1535
genesis 1536 Value encryptwallet(const Array& params, bool fHelp)
genesis 1537 {
genesis 1538 if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
genesis 1539 throw runtime_error(
genesis 1540 "encryptwallet <passphrase>\n"
genesis 1541 "Encrypts the wallet with <passphrase>.");
genesis 1542 if (fHelp)
genesis 1543 return true;
genesis 1544 if (pwalletMain->IsCrypted())
genesis 1545 throw JSONRPCError(-15, "Error: running with an encrypted wallet, but encryptwallet was called.");
genesis 1546
genesis 1547 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
genesis 1548 // Alternately, find a way to make params[0] mlock()'d to begin with.
genesis 1549 SecureString strWalletPass;
genesis 1550 strWalletPass.reserve(100);
genesis 1551 strWalletPass = params[0].get_str().c_str();
genesis 1552
genesis 1553 if (strWalletPass.length() < 1)
genesis 1554 throw runtime_error(
genesis 1555 "encryptwallet <passphrase>\n"
genesis 1556 "Encrypts the wallet with <passphrase>.");
genesis 1557
genesis 1558 if (!pwalletMain->EncryptWallet(strWalletPass))
genesis 1559 throw JSONRPCError(-16, "Error: Failed to encrypt the wallet.");
genesis 1560
genesis 1561 // BDB seems to have a bad habit of writing old data into
genesis 1562 // slack space in .dat files; that is bad if the old data is
genesis 1563 // unencrypted private keys. So:
genesis 1564 CreateThread(Shutdown, NULL);
genesis 1565 return "wallet encrypted; bitcoin server stopping, restart to run with encrypted wallet";
genesis 1566 }
genesis 1567
genesis 1568
genesis 1569 Value validateaddress(const Array& params, bool fHelp)
genesis 1570 {
genesis 1571 if (fHelp || params.size() != 1)
genesis 1572 throw runtime_error(
genesis 1573 "validateaddress <bitcoinaddress>\n"
genesis 1574 "Return information about <bitcoinaddress>.");
genesis 1575
genesis 1576 CBitcoinAddress address(params[0].get_str());
genesis 1577 bool isValid = address.IsValid();
genesis 1578
genesis 1579 Object ret;
genesis 1580 ret.push_back(Pair("isvalid", isValid));
genesis 1581 if (isValid)
genesis 1582 {
genesis 1583 // Call Hash160ToAddress() so we always return current ADDRESSVERSION
genesis 1584 // version of the address:
genesis 1585 string currentAddress = address.ToString();
genesis 1586 ret.push_back(Pair("address", currentAddress));
genesis 1587 ret.push_back(Pair("ismine", (pwalletMain->HaveKey(address) > 0)));
genesis 1588 if (pwalletMain->mapAddressBook.count(address))
genesis 1589 ret.push_back(Pair("account", pwalletMain->mapAddressBook[address]));
genesis 1590 }
genesis 1591 return ret;
genesis 1592 }
genesis 1593
genesis 1594
genesis 1595 Value getwork(const Array& params, bool fHelp)
genesis 1596 {
genesis 1597 if (fHelp || params.size() > 1)
genesis 1598 throw runtime_error(
genesis 1599 "getwork [data]\n"
genesis 1600 "If [data] is not specified, returns formatted hash data to work on:\n"
genesis 1601 " \"midstate\" : precomputed hash state after hashing the first half of the data (DEPRECATED)\n" // deprecated
genesis 1602 " \"data\" : block data\n"
genesis 1603 " \"hash1\" : formatted hash buffer for second hash (DEPRECATED)\n" // deprecated
genesis 1604 " \"target\" : little endian hash target\n"
genesis 1605 "If [data] is specified, tries to solve the block and returns true if it was successful.");
genesis 1606
genesis 1607 if (vNodes.empty())
genesis 1608 throw JSONRPCError(-9, "Bitcoin is not connected!");
genesis 1609
genesis 1610 if (IsInitialBlockDownload())
genesis 1611 throw JSONRPCError(-10, "Bitcoin is downloading blocks...");
genesis 1612
genesis 1613 typedef map<uint256, pair<CBlock*, CScript> > mapNewBlock_t;
genesis 1614 static mapNewBlock_t mapNewBlock;
genesis 1615 static vector<CBlock*> vNewBlock;
genesis 1616 static CReserveKey reservekey(pwalletMain);
genesis 1617
genesis 1618 if (params.size() == 0)
genesis 1619 {
genesis 1620 // Update block
genesis 1621 static unsigned int nTransactionsUpdatedLast;
genesis 1622 static CBlockIndex* pindexPrev;
genesis 1623 static int64 nStart;
genesis 1624 static CBlock* pblock;
genesis 1625 if (pindexPrev != pindexBest ||
genesis 1626 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60))
genesis 1627 {
genesis 1628 if (pindexPrev != pindexBest)
genesis 1629 {
genesis 1630 // Deallocate old blocks since they're obsolete now
genesis 1631 mapNewBlock.clear();
genesis 1632 BOOST_FOREACH(CBlock* pblock, vNewBlock)
genesis 1633 delete pblock;
genesis 1634 vNewBlock.clear();
genesis 1635 }
genesis 1636 nTransactionsUpdatedLast = nTransactionsUpdated;
genesis 1637 pindexPrev = pindexBest;
genesis 1638 nStart = GetTime();
genesis 1639
genesis 1640 // Create new block
genesis 1641 pblock = CreateNewBlock(reservekey);
genesis 1642 if (!pblock)
genesis 1643 throw JSONRPCError(-7, "Out of memory");
genesis 1644 vNewBlock.push_back(pblock);
genesis 1645 }
genesis 1646
genesis 1647 // Update nTime
genesis 1648 pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
genesis 1649 pblock->nNonce = 0;
genesis 1650
genesis 1651 // Update nExtraNonce
genesis 1652 static unsigned int nExtraNonce = 0;
genesis 1653 IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
genesis 1654
genesis 1655 // Save
genesis 1656 mapNewBlock[pblock->hashMerkleRoot] = make_pair(pblock, pblock->vtx[0].vin[0].scriptSig);
genesis 1657
genesis 1658 // Prebuild hash buffers
genesis 1659 char pmidstate[32];
genesis 1660 char pdata[128];
genesis 1661 char phash1[64];
genesis 1662 FormatHashBuffers(pblock, pmidstate, pdata, phash1);
genesis 1663
genesis 1664 uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
genesis 1665
genesis 1666 Object result;
genesis 1667 result.push_back(Pair("midstate", HexStr(BEGIN(pmidstate), END(pmidstate)))); // deprecated
genesis 1668 result.push_back(Pair("data", HexStr(BEGIN(pdata), END(pdata))));
genesis 1669 result.push_back(Pair("hash1", HexStr(BEGIN(phash1), END(phash1)))); // deprecated
genesis 1670 result.push_back(Pair("target", HexStr(BEGIN(hashTarget), END(hashTarget))));
genesis 1671 return result;
genesis 1672 }
genesis 1673 else
genesis 1674 {
genesis 1675 // Parse parameters
genesis 1676 vector<unsigned char> vchData = ParseHex(params[0].get_str());
genesis 1677 if (vchData.size() != 128)
genesis 1678 throw JSONRPCError(-8, "Invalid parameter");
genesis 1679 CBlock* pdata = (CBlock*)&vchData[0];
genesis 1680
genesis 1681 // Byte reverse
genesis 1682 for (int i = 0; i < 128/4; i++)
genesis 1683 ((unsigned int*)pdata)[i] = ByteReverse(((unsigned int*)pdata)[i]);
genesis 1684
genesis 1685 // Get saved block
genesis 1686 if (!mapNewBlock.count(pdata->hashMerkleRoot))
genesis 1687 return false;
genesis 1688 CBlock* pblock = mapNewBlock[pdata->hashMerkleRoot].first;
genesis 1689
genesis 1690 pblock->nTime = pdata->nTime;
genesis 1691 pblock->nNonce = pdata->nNonce;
genesis 1692 pblock->vtx[0].vin[0].scriptSig = mapNewBlock[pdata->hashMerkleRoot].second;
genesis 1693 pblock->hashMerkleRoot = pblock->BuildMerkleTree();
genesis 1694
genesis 1695 return CheckWork(pblock, *pwalletMain, reservekey);
genesis 1696 }
genesis 1697 }
genesis 1698
genesis 1699
genesis 1700 Value getmemorypool(const Array& params, bool fHelp)
genesis 1701 {
genesis 1702 if (fHelp || params.size() > 1)
genesis 1703 throw runtime_error(
genesis 1704 "getmemorypool [data]\n"
genesis 1705 "If [data] is not specified, returns data needed to construct a block to work on:\n"
genesis 1706 " \"version\" : block version\n"
genesis 1707 " \"previousblockhash\" : hash of current highest block\n"
genesis 1708 " \"transactions\" : contents of non-coinbase transactions that should be included in the next block\n"
genesis 1709 " \"coinbasevalue\" : maximum allowable input to coinbase transaction, including the generation award and transaction fees\n"
genesis 1710 " \"time\" : timestamp appropriate for next block\n"
genesis 1711 " \"bits\" : compressed target of next block\n"
genesis 1712 "If [data] is specified, tries to solve the block and returns true if it was successful.");
genesis 1713
genesis 1714 if (params.size() == 0)
genesis 1715 {
genesis 1716 if (vNodes.empty())
genesis 1717 throw JSONRPCError(-9, "Bitcoin is not connected!");
genesis 1718
genesis 1719 if (IsInitialBlockDownload())
genesis 1720 throw JSONRPCError(-10, "Bitcoin is downloading blocks...");
genesis 1721
genesis 1722 static CReserveKey reservekey(pwalletMain);
genesis 1723
genesis 1724 // Update block
genesis 1725 static unsigned int nTransactionsUpdatedLast;
genesis 1726 static CBlockIndex* pindexPrev;
genesis 1727 static int64 nStart;
genesis 1728 static CBlock* pblock;
genesis 1729 if (pindexPrev != pindexBest ||
genesis 1730 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 5))
genesis 1731 {
genesis 1732 nTransactionsUpdatedLast = nTransactionsUpdated;
genesis 1733 pindexPrev = pindexBest;
genesis 1734 nStart = GetTime();
genesis 1735
genesis 1736 // Create new block
genesis 1737 if(pblock)
genesis 1738 delete pblock;
genesis 1739 pblock = CreateNewBlock(reservekey);
genesis 1740 if (!pblock)
genesis 1741 throw JSONRPCError(-7, "Out of memory");
genesis 1742 }
genesis 1743
genesis 1744 // Update nTime
genesis 1745 pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
genesis 1746 pblock->nNonce = 0;
genesis 1747
genesis 1748 Array transactions;
genesis 1749 BOOST_FOREACH(CTransaction tx, pblock->vtx) {
genesis 1750 if(tx.IsCoinBase())
genesis 1751 continue;
genesis 1752
genesis 1753 CDataStream ssTx;
genesis 1754 ssTx << tx;
genesis 1755
genesis 1756 transactions.push_back(HexStr(ssTx.begin(), ssTx.end()));
genesis 1757 }
genesis 1758
genesis 1759 Object result;
genesis 1760 result.push_back(Pair("version", pblock->nVersion));
genesis 1761 result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex()));
genesis 1762 result.push_back(Pair("transactions", transactions));
asciilifeform-kil... 1763 result.push_back(Pair("coinbasevalue", (boost::int64_t)pblock->vtx[0].vout[0].nValue));
asciilifeform-kil... 1764 result.push_back(Pair("time", (boost::int64_t)pblock->nTime));
genesis 1765
genesis 1766 union {
genesis 1767 int32_t nBits;
genesis 1768 char cBits[4];
genesis 1769 } uBits;
genesis 1770 uBits.nBits = htonl((int32_t)pblock->nBits);
genesis 1771 result.push_back(Pair("bits", HexStr(BEGIN(uBits.cBits), END(uBits.cBits))));
genesis 1772
genesis 1773 return result;
genesis 1774 }
genesis 1775 else
genesis 1776 {
genesis 1777 // Parse parameters
genesis 1778 CDataStream ssBlock(ParseHex(params[0].get_str()));
genesis 1779 CBlock pblock;
genesis 1780 ssBlock >> pblock;
genesis 1781
genesis 1782 return ProcessBlock(NULL, &pblock);
genesis 1783 }
genesis 1784 }
genesis 1785
genesis 1786
asciilifeform_and... 1787 Value dumpblock(const Array& params, bool fHelp)
asciilifeform_and... 1788 {
mod6_fix_dumpbloc... 1789 if (fHelp || params.size() != 2)
asciilifeform_and... 1790 throw runtime_error(
asciilifeform_and... 1791 "dumpblock <height> <filename>\n"
asciilifeform_and... 1792 "Emit the block at <height> to <filename>.");
asciilifeform_and... 1793
asciilifeform_and... 1794 int want_height = 0;
asciilifeform_and... 1795 if (params.size() > 0)
asciilifeform_and... 1796 want_height = params[0].get_int();
asciilifeform_and... 1797
asciilifeform_and... 1798 if (want_height > nBestHeight)
asciilifeform_and... 1799 throw runtime_error("Requested block exceeds current nBestHeight!\n");
asciilifeform_and... 1800
asciilifeform_and... 1801 // path to dump block to
asciilifeform_and... 1802 string filename = params[1].get_str();
asciilifeform_and... 1803
asciilifeform_and... 1804 // this is O(n^2)...
asciilifeform_and... 1805 // possibly could be improved if we descend from best height if requested height is closer to it
asciilifeform_and... 1806 for (map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.begin(); mi != mapBlockIndex.end(); ++mi)
asciilifeform_and... 1807 {
asciilifeform_and... 1808 CBlockIndex *pindex = (*mi).second;
asciilifeform_and... 1809 if (pindex->nHeight == want_height) {
asciilifeform_and... 1810 CBlock block;
asciilifeform_and... 1811 block.ReadFromDisk(pindex);
asciilifeform_and... 1812 printf("Dumping block %d to %s\n", want_height, filename.c_str());
asciilifeform_and... 1813 CAutoFile fileout = fopen(filename.c_str(), "wb+");
asciilifeform_and... 1814 fileout << block;
asciilifeform_and... 1815 return true;
asciilifeform_and... 1816 }
asciilifeform_and... 1817 }
asciilifeform_and... 1818 return false;
asciilifeform_and... 1819 }
genesis 1820
genesis 1821
asciilifeform_and... 1822 Value eatblock(const Array& params, bool fHelp)
asciilifeform_and... 1823 {
asciilifeform_and... 1824 if (fHelp || params.size() < 1 || params.size() > 1)
asciilifeform_and... 1825 throw runtime_error(
asciilifeform_and... 1826 "eatblock <filename>\n"
asciilifeform_and... 1827 "Load a candidate for the next block directly from <filename>.");
asciilifeform_and... 1828
asciilifeform_and... 1829 if (!fCanEat)
asciilifeform_and... 1830 throw runtime_error(
asciilifeform_and... 1831 "'eatblock' is only permitted if bitcoind was started with -caneat flag!");
asciilifeform_and... 1832
asciilifeform_and... 1833 // path to load block from
asciilifeform_and... 1834 string filename = params[0].get_str();
asciilifeform_and... 1835
asciilifeform_and... 1836 printf("Attempting to create block #%d from file %s\n", nBestHeight + 1, filename.c_str());
asciilifeform_and... 1837 CAutoFile filein = fopen(filename.c_str(), "rb");
asciilifeform_and... 1838 CBlock block;
asciilifeform_and... 1839 filein >> block;
asciilifeform_and... 1840 return ProcessBlock(NULL, &block); // note that 'true' even if it was rejected (bastard, etc)
asciilifeform_and... 1841 } // ... but will return 'false' if we already have the block.
asciilifeform_and... 1842
asciilifeform_and... 1843
mod6_privkey_tools 1844 Value importprivkey(const Array& params, bool fHelp)
mod6_privkey_tools 1845 {
mod6_privkey_tools 1846 if (fHelp || params.size() < 1 || params.size() > 2)
mod6_privkey_tools 1847 throw runtime_error(
mod6_privkey_tools 1848 "importprivkey <bitcoinprivkey> [label]\n"
mod6_privkey_tools 1849 "Adds a private key (as returned by dumpprivkey) to your wallet.");
mod6_privkey_tools 1850
mod6_privkey_tools 1851 string strSecret = params[0].get_str();
mod6_privkey_tools 1852 string strLabel = "";
mod6_privkey_tools 1853 if (params.size() > 1)
mod6_privkey_tools 1854 strLabel = params[1].get_str();
mod6_privkey_tools 1855 CBitcoinSecret vchSecret;
mod6_privkey_tools 1856 bool fGood = vchSecret.SetString(strSecret);
mod6_privkey_tools 1857
mod6_privkey_tools 1858 if (!fGood) throw JSONRPCError(-5,"Invalid private key");
mod6_privkey_tools 1859
mod6_privkey_tools 1860 CKey key;
mod6_privkey_tools 1861 CSecret secret = vchSecret.GetSecret();
mod6_privkey_tools 1862 key.SetSecret(secret);
mod6_privkey_tools 1863 CBitcoinAddress vchAddress = CBitcoinAddress(key.GetPubKey());
mod6_privkey_tools 1864
mod6_privkey_tools 1865 CRITICAL_BLOCK(cs_main)
mod6_privkey_tools 1866 CRITICAL_BLOCK(pwalletMain->cs_wallet)
mod6_privkey_tools 1867 {
mod6_privkey_tools 1868 pwalletMain->MarkDirty();
mod6_privkey_tools 1869 pwalletMain->SetAddressBookName(vchAddress, strLabel);
mod6_privkey_tools 1870
mod6_privkey_tools 1871 if (!pwalletMain->AddKey(key))
mod6_privkey_tools 1872 throw JSONRPCError(-4,"Error adding key to wallet");
mod6_privkey_tools 1873
mod6_privkey_tools 1874 pwalletMain->ScanForWalletTransactions(pindexGenesisBlock, true);
mod6_privkey_tools 1875 pwalletMain->ReacceptWalletTransactions();
mod6_privkey_tools 1876 }
mod6_privkey_tools 1877
mod6_privkey_tools 1878 return Value::null;
mod6_privkey_tools 1879 }
mod6_privkey_tools 1880
mod6_privkey_tools 1881 Value dumpprivkey(const Array& params, bool fHelp)
mod6_privkey_tools 1882 {
mod6_privkey_tools 1883 if (fHelp || params.size() != 1)
mod6_privkey_tools 1884 throw runtime_error(
mod6_privkey_tools 1885 "dumpprivkey <bitcoinaddress>\n"
mod6_privkey_tools 1886 "Reveals the private key corresponding to <bitcoinaddress>.");
mod6_privkey_tools 1887
mod6_privkey_tools 1888 string strAddress = params[0].get_str();
mod6_privkey_tools 1889 CBitcoinAddress address;
mod6_privkey_tools 1890 if (!address.SetString(strAddress))
mod6_privkey_tools 1891 throw JSONRPCError(-5, "Invalid bitcoin address");
mod6_privkey_tools 1892 CSecret vchSecret;
mod6_privkey_tools 1893 if (!pwalletMain->GetSecret(address, vchSecret))
mod6_privkey_tools 1894 throw JSONRPCError(-4,"Private key for address " + strAddress + " is not known");
mod6_privkey_tools 1895 return CBitcoinSecret(vchSecret).ToString();
mod6_privkey_tools 1896 }
mod6_privkey_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),
mod6_privkey_tools 1947 make_pair("importprivkey", &importprivkey),
mod6_privkey_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