File indexing completed on 2020-06-25 15:50:33
0001
0002
0003
0004
0005
0006 #include "headers.h"
0007 #include "db.h"
0008 #include "net.h"
0009 #include "init.h"
0010 #undef printf
0011 #include <boost/asio.hpp>
0012 #include <boost/iostreams/concepts.hpp>
0013 #include <boost/iostreams/stream.hpp>
0014 #include <boost/algorithm/string.hpp>
0015 #include "json/json_spirit_reader_template.h"
0016 #include "json/json_spirit_writer_template.h"
0017 #include "json/json_spirit_utils.h"
0018 #define printf OutputDebugStringF
0019
0020
0021
0022
0023
0024 using namespace std;
0025 using namespace boost;
0026 using namespace boost::asio;
0027 using namespace json_spirit;
0028
0029 void ThreadRPCServer2(void* parg);
0030 typedef Value(*rpcfn_type)(const Array& params, bool fHelp);
0031 extern map<string, rpcfn_type> mapCallTable;
0032
0033 static std::string strRPCUserColonPass;
0034
0035 static int64 nWalletUnlockTime;
0036 static CCriticalSection cs_nWalletUnlockTime;
0037
0038
0039 Object JSONRPCError(int code, const string& message)
0040 {
0041 Object error;
0042 error.push_back(Pair("code", code));
0043 error.push_back(Pair("message", message));
0044 return error;
0045 }
0046
0047
0048 void PrintConsole(const std::string &format, ...)
0049 {
0050 char buffer[50000];
0051 int limit = sizeof(buffer);
0052 va_list arg_ptr;
0053 va_start(arg_ptr, format);
0054 int ret = _vsnprintf(buffer, limit, format.c_str(), arg_ptr);
0055 va_end(arg_ptr);
0056 if (ret < 0 || ret >= limit)
0057 {
0058 ret = limit - 1;
0059 buffer[limit-1] = 0;
0060 }
0061 printf("%s", buffer);
0062 fprintf(stdout, "%s", buffer);
0063 }
0064
0065
0066 int64 AmountFromValue(const Value& value)
0067 {
0068 double dAmount = value.get_real();
0069 if (dAmount <= 0.0 || dAmount > 21000000.0)
0070 throw JSONRPCError(-3, "Invalid amount");
0071 int64 nAmount = roundint64(dAmount * COIN);
0072 if (!MoneyRange(nAmount))
0073 throw JSONRPCError(-3, "Invalid amount");
0074 return nAmount;
0075 }
0076
0077 Value ValueFromAmount(int64 amount)
0078 {
0079 return (double)amount / (double)COIN;
0080 }
0081
0082 void WalletTxToJSON(const CWalletTx& wtx, Object& entry)
0083 {
0084 entry.push_back(Pair("confirmations", wtx.GetDepthInMainChain()));
0085 entry.push_back(Pair("txid", wtx.GetHash().GetHex()));
0086 entry.push_back(Pair("time", (boost::int64_t)wtx.GetTxTime()));
0087 BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue)
0088 entry.push_back(Pair(item.first, item.second));
0089 }
0090
0091 string AccountFromValue(const Value& value)
0092 {
0093 string strAccount = value.get_str();
0094 if (strAccount == "*")
0095 throw JSONRPCError(-11, "Invalid account name");
0096 return strAccount;
0097 }
0098
0099
0100
0101
0102
0103
0104
0105
0106 Value help(const Array& params, bool fHelp)
0107 {
0108 if (fHelp || params.size() > 1)
0109 throw runtime_error(
0110 "help [command]\n"
0111 "List commands, or get help for a command.");
0112
0113 string strCommand;
0114 if (params.size() > 0)
0115 strCommand = params[0].get_str();
0116
0117 string strRet;
0118 set<rpcfn_type> setDone;
0119 for (map<string, rpcfn_type>::iterator mi = mapCallTable.begin(); mi != mapCallTable.end(); ++mi)
0120 {
0121 string strMethod = (*mi).first;
0122
0123 if (strMethod == "getamountreceived" ||
0124 strMethod == "getallreceived" ||
0125 strMethod == "getblocknumber" ||
0126 (strMethod.find("label") != string::npos))
0127 continue;
0128 if (strCommand != "" && strMethod != strCommand)
0129 continue;
0130 try
0131 {
0132 Array params;
0133 rpcfn_type pfn = (*mi).second;
0134 if (setDone.insert(pfn).second)
0135 (*pfn)(params, true);
0136 }
0137 catch (std::exception& e)
0138 {
0139
0140 string strHelp = string(e.what());
0141 if (strCommand == "")
0142 if (strHelp.find('\n') != -1)
0143 strHelp = strHelp.substr(0, strHelp.find('\n'));
0144 strRet += strHelp + "\n";
0145 }
0146 }
0147 if (strRet == "")
0148 strRet = strprintf("help: unknown command: %s\n", strCommand.c_str());
0149 strRet = strRet.substr(0,strRet.size()-1);
0150 return strRet;
0151 }
0152
0153
0154 Value stop(const Array& params, bool fHelp)
0155 {
0156 if (fHelp || params.size() != 0)
0157 throw runtime_error(
0158 "stop\n"
0159 "Stop bitcoin server.");
0160
0161 CreateThread(Shutdown, NULL);
0162 return "bitcoin server stopping";
0163 }
0164
0165
0166 Value getblockcount(const Array& params, bool fHelp)
0167 {
0168 if (fHelp || params.size() != 0)
0169 throw runtime_error(
0170 "getblockcount\n"
0171 "Returns the number of blocks in the longest block chain.");
0172
0173 return nBestHeight;
0174 }
0175
0176
0177
0178 Value getblocknumber(const Array& params, bool fHelp)
0179 {
0180 if (fHelp || params.size() != 0)
0181 throw runtime_error(
0182 "getblocknumber\n"
0183 "Deprecated. Use getblockcount.");
0184
0185 return nBestHeight;
0186 }
0187
0188
0189 Value getconnectioncount(const Array& params, bool fHelp)
0190 {
0191 if (fHelp || params.size() != 0)
0192 throw runtime_error(
0193 "getconnectioncount\n"
0194 "Returns the number of connections to other nodes.");
0195
0196 return (int)vNodes.size();
0197 }
0198
0199
0200 double GetDifficulty()
0201 {
0202
0203
0204
0205 if (pindexBest == NULL)
0206 return 1.0;
0207 int nShift = (pindexBest->nBits >> 24) & 0xff;
0208
0209 double dDiff =
0210 (double)0x0000ffff / (double)(pindexBest->nBits & 0x00ffffff);
0211
0212 while (nShift < 29)
0213 {
0214 dDiff *= 256.0;
0215 nShift++;
0216 }
0217 while (nShift > 29)
0218 {
0219 dDiff /= 256.0;
0220 nShift--;
0221 }
0222
0223 return dDiff;
0224 }
0225
0226 Value getdifficulty(const Array& params, bool fHelp)
0227 {
0228 if (fHelp || params.size() != 0)
0229 throw runtime_error(
0230 "getdifficulty\n"
0231 "Returns the proof-of-work difficulty as a multiple of the minimum difficulty.");
0232
0233 return GetDifficulty();
0234 }
0235
0236
0237 Value getgenerate(const Array& params, bool fHelp)
0238 {
0239 if (fHelp || params.size() != 0)
0240 throw runtime_error(
0241 "getgenerate\n"
0242 "Returns true or false.");
0243
0244 return (bool)fGenerateBitcoins;
0245 }
0246
0247
0248 Value setgenerate(const Array& params, bool fHelp)
0249 {
0250 if (fHelp || params.size() < 1 || params.size() > 2)
0251 throw runtime_error(
0252 "setgenerate <generate> [genproclimit]\n"
0253 "<generate> is true or false to turn generation on or off.\n"
0254 "Generation is limited to [genproclimit] processors, -1 is unlimited.");
0255
0256 bool fGenerate = true;
0257 if (params.size() > 0)
0258 fGenerate = params[0].get_bool();
0259
0260 if (params.size() > 1)
0261 {
0262 int nGenProcLimit = params[1].get_int();
0263 fLimitProcessors = (nGenProcLimit != -1);
0264 WriteSetting("fLimitProcessors", fLimitProcessors);
0265 if (nGenProcLimit != -1)
0266 WriteSetting("nLimitProcessors", nLimitProcessors = nGenProcLimit);
0267 if (nGenProcLimit == 0)
0268 fGenerate = false;
0269 }
0270
0271 GenerateBitcoins(fGenerate, pwalletMain);
0272 return Value::null;
0273 }
0274
0275
0276 Value gethashespersec(const Array& params, bool fHelp)
0277 {
0278 if (fHelp || params.size() != 0)
0279 throw runtime_error(
0280 "gethashespersec\n"
0281 "Returns a recent hashes per second performance measurement while generating.");
0282
0283 if (GetTimeMillis() - nHPSTimerStart > 8000)
0284 return (boost::int64_t)0;
0285 return (boost::int64_t)dHashesPerSec;
0286 }
0287
0288
0289 Value getinfo(const Array& params, bool fHelp)
0290 {
0291 if (fHelp || params.size() != 0)
0292 throw runtime_error(
0293 "getinfo\n"
0294 "Returns an object containing various state info.");
0295
0296 Object obj;
0297 obj.push_back(Pair("version", (int)VERSION));
0298 obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance())));
0299 obj.push_back(Pair("blocks", (int)nBestHeight));
0300 obj.push_back(Pair("connections", (int)vNodes.size()));
0301 obj.push_back(Pair("proxy", (fUseProxy ? addrProxy.ToStringIPPort() : string())));
0302 obj.push_back(Pair("generate", (bool)fGenerateBitcoins));
0303 obj.push_back(Pair("genproclimit", (int)(fLimitProcessors ? nLimitProcessors : -1)));
0304 obj.push_back(Pair("difficulty", (double)GetDifficulty()));
0305 obj.push_back(Pair("hashespersec", gethashespersec(params, false)));
0306 obj.push_back(Pair("keypoololdest", (boost::int64_t)pwalletMain->GetOldestKeyPoolTime()));
0307 obj.push_back(Pair("keypoolsize", pwalletMain->GetKeyPoolSize()));
0308 obj.push_back(Pair("paytxfee", ValueFromAmount(nTransactionFee)));
0309 if (pwalletMain->IsCrypted())
0310 obj.push_back(Pair("unlocked_until", (boost::int64_t)nWalletUnlockTime / 1000));
0311 obj.push_back(Pair("errors", GetWarnings("statusbar")));
0312 return obj;
0313 }
0314
0315
0316 Value getnewaddress(const Array& params, bool fHelp)
0317 {
0318 if (fHelp || params.size() > 1)
0319 throw runtime_error(
0320 "getnewaddress [account]\n"
0321 "Returns a new bitcoin address for receiving payments. "
0322 "If [account] is specified (recommended), it is added to the address book "
0323 "so payments received with the address will be credited to [account].");
0324
0325
0326 string strAccount;
0327 if (params.size() > 0)
0328 strAccount = AccountFromValue(params[0]);
0329
0330 if (!pwalletMain->IsLocked())
0331 pwalletMain->TopUpKeyPool();
0332
0333
0334 std::vector<unsigned char> newKey;
0335 if (!pwalletMain->GetKeyFromPool(newKey, false))
0336 throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
0337 CBitcoinAddress address(newKey);
0338
0339 pwalletMain->SetAddressBookName(address, strAccount);
0340
0341 return address.ToString();
0342 }
0343
0344
0345 CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false)
0346 {
0347 CWalletDB walletdb(pwalletMain->strWalletFile);
0348
0349 CAccount account;
0350 walletdb.ReadAccount(strAccount, account);
0351
0352 bool bKeyUsed = false;
0353
0354
0355 if (!account.vchPubKey.empty())
0356 {
0357 CScript scriptPubKey;
0358 scriptPubKey.SetBitcoinAddress(account.vchPubKey);
0359 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
0360 it != pwalletMain->mapWallet.end() && !account.vchPubKey.empty();
0361 ++it)
0362 {
0363 const CWalletTx& wtx = (*it).second;
0364 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
0365 if (txout.scriptPubKey == scriptPubKey)
0366 bKeyUsed = true;
0367 }
0368 }
0369
0370
0371 if (account.vchPubKey.empty() || bForceNew || bKeyUsed)
0372 {
0373 if (!pwalletMain->GetKeyFromPool(account.vchPubKey, false))
0374 throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
0375
0376 pwalletMain->SetAddressBookName(CBitcoinAddress(account.vchPubKey), strAccount);
0377 walletdb.WriteAccount(strAccount, account);
0378 }
0379
0380 return CBitcoinAddress(account.vchPubKey);
0381 }
0382
0383 Value getaccountaddress(const Array& params, bool fHelp)
0384 {
0385 if (fHelp || params.size() != 1)
0386 throw runtime_error(
0387 "getaccountaddress <account>\n"
0388 "Returns the current bitcoin address for receiving payments to this account.");
0389
0390
0391 string strAccount = AccountFromValue(params[0]);
0392
0393 Value ret;
0394
0395 ret = GetAccountAddress(strAccount).ToString();
0396
0397 return ret;
0398 }
0399
0400
0401
0402 Value setaccount(const Array& params, bool fHelp)
0403 {
0404 if (fHelp || params.size() < 1 || params.size() > 2)
0405 throw runtime_error(
0406 "setaccount <bitcoinaddress> <account>\n"
0407 "Sets the account associated with the given address.");
0408
0409 CBitcoinAddress address(params[0].get_str());
0410 if (!address.IsValid())
0411 throw JSONRPCError(-5, "Invalid bitcoin address");
0412
0413
0414 string strAccount;
0415 if (params.size() > 1)
0416 strAccount = AccountFromValue(params[1]);
0417
0418
0419 if (pwalletMain->mapAddressBook.count(address))
0420 {
0421 string strOldAccount = pwalletMain->mapAddressBook[address];
0422 if (address == GetAccountAddress(strOldAccount))
0423 GetAccountAddress(strOldAccount, true);
0424 }
0425
0426 pwalletMain->SetAddressBookName(address, strAccount);
0427
0428 return Value::null;
0429 }
0430
0431
0432 Value getaccount(const Array& params, bool fHelp)
0433 {
0434 if (fHelp || params.size() != 1)
0435 throw runtime_error(
0436 "getaccount <bitcoinaddress>\n"
0437 "Returns the account associated with the given address.");
0438
0439 CBitcoinAddress address(params[0].get_str());
0440 if (!address.IsValid())
0441 throw JSONRPCError(-5, "Invalid bitcoin address");
0442
0443 string strAccount;
0444 map<CBitcoinAddress, string>::iterator mi = pwalletMain->mapAddressBook.find(address);
0445 if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.empty())
0446 strAccount = (*mi).second;
0447 return strAccount;
0448 }
0449
0450
0451 Value getaddressesbyaccount(const Array& params, bool fHelp)
0452 {
0453 if (fHelp || params.size() != 1)
0454 throw runtime_error(
0455 "getaddressesbyaccount <account>\n"
0456 "Returns the list of addresses for the given account.");
0457
0458 string strAccount = AccountFromValue(params[0]);
0459
0460
0461 Array ret;
0462 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
0463 {
0464 const CBitcoinAddress& address = item.first;
0465 const string& strName = item.second;
0466 if (strName == strAccount)
0467 ret.push_back(address.ToString());
0468 }
0469 return ret;
0470 }
0471
0472 Value settxfee(const Array& params, bool fHelp)
0473 {
0474 if (fHelp || params.size() < 1 || params.size() > 1)
0475 throw runtime_error(
0476 "settxfee <amount>\n"
0477 "<amount> is a real and is rounded to the nearest 0.00000001");
0478
0479
0480 int64 nAmount = 0;
0481 if (params[0].get_real() != 0.0)
0482 nAmount = AmountFromValue(params[0]);
0483
0484 nTransactionFee = nAmount;
0485 return true;
0486 }
0487
0488 Value sendtoaddress(const Array& params, bool fHelp)
0489 {
0490 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
0491 throw runtime_error(
0492 "sendtoaddress <bitcoinaddress> <amount> [comment] [comment-to]\n"
0493 "<amount> is a real and is rounded to the nearest 0.00000001\n"
0494 "requires wallet passphrase to be set with walletpassphrase first");
0495 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
0496 throw runtime_error(
0497 "sendtoaddress <bitcoinaddress> <amount> [comment] [comment-to]\n"
0498 "<amount> is a real and is rounded to the nearest 0.00000001");
0499
0500 CBitcoinAddress address(params[0].get_str());
0501 if (!address.IsValid())
0502 throw JSONRPCError(-5, "Invalid bitcoin address");
0503
0504
0505 int64 nAmount = AmountFromValue(params[1]);
0506
0507
0508 CWalletTx wtx;
0509 if (params.size() > 2 && params[2].type() != null_type && !params[2].get_str().empty())
0510 wtx.mapValue["comment"] = params[2].get_str();
0511 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
0512 wtx.mapValue["to"] = params[3].get_str();
0513
0514 if (pwalletMain->IsLocked())
0515 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
0516
0517 string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
0518 if (strError != "")
0519 throw JSONRPCError(-4, strError);
0520
0521 return wtx.GetHash().GetHex();
0522 }
0523
0524 static const string strMessageMagic = "Bitcoin Signed Message:\n";
0525
0526 Value signmessage(const Array& params, bool fHelp)
0527 {
0528 if (fHelp || params.size() != 2)
0529 throw runtime_error(
0530 "signmessage <bitcoinaddress> <message>\n"
0531 "Sign a message with the private key of an address");
0532
0533 if (pwalletMain->IsLocked())
0534 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
0535
0536 string strAddress = params[0].get_str();
0537 string strMessage = params[1].get_str();
0538
0539 CBitcoinAddress addr(strAddress);
0540 if (!addr.IsValid())
0541 throw JSONRPCError(-3, "Invalid address");
0542
0543 CKey key;
0544 if (!pwalletMain->GetKey(addr, key))
0545 throw JSONRPCError(-4, "Private key not available");
0546
0547 CDataStream ss(SER_GETHASH);
0548 ss << strMessageMagic;
0549 ss << strMessage;
0550
0551 vector<unsigned char> vchSig;
0552 if (!key.SignCompact(Hash(ss.begin(), ss.end()), vchSig))
0553 throw JSONRPCError(-5, "Sign failed");
0554
0555 return EncodeBase64(&vchSig[0], vchSig.size());
0556 }
0557
0558 Value verifymessage(const Array& params, bool fHelp)
0559 {
0560 if (fHelp || params.size() != 3)
0561 throw runtime_error(
0562 "verifymessage <bitcoinaddress> <signature> <message>\n"
0563 "Verify a signed message");
0564
0565 string strAddress = params[0].get_str();
0566 string strSign = params[1].get_str();
0567 string strMessage = params[2].get_str();
0568
0569 CBitcoinAddress addr(strAddress);
0570 if (!addr.IsValid())
0571 throw JSONRPCError(-3, "Invalid address");
0572
0573 bool fInvalid = false;
0574 vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid);
0575
0576 if (fInvalid)
0577 throw JSONRPCError(-5, "Malformed base64 encoding");
0578
0579 CDataStream ss(SER_GETHASH);
0580 ss << strMessageMagic;
0581 ss << strMessage;
0582
0583 CKey key;
0584 if (!key.SetCompactSignature(Hash(ss.begin(), ss.end()), vchSig))
0585 return false;
0586
0587 return (key.GetAddress() == addr);
0588 }
0589
0590
0591 Value getreceivedbyaddress(const Array& params, bool fHelp)
0592 {
0593 if (fHelp || params.size() < 1 || params.size() > 2)
0594 throw runtime_error(
0595 "getreceivedbyaddress <bitcoinaddress> [minconf=1]\n"
0596 "Returns the total amount received by <bitcoinaddress> in transactions with at least [minconf] confirmations.");
0597
0598
0599 CBitcoinAddress address = CBitcoinAddress(params[0].get_str());
0600 CScript scriptPubKey;
0601 if (!address.IsValid())
0602 throw JSONRPCError(-5, "Invalid bitcoin address");
0603 scriptPubKey.SetBitcoinAddress(address);
0604 if (!IsMine(*pwalletMain,scriptPubKey))
0605 return (double)0.0;
0606
0607
0608 int nMinDepth = 1;
0609 if (params.size() > 1)
0610 nMinDepth = params[1].get_int();
0611
0612
0613 int64 nAmount = 0;
0614 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
0615 {
0616 const CWalletTx& wtx = (*it).second;
0617 if (wtx.IsCoinBase() || !wtx.IsFinal())
0618 continue;
0619
0620 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
0621 if (txout.scriptPubKey == scriptPubKey)
0622 if (wtx.GetDepthInMainChain() >= nMinDepth)
0623 nAmount += txout.nValue;
0624 }
0625
0626 return ValueFromAmount(nAmount);
0627 }
0628
0629
0630 void GetAccountAddresses(string strAccount, set<CBitcoinAddress>& setAddress)
0631 {
0632 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
0633 {
0634 const CBitcoinAddress& address = item.first;
0635 const string& strName = item.second;
0636 if (strName == strAccount)
0637 setAddress.insert(address);
0638 }
0639 }
0640
0641
0642 Value getreceivedbyaccount(const Array& params, bool fHelp)
0643 {
0644 if (fHelp || params.size() < 1 || params.size() > 2)
0645 throw runtime_error(
0646 "getreceivedbyaccount <account> [minconf=1]\n"
0647 "Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.");
0648
0649
0650 int nMinDepth = 1;
0651 if (params.size() > 1)
0652 nMinDepth = params[1].get_int();
0653
0654
0655 string strAccount = AccountFromValue(params[0]);
0656 set<CBitcoinAddress> setAddress;
0657 GetAccountAddresses(strAccount, setAddress);
0658
0659
0660 int64 nAmount = 0;
0661 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
0662 {
0663 const CWalletTx& wtx = (*it).second;
0664 if (wtx.IsCoinBase() || !wtx.IsFinal())
0665 continue;
0666
0667 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
0668 {
0669 CBitcoinAddress address;
0670 if (ExtractAddress(txout.scriptPubKey, pwalletMain, address) && setAddress.count(address))
0671 if (wtx.GetDepthInMainChain() >= nMinDepth)
0672 nAmount += txout.nValue;
0673 }
0674 }
0675
0676 return (double)nAmount / (double)COIN;
0677 }
0678
0679
0680 int64 GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth)
0681 {
0682 int64 nBalance = 0;
0683
0684
0685 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
0686 {
0687 const CWalletTx& wtx = (*it).second;
0688 if (!wtx.IsFinal())
0689 continue;
0690
0691 int64 nGenerated, nReceived, nSent, nFee;
0692 wtx.GetAccountAmounts(strAccount, nGenerated, nReceived, nSent, nFee);
0693
0694 if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
0695 nBalance += nReceived;
0696 nBalance += nGenerated - nSent - nFee;
0697 }
0698
0699
0700 nBalance += walletdb.GetAccountCreditDebit(strAccount);
0701
0702 return nBalance;
0703 }
0704
0705 int64 GetAccountBalance(const string& strAccount, int nMinDepth)
0706 {
0707 CWalletDB walletdb(pwalletMain->strWalletFile);
0708 return GetAccountBalance(walletdb, strAccount, nMinDepth);
0709 }
0710
0711
0712 Value getbalance(const Array& params, bool fHelp)
0713 {
0714 if (fHelp || params.size() > 2)
0715 throw runtime_error(
0716 "getbalance [account] [minconf=1]\n"
0717 "If [account] is not specified, returns the server's total available balance.\n"
0718 "If [account] is specified, returns the balance in the account.");
0719
0720 if (params.size() == 0)
0721 return ValueFromAmount(pwalletMain->GetBalance());
0722
0723 int nMinDepth = 1;
0724 if (params.size() > 1)
0725 nMinDepth = params[1].get_int();
0726
0727 if (params[0].get_str() == "*") {
0728
0729
0730
0731 int64 nBalance = 0;
0732 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
0733 {
0734 const CWalletTx& wtx = (*it).second;
0735 if (!wtx.IsFinal())
0736 continue;
0737
0738 int64 allGeneratedImmature, allGeneratedMature, allFee;
0739 allGeneratedImmature = allGeneratedMature = allFee = 0;
0740 string strSentAccount;
0741 list<pair<CBitcoinAddress, int64> > listReceived;
0742 list<pair<CBitcoinAddress, int64> > listSent;
0743 wtx.GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount);
0744 if (wtx.GetDepthInMainChain() >= nMinDepth)
0745 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listReceived)
0746 nBalance += r.second;
0747 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listSent)
0748 nBalance -= r.second;
0749 nBalance -= allFee;
0750 nBalance += allGeneratedMature;
0751 }
0752 return ValueFromAmount(nBalance);
0753 }
0754
0755 string strAccount = AccountFromValue(params[0]);
0756
0757 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
0758
0759 return ValueFromAmount(nBalance);
0760 }
0761
0762
0763 Value movecmd(const Array& params, bool fHelp)
0764 {
0765 if (fHelp || params.size() < 3 || params.size() > 5)
0766 throw runtime_error(
0767 "move <fromaccount> <toaccount> <amount> [minconf=1] [comment]\n"
0768 "Move from one account in your wallet to another.");
0769
0770 string strFrom = AccountFromValue(params[0]);
0771 string strTo = AccountFromValue(params[1]);
0772 int64 nAmount = AmountFromValue(params[2]);
0773 if (params.size() > 3)
0774
0775 (void)params[3].get_int();
0776 string strComment;
0777 if (params.size() > 4)
0778 strComment = params[4].get_str();
0779
0780 CWalletDB walletdb(pwalletMain->strWalletFile);
0781 walletdb.TxnBegin();
0782
0783 int64 nNow = GetAdjustedTime();
0784
0785
0786 CAccountingEntry debit;
0787 debit.strAccount = strFrom;
0788 debit.nCreditDebit = -nAmount;
0789 debit.nTime = nNow;
0790 debit.strOtherAccount = strTo;
0791 debit.strComment = strComment;
0792 walletdb.WriteAccountingEntry(debit);
0793
0794
0795 CAccountingEntry credit;
0796 credit.strAccount = strTo;
0797 credit.nCreditDebit = nAmount;
0798 credit.nTime = nNow;
0799 credit.strOtherAccount = strFrom;
0800 credit.strComment = strComment;
0801 walletdb.WriteAccountingEntry(credit);
0802
0803 walletdb.TxnCommit();
0804
0805 return true;
0806 }
0807
0808
0809 Value sendfrom(const Array& params, bool fHelp)
0810 {
0811 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
0812 throw runtime_error(
0813 "sendfrom <fromaccount> <tobitcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
0814 "<amount> is a real and is rounded to the nearest 0.00000001\n"
0815 "requires wallet passphrase to be set with walletpassphrase first");
0816 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
0817 throw runtime_error(
0818 "sendfrom <fromaccount> <tobitcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
0819 "<amount> is a real and is rounded to the nearest 0.00000001");
0820
0821 string strAccount = AccountFromValue(params[0]);
0822 CBitcoinAddress address(params[1].get_str());
0823 if (!address.IsValid())
0824 throw JSONRPCError(-5, "Invalid bitcoin address");
0825 int64 nAmount = AmountFromValue(params[2]);
0826 int nMinDepth = 1;
0827 if (params.size() > 3)
0828 nMinDepth = params[3].get_int();
0829
0830 CWalletTx wtx;
0831 wtx.strFromAccount = strAccount;
0832 if (params.size() > 4 && params[4].type() != null_type && !params[4].get_str().empty())
0833 wtx.mapValue["comment"] = params[4].get_str();
0834 if (params.size() > 5 && params[5].type() != null_type && !params[5].get_str().empty())
0835 wtx.mapValue["to"] = params[5].get_str();
0836
0837 if (pwalletMain->IsLocked())
0838 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
0839
0840
0841 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
0842 if (nAmount > nBalance)
0843 throw JSONRPCError(-6, "Account has insufficient funds");
0844
0845
0846 string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
0847 if (strError != "")
0848 throw JSONRPCError(-4, strError);
0849
0850 return wtx.GetHash().GetHex();
0851 }
0852
0853
0854 Value sendmany(const Array& params, bool fHelp)
0855 {
0856 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
0857 throw runtime_error(
0858 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
0859 "amounts are double-precision floating point numbers\n"
0860 "requires wallet passphrase to be set with walletpassphrase first");
0861 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
0862 throw runtime_error(
0863 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
0864 "amounts are double-precision floating point numbers");
0865
0866 string strAccount = AccountFromValue(params[0]);
0867 Object sendTo = params[1].get_obj();
0868 int nMinDepth = 1;
0869 if (params.size() > 2)
0870 nMinDepth = params[2].get_int();
0871
0872 CWalletTx wtx;
0873 wtx.strFromAccount = strAccount;
0874 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
0875 wtx.mapValue["comment"] = params[3].get_str();
0876
0877 set<CBitcoinAddress> setAddress;
0878 vector<pair<CScript, int64> > vecSend;
0879
0880 int64 totalAmount = 0;
0881 BOOST_FOREACH(const Pair& s, sendTo)
0882 {
0883 CBitcoinAddress address(s.name_);
0884 if (!address.IsValid())
0885 throw JSONRPCError(-5, string("Invalid bitcoin address:")+s.name_);
0886
0887 if (setAddress.count(address))
0888 throw JSONRPCError(-8, string("Invalid parameter, duplicated address: ")+s.name_);
0889 setAddress.insert(address);
0890
0891 CScript scriptPubKey;
0892 scriptPubKey.SetBitcoinAddress(address);
0893 int64 nAmount = AmountFromValue(s.value_);
0894 totalAmount += nAmount;
0895
0896 vecSend.push_back(make_pair(scriptPubKey, nAmount));
0897 }
0898
0899 if (pwalletMain->IsLocked())
0900 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
0901
0902
0903 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
0904 if (totalAmount > nBalance)
0905 throw JSONRPCError(-6, "Account has insufficient funds");
0906
0907
0908 CReserveKey keyChange(pwalletMain);
0909 int64 nFeeRequired = 0;
0910 bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired);
0911 if (!fCreated)
0912 {
0913 if (totalAmount + nFeeRequired > pwalletMain->GetBalance())
0914 throw JSONRPCError(-6, "Insufficient funds");
0915 throw JSONRPCError(-4, "Transaction creation failed");
0916 }
0917 if (!pwalletMain->CommitTransaction(wtx, keyChange))
0918 throw JSONRPCError(-4, "Transaction commit failed");
0919
0920 return wtx.GetHash().GetHex();
0921 }
0922
0923
0924 struct tallyitem
0925 {
0926 int64 nAmount;
0927 int nConf;
0928 tallyitem()
0929 {
0930 nAmount = 0;
0931 nConf = INT_MAX;
0932 }
0933 };
0934
0935 Value ListReceived(const Array& params, bool fByAccounts)
0936 {
0937
0938 int nMinDepth = 1;
0939 if (params.size() > 0)
0940 nMinDepth = params[0].get_int();
0941
0942
0943 bool fIncludeEmpty = false;
0944 if (params.size() > 1)
0945 fIncludeEmpty = params[1].get_bool();
0946
0947
0948 map<CBitcoinAddress, tallyitem> mapTally;
0949 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
0950 {
0951 const CWalletTx& wtx = (*it).second;
0952 if (wtx.IsCoinBase() || !wtx.IsFinal())
0953 continue;
0954
0955 int nDepth = wtx.GetDepthInMainChain();
0956 if (nDepth < nMinDepth)
0957 continue;
0958
0959 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
0960 {
0961 CBitcoinAddress address;
0962 if (!ExtractAddress(txout.scriptPubKey, pwalletMain, address) || !address.IsValid())
0963 continue;
0964
0965 tallyitem& item = mapTally[address];
0966 item.nAmount += txout.nValue;
0967 item.nConf = min(item.nConf, nDepth);
0968 }
0969 }
0970
0971
0972 Array ret;
0973 map<string, tallyitem> mapAccountTally;
0974 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
0975 {
0976 const CBitcoinAddress& address = item.first;
0977 const string& strAccount = item.second;
0978 map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
0979 if (it == mapTally.end() && !fIncludeEmpty)
0980 continue;
0981
0982 int64 nAmount = 0;
0983 int nConf = INT_MAX;
0984 if (it != mapTally.end())
0985 {
0986 nAmount = (*it).second.nAmount;
0987 nConf = (*it).second.nConf;
0988 }
0989
0990 if (fByAccounts)
0991 {
0992 tallyitem& item = mapAccountTally[strAccount];
0993 item.nAmount += nAmount;
0994 item.nConf = min(item.nConf, nConf);
0995 }
0996 else
0997 {
0998 Object obj;
0999 obj.push_back(Pair("address", address.ToString()));
1000 obj.push_back(Pair("account", strAccount));
1001 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1002 obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf)));
1003 ret.push_back(obj);
1004 }
1005 }
1006
1007 if (fByAccounts)
1008 {
1009 for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
1010 {
1011 int64 nAmount = (*it).second.nAmount;
1012 int nConf = (*it).second.nConf;
1013 Object obj;
1014 obj.push_back(Pair("account", (*it).first));
1015 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1016 obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf)));
1017 ret.push_back(obj);
1018 }
1019 }
1020
1021 return ret;
1022 }
1023
1024 Value listreceivedbyaddress(const Array& params, bool fHelp)
1025 {
1026 if (fHelp || params.size() > 2)
1027 throw runtime_error(
1028 "listreceivedbyaddress [minconf=1] [includeempty=false]\n"
1029 "[minconf] is the minimum number of confirmations before payments are included.\n"
1030 "[includeempty] whether to include addresses that haven't received any payments.\n"
1031 "Returns an array of objects containing:\n"
1032 " \"address\" : receiving address\n"
1033 " \"account\" : the account of the receiving address\n"
1034 " \"amount\" : total amount received by the address\n"
1035 " \"confirmations\" : number of confirmations of the most recent transaction included");
1036
1037 return ListReceived(params, false);
1038 }
1039
1040 Value listreceivedbyaccount(const Array& params, bool fHelp)
1041 {
1042 if (fHelp || params.size() > 2)
1043 throw runtime_error(
1044 "listreceivedbyaccount [minconf=1] [includeempty=false]\n"
1045 "[minconf] is the minimum number of confirmations before payments are included.\n"
1046 "[includeempty] whether to include accounts that haven't received any payments.\n"
1047 "Returns an array of objects containing:\n"
1048 " \"account\" : the account of the receiving addresses\n"
1049 " \"amount\" : total amount received by addresses with this account\n"
1050 " \"confirmations\" : number of confirmations of the most recent transaction included");
1051
1052 return ListReceived(params, true);
1053 }
1054
1055 void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret)
1056 {
1057 int64 nGeneratedImmature, nGeneratedMature, nFee;
1058 string strSentAccount;
1059 list<pair<CBitcoinAddress, int64> > listReceived;
1060 list<pair<CBitcoinAddress, int64> > listSent;
1061 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1062
1063 bool fAllAccounts = (strAccount == string("*"));
1064
1065
1066 if ((nGeneratedMature+nGeneratedImmature) != 0 && (fAllAccounts || strAccount == ""))
1067 {
1068 Object entry;
1069 entry.push_back(Pair("account", string("")));
1070 if (nGeneratedImmature)
1071 {
1072 entry.push_back(Pair("category", wtx.GetDepthInMainChain() ? "immature" : "orphan"));
1073 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedImmature)));
1074 }
1075 else
1076 {
1077 entry.push_back(Pair("category", "generate"));
1078 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedMature)));
1079 }
1080 if (fLong)
1081 WalletTxToJSON(wtx, entry);
1082 ret.push_back(entry);
1083 }
1084
1085
1086 if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
1087 {
1088 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1089 {
1090 Object entry;
1091 entry.push_back(Pair("account", strSentAccount));
1092 entry.push_back(Pair("address", s.first.ToString()));
1093 entry.push_back(Pair("category", "send"));
1094 entry.push_back(Pair("amount", ValueFromAmount(-s.second)));
1095 entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
1096 if (fLong)
1097 WalletTxToJSON(wtx, entry);
1098 ret.push_back(entry);
1099 }
1100 }
1101
1102
1103 if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
1104 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1105 {
1106 string account;
1107 if (pwalletMain->mapAddressBook.count(r.first))
1108 account = pwalletMain->mapAddressBook[r.first];
1109 if (fAllAccounts || (account == strAccount))
1110 {
1111 Object entry;
1112 entry.push_back(Pair("account", account));
1113 entry.push_back(Pair("address", r.first.ToString()));
1114 entry.push_back(Pair("category", "receive"));
1115 entry.push_back(Pair("amount", ValueFromAmount(r.second)));
1116 if (fLong)
1117 WalletTxToJSON(wtx, entry);
1118 ret.push_back(entry);
1119 }
1120 }
1121 }
1122
1123 void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret)
1124 {
1125 bool fAllAccounts = (strAccount == string("*"));
1126
1127 if (fAllAccounts || acentry.strAccount == strAccount)
1128 {
1129 Object entry;
1130 entry.push_back(Pair("account", acentry.strAccount));
1131 entry.push_back(Pair("category", "move"));
1132 entry.push_back(Pair("time", (boost::int64_t)acentry.nTime));
1133 entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
1134 entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
1135 entry.push_back(Pair("comment", acentry.strComment));
1136 ret.push_back(entry);
1137 }
1138 }
1139
1140 Value listtransactions(const Array& params, bool fHelp)
1141 {
1142 if (fHelp || params.size() > 3)
1143 throw runtime_error(
1144 "listtransactions [account] [count=10] [from=0]\n"
1145 "Returns up to [count] most recent transactions skipping the first [from] transactions for account [account].");
1146
1147 string strAccount = "*";
1148 if (params.size() > 0)
1149 strAccount = params[0].get_str();
1150 int nCount = 10;
1151 if (params.size() > 1)
1152 nCount = params[1].get_int();
1153 int nFrom = 0;
1154 if (params.size() > 2)
1155 nFrom = params[2].get_int();
1156
1157 Array ret;
1158 CWalletDB walletdb(pwalletMain->strWalletFile);
1159
1160
1161 typedef pair<CWalletTx*, CAccountingEntry*> TxPair;
1162 typedef multimap<int64, TxPair > TxItems;
1163 TxItems txByTime;
1164
1165 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1166 {
1167 CWalletTx* wtx = &((*it).second);
1168 txByTime.insert(make_pair(wtx->GetTxTime(), TxPair(wtx, (CAccountingEntry*)0)));
1169 }
1170 list<CAccountingEntry> acentries;
1171 walletdb.ListAccountCreditDebit(strAccount, acentries);
1172 BOOST_FOREACH(CAccountingEntry& entry, acentries)
1173 {
1174 txByTime.insert(make_pair(entry.nTime, TxPair((CWalletTx*)0, &entry)));
1175 }
1176
1177
1178 TxItems::reverse_iterator it = txByTime.rbegin();
1179 if (txByTime.size() > nFrom) std::advance(it, nFrom);
1180 for (; it != txByTime.rend(); ++it)
1181 {
1182 CWalletTx *const pwtx = (*it).second.first;
1183 if (pwtx != 0)
1184 ListTransactions(*pwtx, strAccount, 0, true, ret);
1185 CAccountingEntry *const pacentry = (*it).second.second;
1186 if (pacentry != 0)
1187 AcentryToJSON(*pacentry, strAccount, ret);
1188
1189 if (ret.size() >= nCount) break;
1190 }
1191
1192
1193
1194 if (ret.size() > nCount)
1195 {
1196 Array::iterator last = ret.begin();
1197 std::advance(last, nCount);
1198 ret.erase(last, ret.end());
1199 }
1200 std::reverse(ret.begin(), ret.end());
1201
1202 return ret;
1203 }
1204
1205 Value listaccounts(const Array& params, bool fHelp)
1206 {
1207 if (fHelp || params.size() > 1)
1208 throw runtime_error(
1209 "listaccounts [minconf=1]\n"
1210 "Returns Object that has account names as keys, account balances as values.");
1211
1212 int nMinDepth = 1;
1213 if (params.size() > 0)
1214 nMinDepth = params[0].get_int();
1215
1216 map<string, int64> mapAccountBalances;
1217 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& entry, pwalletMain->mapAddressBook) {
1218 if (pwalletMain->HaveKey(entry.first))
1219 mapAccountBalances[entry.second] = 0;
1220 }
1221
1222 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1223 {
1224 const CWalletTx& wtx = (*it).second;
1225 int64 nGeneratedImmature, nGeneratedMature, nFee;
1226 string strSentAccount;
1227 list<pair<CBitcoinAddress, int64> > listReceived;
1228 list<pair<CBitcoinAddress, int64> > listSent;
1229 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1230 mapAccountBalances[strSentAccount] -= nFee;
1231 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1232 mapAccountBalances[strSentAccount] -= s.second;
1233 if (wtx.GetDepthInMainChain() >= nMinDepth)
1234 {
1235 mapAccountBalances[""] += nGeneratedMature;
1236 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1237 if (pwalletMain->mapAddressBook.count(r.first))
1238 mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second;
1239 else
1240 mapAccountBalances[""] += r.second;
1241 }
1242 }
1243
1244 list<CAccountingEntry> acentries;
1245 CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
1246 BOOST_FOREACH(const CAccountingEntry& entry, acentries)
1247 mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
1248
1249 Object ret;
1250 BOOST_FOREACH(const PAIRTYPE(string, int64)& accountBalance, mapAccountBalances) {
1251 ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
1252 }
1253 return ret;
1254 }
1255
1256 Value listsinceblock(const Array& params, bool fHelp)
1257 {
1258 if (fHelp)
1259 throw runtime_error(
1260 "listsinceblock [blockid] [target-confirmations]\n"
1261 "Get all transactions in blocks since block [blockid], or all transactions if omitted");
1262
1263 CBlockIndex *pindex = NULL;
1264 int target_confirms = 1;
1265
1266 if (params.size() > 0)
1267 {
1268 uint256 blockId = 0;
1269
1270 blockId.SetHex(params[0].get_str());
1271 pindex = CBlockLocator(blockId).GetBlockIndex();
1272 }
1273
1274 if (params.size() > 1)
1275 {
1276 target_confirms = params[1].get_int();
1277
1278 if (target_confirms < 1)
1279 throw JSONRPCError(-8, "Invalid parameter");
1280 }
1281
1282 int depth = pindex ? (1 + nBestHeight - pindex->nHeight) : -1;
1283
1284 Array transactions;
1285
1286 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++)
1287 {
1288 CWalletTx tx = (*it).second;
1289
1290 if (depth == -1 || tx.GetDepthInMainChain() < depth)
1291 ListTransactions(tx, "*", 0, true, transactions);
1292 }
1293
1294 uint256 lastblock;
1295
1296 if (target_confirms == 1)
1297 {
1298 printf("oops!\n");
1299 lastblock = hashBestChain;
1300 }
1301 else
1302 {
1303 int target_height = pindexBest->nHeight + 1 - target_confirms;
1304
1305 CBlockIndex *block;
1306 for (block = pindexBest;
1307 block && block->nHeight > target_height;
1308 block = block->pprev) { }
1309
1310 lastblock = block ? block->GetBlockHash() : 0;
1311 }
1312
1313 Object ret;
1314 ret.push_back(Pair("transactions", transactions));
1315 ret.push_back(Pair("lastblock", lastblock.GetHex()));
1316
1317 return ret;
1318 }
1319
1320 Value gettransaction(const Array& params, bool fHelp)
1321 {
1322 if (fHelp || params.size() != 1)
1323 throw runtime_error(
1324 "gettransaction <txid>\n"
1325 "Get detailed information about <txid>");
1326
1327 uint256 hash;
1328 hash.SetHex(params[0].get_str());
1329
1330 Object entry;
1331
1332 if (!pwalletMain->mapWallet.count(hash))
1333 throw JSONRPCError(-5, "Invalid or non-wallet transaction id");
1334 const CWalletTx& wtx = pwalletMain->mapWallet[hash];
1335
1336 int64 nCredit = wtx.GetCredit();
1337 int64 nDebit = wtx.GetDebit();
1338 int64 nNet = nCredit - nDebit;
1339 int64 nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0);
1340
1341 entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
1342 if (wtx.IsFromMe())
1343 entry.push_back(Pair("fee", ValueFromAmount(nFee)));
1344
1345 WalletTxToJSON(pwalletMain->mapWallet[hash], entry);
1346
1347 Array details;
1348 ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details);
1349 entry.push_back(Pair("details", details));
1350
1351 return entry;
1352 }
1353
1354
1355 Value backupwallet(const Array& params, bool fHelp)
1356 {
1357 if (fHelp || params.size() != 1)
1358 throw runtime_error(
1359 "backupwallet <destination>\n"
1360 "Safely copies wallet.dat to destination, which can be a directory or a path with filename.");
1361
1362 string strDest = params[0].get_str();
1363 BackupWallet(*pwalletMain, strDest);
1364
1365 return Value::null;
1366 }
1367
1368
1369 Value keypoolrefill(const Array& params, bool fHelp)
1370 {
1371 if (pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1372 throw runtime_error(
1373 "keypoolrefill\n"
1374 "Fills the keypool, requires wallet passphrase to be set.");
1375 if (!pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1376 throw runtime_error(
1377 "keypoolrefill\n"
1378 "Fills the keypool.");
1379
1380 if (pwalletMain->IsLocked())
1381 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
1382
1383 pwalletMain->TopUpKeyPool();
1384
1385 if (pwalletMain->GetKeyPoolSize() < GetArg("-keypool", 100))
1386 throw JSONRPCError(-4, "Error refreshing keypool.");
1387
1388 return Value::null;
1389 }
1390
1391
1392 void ThreadTopUpKeyPool(void* parg)
1393 {
1394 pwalletMain->TopUpKeyPool();
1395 }
1396
1397 void ThreadCleanWalletPassphrase(void* parg)
1398 {
1399 int64 nMyWakeTime = GetTimeMillis() + *((int64*)parg) * 1000;
1400
1401 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1402
1403 if (nWalletUnlockTime == 0)
1404 {
1405 nWalletUnlockTime = nMyWakeTime;
1406
1407 do
1408 {
1409 if (nWalletUnlockTime==0)
1410 break;
1411 int64 nToSleep = nWalletUnlockTime - GetTimeMillis();
1412 if (nToSleep <= 0)
1413 break;
1414
1415 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1416 Sleep(nToSleep);
1417 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1418
1419 } while(1);
1420
1421 if (nWalletUnlockTime)
1422 {
1423 nWalletUnlockTime = 0;
1424 pwalletMain->Lock();
1425 }
1426 }
1427 else
1428 {
1429 if (nWalletUnlockTime < nMyWakeTime)
1430 nWalletUnlockTime = nMyWakeTime;
1431 }
1432
1433 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1434
1435 delete (int64*)parg;
1436 }
1437
1438 Value walletpassphrase(const Array& params, bool fHelp)
1439 {
1440 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1441 throw runtime_error(
1442 "walletpassphrase <passphrase> <timeout>\n"
1443 "Stores the wallet decryption key in memory for <timeout> seconds.");
1444 if (fHelp)
1445 return true;
1446 if (!pwalletMain->IsCrypted())
1447 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
1448
1449 if (!pwalletMain->IsLocked())
1450 throw JSONRPCError(-17, "Error: Wallet is already unlocked.");
1451
1452
1453 SecureString strWalletPass;
1454 strWalletPass.reserve(100);
1455
1456
1457 strWalletPass = params[0].get_str().c_str();
1458
1459 if (strWalletPass.length() > 0)
1460 {
1461 if (!pwalletMain->Unlock(strWalletPass))
1462 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1463 }
1464 else
1465 throw runtime_error(
1466 "walletpassphrase <passphrase> <timeout>\n"
1467 "Stores the wallet decryption key in memory for <timeout> seconds.");
1468
1469 CreateThread(ThreadTopUpKeyPool, NULL);
1470 int64* pnSleepTime = new int64(params[1].get_int64());
1471 CreateThread(ThreadCleanWalletPassphrase, pnSleepTime);
1472
1473 return Value::null;
1474 }
1475
1476
1477 Value walletpassphrasechange(const Array& params, bool fHelp)
1478 {
1479 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1480 throw runtime_error(
1481 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1482 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1483 if (fHelp)
1484 return true;
1485 if (!pwalletMain->IsCrypted())
1486 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
1487
1488
1489
1490 SecureString strOldWalletPass;
1491 strOldWalletPass.reserve(100);
1492 strOldWalletPass = params[0].get_str().c_str();
1493
1494 SecureString strNewWalletPass;
1495 strNewWalletPass.reserve(100);
1496 strNewWalletPass = params[1].get_str().c_str();
1497
1498 if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
1499 throw runtime_error(
1500 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1501 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1502
1503 if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
1504 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1505
1506 return Value::null;
1507 }
1508
1509
1510 Value walletlock(const Array& params, bool fHelp)
1511 {
1512 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
1513 throw runtime_error(
1514 "walletlock\n"
1515 "Removes the wallet encryption key from memory, locking the wallet.\n"
1516 "After calling this method, you will need to call walletpassphrase again\n"
1517 "before being able to call any methods which require the wallet to be unlocked.");
1518 if (fHelp)
1519 return true;
1520 if (!pwalletMain->IsCrypted())
1521 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletlock was called.");
1522
1523 CRITICAL_BLOCK(cs_nWalletUnlockTime)
1524 {
1525 pwalletMain->Lock();
1526 nWalletUnlockTime = 0;
1527 }
1528
1529 return Value::null;
1530 }
1531
1532
1533 Value encryptwallet(const Array& params, bool fHelp)
1534 {
1535 if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
1536 throw runtime_error(
1537 "encryptwallet <passphrase>\n"
1538 "Encrypts the wallet with <passphrase>.");
1539 if (fHelp)
1540 return true;
1541 if (pwalletMain->IsCrypted())
1542 throw JSONRPCError(-15, "Error: running with an encrypted wallet, but encryptwallet was called.");
1543
1544
1545
1546 SecureString strWalletPass;
1547 strWalletPass.reserve(100);
1548 strWalletPass = params[0].get_str().c_str();
1549
1550 if (strWalletPass.length() < 1)
1551 throw runtime_error(
1552 "encryptwallet <passphrase>\n"
1553 "Encrypts the wallet with <passphrase>.");
1554
1555 if (!pwalletMain->EncryptWallet(strWalletPass))
1556 throw JSONRPCError(-16, "Error: Failed to encrypt the wallet.");
1557
1558
1559
1560
1561 CreateThread(Shutdown, NULL);
1562 return "wallet encrypted; bitcoin server stopping, restart to run with encrypted wallet";
1563 }
1564
1565
1566 Value validateaddress(const Array& params, bool fHelp)
1567 {
1568 if (fHelp || params.size() != 1)
1569 throw runtime_error(
1570 "validateaddress <bitcoinaddress>\n"
1571 "Return information about <bitcoinaddress>.");
1572
1573 CBitcoinAddress address(params[0].get_str());
1574 bool isValid = address.IsValid();
1575
1576 Object ret;
1577 ret.push_back(Pair("isvalid", isValid));
1578 if (isValid)
1579 {
1580
1581
1582 string currentAddress = address.ToString();
1583 ret.push_back(Pair("address", currentAddress));
1584 ret.push_back(Pair("ismine", (pwalletMain->HaveKey(address) > 0)));
1585 if (pwalletMain->mapAddressBook.count(address))
1586 ret.push_back(Pair("account", pwalletMain->mapAddressBook[address]));
1587 }
1588 return ret;
1589 }
1590
1591
1592 Value getwork(const Array& params, bool fHelp)
1593 {
1594 if (fHelp || params.size() > 1)
1595 throw runtime_error(
1596 "getwork [data]\n"
1597 "If [data] is not specified, returns formatted hash data to work on:\n"
1598 " \"midstate\" : precomputed hash state after hashing the first half of the data (DEPRECATED)\n"
1599 " \"data\" : block data\n"
1600 " \"hash1\" : formatted hash buffer for second hash (DEPRECATED)\n"
1601 " \"target\" : little endian hash target\n"
1602 "If [data] is specified, tries to solve the block and returns true if it was successful.");
1603
1604 if (vNodes.empty())
1605 throw JSONRPCError(-9, "Bitcoin is not connected!");
1606
1607 if (IsInitialBlockDownload())
1608 throw JSONRPCError(-10, "Bitcoin is downloading blocks...");
1609
1610 typedef map<uint256, pair<CBlock*, CScript> > mapNewBlock_t;
1611 static mapNewBlock_t mapNewBlock;
1612 static vector<CBlock*> vNewBlock;
1613 static CReserveKey reservekey(pwalletMain);
1614
1615 if (params.size() == 0)
1616 {
1617
1618 static unsigned int nTransactionsUpdatedLast;
1619 static CBlockIndex* pindexPrev;
1620 static int64 nStart;
1621 static CBlock* pblock;
1622 if (pindexPrev != pindexBest ||
1623 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60))
1624 {
1625 if (pindexPrev != pindexBest)
1626 {
1627
1628 mapNewBlock.clear();
1629 BOOST_FOREACH(CBlock* pblock, vNewBlock)
1630 delete pblock;
1631 vNewBlock.clear();
1632 }
1633 nTransactionsUpdatedLast = nTransactionsUpdated;
1634 pindexPrev = pindexBest;
1635 nStart = GetTime();
1636
1637
1638 pblock = CreateNewBlock(reservekey);
1639 if (!pblock)
1640 throw JSONRPCError(-7, "Out of memory");
1641 vNewBlock.push_back(pblock);
1642 }
1643
1644
1645 pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
1646 pblock->nNonce = 0;
1647
1648
1649 static unsigned int nExtraNonce = 0;
1650 IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
1651
1652
1653 mapNewBlock[pblock->hashMerkleRoot] = make_pair(pblock, pblock->vtx[0].vin[0].scriptSig);
1654
1655
1656 char pmidstate[32];
1657 char pdata[128];
1658 char phash1[64];
1659 FormatHashBuffers(pblock, pmidstate, pdata, phash1);
1660
1661 uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
1662
1663 Object result;
1664 result.push_back(Pair("midstate", HexStr(BEGIN(pmidstate), END(pmidstate))));
1665 result.push_back(Pair("data", HexStr(BEGIN(pdata), END(pdata))));
1666 result.push_back(Pair("hash1", HexStr(BEGIN(phash1), END(phash1))));
1667 result.push_back(Pair("target", HexStr(BEGIN(hashTarget), END(hashTarget))));
1668 return result;
1669 }
1670 else
1671 {
1672
1673 vector<unsigned char> vchData = ParseHex(params[0].get_str());
1674 if (vchData.size() != 128)
1675 throw JSONRPCError(-8, "Invalid parameter");
1676 CBlock* pdata = (CBlock*)&vchData[0];
1677
1678
1679 for (int i = 0; i < 128/4; i++)
1680 ((unsigned int*)pdata)[i] = ByteReverse(((unsigned int*)pdata)[i]);
1681
1682
1683 if (!mapNewBlock.count(pdata->hashMerkleRoot))
1684 return false;
1685 CBlock* pblock = mapNewBlock[pdata->hashMerkleRoot].first;
1686
1687 pblock->nTime = pdata->nTime;
1688 pblock->nNonce = pdata->nNonce;
1689 pblock->vtx[0].vin[0].scriptSig = mapNewBlock[pdata->hashMerkleRoot].second;
1690 pblock->hashMerkleRoot = pblock->BuildMerkleTree();
1691
1692 return CheckWork(pblock, *pwalletMain, reservekey);
1693 }
1694 }
1695
1696
1697 Value getmemorypool(const Array& params, bool fHelp)
1698 {
1699 if (fHelp || params.size() > 1)
1700 throw runtime_error(
1701 "getmemorypool [data]\n"
1702 "If [data] is not specified, returns data needed to construct a block to work on:\n"
1703 " \"version\" : block version\n"
1704 " \"previousblockhash\" : hash of current highest block\n"
1705 " \"transactions\" : contents of non-coinbase transactions that should be included in the next block\n"
1706 " \"coinbasevalue\" : maximum allowable input to coinbase transaction, including the generation award and transaction fees\n"
1707 " \"time\" : timestamp appropriate for next block\n"
1708 " \"bits\" : compressed target of next block\n"
1709 "If [data] is specified, tries to solve the block and returns true if it was successful.");
1710
1711 if (params.size() == 0)
1712 {
1713 if (vNodes.empty())
1714 throw JSONRPCError(-9, "Bitcoin is not connected!");
1715
1716 if (IsInitialBlockDownload())
1717 throw JSONRPCError(-10, "Bitcoin is downloading blocks...");
1718
1719 static CReserveKey reservekey(pwalletMain);
1720
1721
1722 static unsigned int nTransactionsUpdatedLast;
1723 static CBlockIndex* pindexPrev;
1724 static int64 nStart;
1725 static CBlock* pblock;
1726 if (pindexPrev != pindexBest ||
1727 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 5))
1728 {
1729 nTransactionsUpdatedLast = nTransactionsUpdated;
1730 pindexPrev = pindexBest;
1731 nStart = GetTime();
1732
1733
1734 if(pblock)
1735 delete pblock;
1736 pblock = CreateNewBlock(reservekey);
1737 if (!pblock)
1738 throw JSONRPCError(-7, "Out of memory");
1739 }
1740
1741
1742 pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
1743 pblock->nNonce = 0;
1744
1745 Array transactions;
1746 BOOST_FOREACH(CTransaction tx, pblock->vtx) {
1747 if(tx.IsCoinBase())
1748 continue;
1749
1750 CDataStream ssTx;
1751 ssTx << tx;
1752
1753 transactions.push_back(HexStr(ssTx.begin(), ssTx.end()));
1754 }
1755
1756 Object result;
1757 result.push_back(Pair("version", pblock->nVersion));
1758 result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex()));
1759 result.push_back(Pair("transactions", transactions));
1760 result.push_back(Pair("coinbasevalue", (boost::int64_t)pblock->vtx[0].vout[0].nValue));
1761 result.push_back(Pair("time", (boost::int64_t)pblock->nTime));
1762
1763 union {
1764 int32_t nBits;
1765 char cBits[4];
1766 } uBits;
1767 uBits.nBits = htonl((int32_t)pblock->nBits);
1768 result.push_back(Pair("bits", HexStr(BEGIN(uBits.cBits), END(uBits.cBits))));
1769
1770 return result;
1771 }
1772 else
1773 {
1774
1775 CDataStream ssBlock(ParseHex(params[0].get_str()));
1776 CBlock pblock;
1777 ssBlock >> pblock;
1778
1779 return ProcessBlock(NULL, &pblock);
1780 }
1781 }
1782
1783
1784 Value dumpblock(const Array& params, bool fHelp)
1785 {
1786 if (fHelp || params.size() != 2)
1787 throw runtime_error(
1788 "dumpblock <height> <filename>\n"
1789 "Emit the block at <height> to <filename>.");
1790
1791 int want_height = 0;
1792 if (params.size() > 0)
1793 want_height = params[0].get_int();
1794
1795 if (want_height > nBestHeight)
1796 throw runtime_error("Requested block exceeds current nBestHeight!\n");
1797
1798
1799 string filename = params[1].get_str();
1800
1801
1802
1803 for (map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.begin(); mi != mapBlockIndex.end(); ++mi)
1804 {
1805 CBlockIndex *pindex = (*mi).second;
1806 if (pindex->nHeight == want_height) {
1807 CBlock block;
1808 block.ReadFromDisk(pindex);
1809 printf("Dumping block %d to %s\n", want_height, filename.c_str());
1810 CAutoFile fileout = fopen(filename.c_str(), "wb+");
1811 fileout << block;
1812 return true;
1813 }
1814 }
1815 return false;
1816 }
1817
1818
1819 Value eatblock(const Array& params, bool fHelp)
1820 {
1821 if (fHelp || params.size() < 1 || params.size() > 1)
1822 throw runtime_error(
1823 "eatblock <filename>\n"
1824 "Load a candidate for the next block directly from <filename>.");
1825
1826 if (!fCanEat)
1827 throw runtime_error(
1828 "'eatblock' is only permitted if bitcoind was started with -caneat flag!");
1829
1830
1831 string filename = params[0].get_str();
1832
1833 printf("Attempting to create block #%d from file %s\n", nBestHeight + 1, filename.c_str());
1834 CAutoFile filein = fopen(filename.c_str(), "rb");
1835 CBlock block;
1836 filein >> block;
1837 return ProcessBlock(NULL, &block);
1838 }
1839
1840
1841
1842
1843
1844
1845
1846 pair<string, rpcfn_type> pCallTable[] =
1847 {
1848 make_pair("help", &help),
1849 make_pair("stop", &stop),
1850 make_pair("getblockcount", &getblockcount),
1851 make_pair("getblocknumber", &getblocknumber),
1852 make_pair("getconnectioncount", &getconnectioncount),
1853 make_pair("getdifficulty", &getdifficulty),
1854 make_pair("getgenerate", &getgenerate),
1855 make_pair("setgenerate", &setgenerate),
1856 make_pair("gethashespersec", &gethashespersec),
1857 make_pair("getinfo", &getinfo),
1858 make_pair("getnewaddress", &getnewaddress),
1859 make_pair("getaccountaddress", &getaccountaddress),
1860 make_pair("setaccount", &setaccount),
1861 make_pair("getaccount", &getaccount),
1862 make_pair("getaddressesbyaccount", &getaddressesbyaccount),
1863 make_pair("sendtoaddress", &sendtoaddress),
1864 make_pair("getreceivedbyaddress", &getreceivedbyaddress),
1865 make_pair("getreceivedbyaccount", &getreceivedbyaccount),
1866 make_pair("listreceivedbyaddress", &listreceivedbyaddress),
1867 make_pair("listreceivedbyaccount", &listreceivedbyaccount),
1868 make_pair("backupwallet", &backupwallet),
1869 make_pair("keypoolrefill", &keypoolrefill),
1870 make_pair("walletpassphrase", &walletpassphrase),
1871 make_pair("walletpassphrasechange", &walletpassphrasechange),
1872 make_pair("walletlock", &walletlock),
1873 make_pair("encryptwallet", &encryptwallet),
1874 make_pair("validateaddress", &validateaddress),
1875 make_pair("getbalance", &getbalance),
1876 make_pair("move", &movecmd),
1877 make_pair("sendfrom", &sendfrom),
1878 make_pair("sendmany", &sendmany),
1879 make_pair("gettransaction", &gettransaction),
1880 make_pair("listtransactions", &listtransactions),
1881 make_pair("signmessage", &signmessage),
1882 make_pair("verifymessage", &verifymessage),
1883 make_pair("getwork", &getwork),
1884 make_pair("listaccounts", &listaccounts),
1885 make_pair("settxfee", &settxfee),
1886 make_pair("getmemorypool", &getmemorypool),
1887 make_pair("listsinceblock", &listsinceblock),
1888 make_pair("dumpblock", &dumpblock),
1889 make_pair("eatblock", &eatblock),
1890 };
1891 map<string, rpcfn_type> mapCallTable(pCallTable, pCallTable + sizeof(pCallTable)/sizeof(pCallTable[0]));
1892
1893 string pAllowInSafeMode[] =
1894 {
1895 "help",
1896 "stop",
1897 "getblockcount",
1898 "getblocknumber",
1899 "getconnectioncount",
1900 "getdifficulty",
1901 "getgenerate",
1902 "setgenerate",
1903 "gethashespersec",
1904 "getinfo",
1905 "getnewaddress",
1906 "getaccountaddress",
1907 "getaccount",
1908 "getaddressesbyaccount",
1909 "backupwallet",
1910 "keypoolrefill",
1911 "walletpassphrase",
1912 "walletlock",
1913 "validateaddress",
1914 "getwork",
1915 "getmemorypool",
1916 "dumpblock",
1917 };
1918 set<string> setAllowInSafeMode(pAllowInSafeMode, pAllowInSafeMode + sizeof(pAllowInSafeMode)/sizeof(pAllowInSafeMode[0]));
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930 string HTTPPost(const string& strMsg, const map<string,string>& mapRequestHeaders)
1931 {
1932 ostringstream s;
1933 s << "POST / HTTP/1.1\r\n"
1934 << "User-Agent: bitcoin-json-rpc/" << FormatFullVersion() << "\r\n"
1935 << "Host: 127.0.0.1\r\n"
1936 << "Content-Type: application/json\r\n"
1937 << "Content-Length: " << strMsg.size() << "\r\n"
1938 << "Connection: close\r\n"
1939 << "Accept: application/json\r\n";
1940 BOOST_FOREACH(const PAIRTYPE(string, string)& item, mapRequestHeaders)
1941 s << item.first << ": " << item.second << "\r\n";
1942 s << "\r\n" << strMsg;
1943
1944 return s.str();
1945 }
1946
1947 string rfc1123Time()
1948 {
1949 char buffer[64];
1950 time_t now;
1951 time(&now);
1952 struct tm* now_gmt = gmtime(&now);
1953 string locale(setlocale(LC_TIME, NULL));
1954 setlocale(LC_TIME, "C");
1955 strftime(buffer, sizeof(buffer), "%a, %d %b %Y %H:%M:%S +0000", now_gmt);
1956 setlocale(LC_TIME, locale.c_str());
1957 return string(buffer);
1958 }
1959
1960 static string HTTPReply(int nStatus, const string& strMsg)
1961 {
1962 if (nStatus == 401)
1963 return strprintf("HTTP/1.0 401 Authorization Required\r\n"
1964 "Date: %s\r\n"
1965 "Server: bitcoin-json-rpc/%s\r\n"
1966 "WWW-Authenticate: Basic realm=\"jsonrpc\"\r\n"
1967 "Content-Type: text/html\r\n"
1968 "Content-Length: 296\r\n"
1969 "\r\n"
1970 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\r\n"
1971 "\"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd\">\r\n"
1972 "<HTML>\r\n"
1973 "<HEAD>\r\n"
1974 "<TITLE>Error</TITLE>\r\n"
1975 "<META HTTP-EQUIV='Content-Type' CONTENT='text/html; charset=ISO-8859-1'>\r\n"
1976 "</HEAD>\r\n"
1977 "<BODY><H1>401 Unauthorized.</H1></BODY>\r\n"
1978 "</HTML>\r\n", rfc1123Time().c_str(), FormatFullVersion().c_str());
1979 const char *cStatus;
1980 if (nStatus == 200) cStatus = "OK";
1981 else if (nStatus == 400) cStatus = "Bad Request";
1982 else if (nStatus == 403) cStatus = "Forbidden";
1983 else if (nStatus == 404) cStatus = "Not Found";
1984 else if (nStatus == 500) cStatus = "Internal Server Error";
1985 else cStatus = "";
1986 return strprintf(
1987 "HTTP/1.1 %d %s\r\n"
1988 "Date: %s\r\n"
1989 "Connection: close\r\n"
1990 "Content-Length: %d\r\n"
1991 "Content-Type: application/json\r\n"
1992 "Server: bitcoin-json-rpc/%s\r\n"
1993 "\r\n"
1994 "%s",
1995 nStatus,
1996 cStatus,
1997 rfc1123Time().c_str(),
1998 strMsg.size(),
1999 FormatFullVersion().c_str(),
2000 strMsg.c_str());
2001 }
2002
2003 int ReadHTTPStatus(std::basic_istream<char>& stream)
2004 {
2005 string str;
2006 getline(stream, str);
2007 vector<string> vWords;
2008 boost::split(vWords, str, boost::is_any_of(" "));
2009 if (vWords.size() < 2)
2010 return 500;
2011 return atoi(vWords[1].c_str());
2012 }
2013
2014 int ReadHTTPHeader(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet)
2015 {
2016 int nLen = 0;
2017 loop
2018 {
2019 string str;
2020 std::getline(stream, str);
2021 if (str.empty() || str == "\r")
2022 break;
2023 string::size_type nColon = str.find(":");
2024 if (nColon != string::npos)
2025 {
2026 string strHeader = str.substr(0, nColon);
2027 boost::trim(strHeader);
2028 boost::to_lower(strHeader);
2029 string strValue = str.substr(nColon+1);
2030 boost::trim(strValue);
2031 mapHeadersRet[strHeader] = strValue;
2032 if (strHeader == "content-length")
2033 nLen = atoi(strValue.c_str());
2034 }
2035 }
2036 return nLen;
2037 }
2038
2039 int ReadHTTP(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet, string& strMessageRet)
2040 {
2041 mapHeadersRet.clear();
2042 strMessageRet = "";
2043
2044
2045 int nStatus = ReadHTTPStatus(stream);
2046
2047
2048 int nLen = ReadHTTPHeader(stream, mapHeadersRet);
2049 if (nLen < 0 || nLen > MAX_SIZE)
2050 return 500;
2051
2052
2053 if (nLen > 0)
2054 {
2055 vector<char> vch(nLen);
2056 stream.read(&vch[0], nLen);
2057 strMessageRet = string(vch.begin(), vch.end());
2058 }
2059
2060 return nStatus;
2061 }
2062
2063 bool HTTPAuthorized(map<string, string>& mapHeaders)
2064 {
2065 string strAuth = mapHeaders["authorization"];
2066 if (strAuth.substr(0,6) != "Basic ")
2067 return false;
2068 string strUserPass64 = strAuth.substr(6); boost::trim(strUserPass64);
2069 string strUserPass = DecodeBase64(strUserPass64);
2070 return strUserPass == strRPCUserColonPass;
2071 }
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083 string JSONRPCRequest(const string& strMethod, const Array& params, const Value& id)
2084 {
2085 Object request;
2086 request.push_back(Pair("method", strMethod));
2087 request.push_back(Pair("params", params));
2088 request.push_back(Pair("id", id));
2089 return write_string(Value(request), false) + "\n";
2090 }
2091
2092 string JSONRPCReply(const Value& result, const Value& error, const Value& id)
2093 {
2094 Object reply;
2095 if (error.type() != null_type)
2096 reply.push_back(Pair("result", Value::null));
2097 else
2098 reply.push_back(Pair("result", result));
2099 reply.push_back(Pair("error", error));
2100 reply.push_back(Pair("id", id));
2101 return write_string(Value(reply), false) + "\n";
2102 }
2103
2104 void ErrorReply(std::ostream& stream, const Object& objError, const Value& id)
2105 {
2106
2107 int nStatus = 500;
2108 int code = find_value(objError, "code").get_int();
2109 if (code == -32600) nStatus = 400;
2110 else if (code == -32601) nStatus = 404;
2111 string strReply = JSONRPCReply(Value::null, objError, id);
2112 stream << HTTPReply(nStatus, strReply) << std::flush;
2113 }
2114
2115 bool ClientAllowed(const string& strAddress)
2116 {
2117 if (strAddress == asio::ip::address_v4::loopback().to_string())
2118 return true;
2119 const vector<string>& vAllow = mapMultiArgs["-rpcallowip"];
2120 BOOST_FOREACH(string strAllow, vAllow)
2121 if (WildcardMatch(strAddress, strAllow))
2122 return true;
2123 return false;
2124 }
2125
2126 void ThreadRPCServer(void* parg)
2127 {
2128 IMPLEMENT_RANDOMIZE_STACK(ThreadRPCServer(parg));
2129 try
2130 {
2131 vnThreadsRunning[4]++;
2132 ThreadRPCServer2(parg);
2133 vnThreadsRunning[4]--;
2134 }
2135 catch (std::exception& e) {
2136 vnThreadsRunning[4]--;
2137 PrintException(&e, "ThreadRPCServer()");
2138 } catch (...) {
2139 vnThreadsRunning[4]--;
2140 PrintException(NULL, "ThreadRPCServer()");
2141 }
2142 printf("ThreadRPCServer exiting\n");
2143 }
2144
2145 void ThreadRPCServer2(void* parg)
2146 {
2147 printf("ThreadRPCServer started\n");
2148
2149 strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"];
2150 if (strRPCUserColonPass == ":")
2151 {
2152 unsigned char rand_pwd[32];
2153 RAND_bytes(rand_pwd, 32);
2154 string strWhatAmI = "To use bitcoind";
2155 if (mapArgs.count("-server"))
2156 strWhatAmI = strprintf(_("To use the %s option"), "\"-server\"");
2157 else if (mapArgs.count("-daemon"))
2158 strWhatAmI = strprintf(_("To use the %s option"), "\"-daemon\"");
2159 PrintConsole(
2160 _("Error: %s, you must set a rpcpassword in the configuration file:\n %s\n"
2161 "It is recommended you use the following random password:\n"
2162 "rpcuser=bitcoinrpc\n"
2163 "rpcpassword=%s\n"
2164 "(you do not need to remember this password)\n"
2165 "If the file does not exist, create it with owner-readable-only file permissions.\n"),
2166 strWhatAmI.c_str(),
2167 GetConfigFile().c_str(),
2168 EncodeBase58(&rand_pwd[0],&rand_pwd[0]+32).c_str());
2169 CreateThread(Shutdown, NULL);
2170 return;
2171 }
2172
2173 asio::ip::address bindAddress = mapArgs.count("-rpcallowip") ? asio::ip::address_v4::any() : asio::ip::address_v4::loopback();
2174
2175 asio::io_service io_service;
2176 ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", 8332));
2177 ip::tcp::acceptor acceptor(io_service, endpoint);
2178
2179 acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
2180
2181 loop
2182 {
2183
2184 ip::tcp::iostream stream;
2185
2186 ip::tcp::endpoint peer;
2187 vnThreadsRunning[4]--;
2188 acceptor.accept(*stream.rdbuf(), peer);
2189 vnThreadsRunning[4]++;
2190 if (fShutdown)
2191 return;
2192
2193
2194 if (!ClientAllowed(peer.address().to_string()))
2195 {
2196
2197
2198
2199 stream << HTTPReply(403, "") << std::flush;
2200 continue;
2201 }
2202
2203 map<string, string> mapHeaders;
2204 string strRequest;
2205
2206 boost::thread api_caller(ReadHTTP, boost::ref(stream), boost::ref(mapHeaders), boost::ref(strRequest));
2207 if (!api_caller.timed_join(boost::posix_time::seconds(GetArg("-rpctimeout", 30))))
2208 {
2209 acceptor.cancel();
2210 printf("ThreadRPCServer ReadHTTP timeout\n");
2211 continue;
2212 }
2213
2214
2215 if (mapHeaders.count("authorization") == 0)
2216 {
2217 stream << HTTPReply(401, "") << std::flush;
2218 continue;
2219 }
2220 if (!HTTPAuthorized(mapHeaders))
2221 {
2222 printf("ThreadRPCServer incorrect password attempt from %s\n",peer.address().to_string().c_str());
2223
2224
2225
2226 if (mapArgs["-rpcpassword"].size() < 20)
2227 Sleep(250);
2228
2229 stream << HTTPReply(401, "") << std::flush;
2230 continue;
2231 }
2232
2233 Value id = Value::null;
2234 try
2235 {
2236
2237 Value valRequest;
2238 if (!read_string(strRequest, valRequest) || valRequest.type() != obj_type)
2239 throw JSONRPCError(-32700, "Parse error");
2240 const Object& request = valRequest.get_obj();
2241
2242
2243 id = find_value(request, "id");
2244
2245
2246 Value valMethod = find_value(request, "method");
2247 if (valMethod.type() == null_type)
2248 throw JSONRPCError(-32600, "Missing method");
2249 if (valMethod.type() != str_type)
2250 throw JSONRPCError(-32600, "Method must be a string");
2251 string strMethod = valMethod.get_str();
2252 if (strMethod != "getwork" && strMethod != "getmemorypool")
2253 printf("ThreadRPCServer method=%s\n", strMethod.c_str());
2254
2255
2256 Value valParams = find_value(request, "params");
2257 Array params;
2258 if (valParams.type() == array_type)
2259 params = valParams.get_array();
2260 else if (valParams.type() == null_type)
2261 params = Array();
2262 else
2263 throw JSONRPCError(-32600, "Params must be an array");
2264
2265
2266 map<string, rpcfn_type>::iterator mi = mapCallTable.find(strMethod);
2267 if (mi == mapCallTable.end())
2268 throw JSONRPCError(-32601, "Method not found");
2269
2270
2271 string strWarning = GetWarnings("rpc");
2272 if (strWarning != "" && !GetBoolArg("-disablesafemode") && !setAllowInSafeMode.count(strMethod))
2273 throw JSONRPCError(-2, string("Safe mode: ") + strWarning);
2274
2275 try
2276 {
2277
2278 Value result;
2279 CRITICAL_BLOCK(cs_main)
2280 CRITICAL_BLOCK(pwalletMain->cs_wallet)
2281 result = (*(*mi).second)(params, false);
2282
2283
2284 string strReply = JSONRPCReply(result, Value::null, id);
2285 stream << HTTPReply(200, strReply) << std::flush;
2286 }
2287 catch (std::exception& e)
2288 {
2289 ErrorReply(stream, JSONRPCError(-1, e.what()), id);
2290 }
2291 }
2292 catch (Object& objError)
2293 {
2294 ErrorReply(stream, objError, id);
2295 }
2296 catch (std::exception& e)
2297 {
2298 ErrorReply(stream, JSONRPCError(-32700, e.what()), id);
2299 }
2300 }
2301 }
2302
2303
2304
2305
2306 Object CallRPC(const string& strMethod, const Array& params)
2307 {
2308 if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
2309 throw runtime_error(strprintf(
2310 _("You must set rpcpassword=<password> in the configuration file:\n%s\n"
2311 "If the file does not exist, create it with owner-readable-only file permissions."),
2312 GetConfigFile().c_str()));
2313
2314
2315 ip::tcp::iostream stream(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332"));
2316 if (stream.fail())
2317 throw runtime_error("couldn't connect to server");
2318
2319
2320 string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
2321 map<string, string> mapRequestHeaders;
2322 mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64;
2323
2324
2325 string strRequest = JSONRPCRequest(strMethod, params, 1);
2326 string strPost = HTTPPost(strRequest, mapRequestHeaders);
2327 stream << strPost << std::flush;
2328
2329
2330 map<string, string> mapHeaders;
2331 string strReply;
2332 int nStatus = ReadHTTP(stream, mapHeaders, strReply);
2333 if (nStatus == 401)
2334 throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
2335 else if (nStatus >= 400 && nStatus != 400 && nStatus != 404 && nStatus != 500)
2336 throw runtime_error(strprintf("server returned HTTP error %d", nStatus));
2337 else if (strReply.empty())
2338 throw runtime_error("no response from server");
2339
2340
2341 Value valReply;
2342 if (!read_string(strReply, valReply))
2343 throw runtime_error("couldn't parse reply from server");
2344 const Object& reply = valReply.get_obj();
2345 if (reply.empty())
2346 throw runtime_error("expected reply to have result, error and id properties");
2347
2348 return reply;
2349 }
2350
2351
2352
2353
2354 template<typename T>
2355 void ConvertTo(Value& value)
2356 {
2357 if (value.type() == str_type)
2358 {
2359
2360 Value value2;
2361 if (!read_string(value.get_str(), value2))
2362 throw runtime_error("type mismatch");
2363 value = value2.get_value<T>();
2364 }
2365 else
2366 {
2367 value = value.get_value<T>();
2368 }
2369 }
2370
2371 int CommandLineRPC(int argc, char *argv[])
2372 {
2373 string strPrint;
2374 int nRet = 0;
2375 try
2376 {
2377
2378 while (argc > 1 && IsSwitchChar(argv[1][0]))
2379 {
2380 argc--;
2381 argv++;
2382 }
2383
2384
2385 if (argc < 2)
2386 throw runtime_error("too few parameters");
2387 string strMethod = argv[1];
2388
2389
2390 Array params;
2391 for (int i = 2; i < argc; i++)
2392 params.push_back(argv[i]);
2393 int n = params.size();
2394
2395
2396
2397
2398 if (strMethod == "setgenerate" && n > 0) ConvertTo<bool>(params[0]);
2399 if (strMethod == "setgenerate" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2400 if (strMethod == "sendtoaddress" && n > 1) ConvertTo<double>(params[1]);
2401 if (strMethod == "settxfee" && n > 0) ConvertTo<double>(params[0]);
2402 if (strMethod == "getreceivedbyaddress" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2403 if (strMethod == "getreceivedbyaccount" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2404 if (strMethod == "listreceivedbyaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2405 if (strMethod == "listreceivedbyaddress" && n > 1) ConvertTo<bool>(params[1]);
2406 if (strMethod == "listreceivedbyaccount" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2407 if (strMethod == "listreceivedbyaccount" && n > 1) ConvertTo<bool>(params[1]);
2408 if (strMethod == "getbalance" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2409 if (strMethod == "move" && n > 2) ConvertTo<double>(params[2]);
2410 if (strMethod == "move" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2411 if (strMethod == "sendfrom" && n > 2) ConvertTo<double>(params[2]);
2412 if (strMethod == "sendfrom" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2413 if (strMethod == "listtransactions" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2414 if (strMethod == "listtransactions" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2415 if (strMethod == "listaccounts" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2416 if (strMethod == "walletpassphrase" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2417 if (strMethod == "listsinceblock" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2418 if (strMethod == "dumpblock" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2419 if (strMethod == "sendmany" && n > 1)
2420 {
2421 string s = params[1].get_str();
2422 Value v;
2423 if (!read_string(s, v) || v.type() != obj_type)
2424 throw runtime_error("type mismatch");
2425 params[1] = v.get_obj();
2426 }
2427 if (strMethod == "sendmany" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2428
2429
2430 Object reply = CallRPC(strMethod, params);
2431
2432
2433 const Value& result = find_value(reply, "result");
2434 const Value& error = find_value(reply, "error");
2435
2436 if (error.type() != null_type)
2437 {
2438
2439 strPrint = "error: " + write_string(error, false);
2440 int code = find_value(error.get_obj(), "code").get_int();
2441 nRet = abs(code);
2442 }
2443 else
2444 {
2445
2446 if (result.type() == null_type)
2447 strPrint = "";
2448 else if (result.type() == str_type)
2449 strPrint = result.get_str();
2450 else
2451 strPrint = write_string(result, true);
2452 }
2453 }
2454 catch (std::exception& e)
2455 {
2456 strPrint = string("error: ") + e.what();
2457 nRet = 87;
2458 }
2459 catch (...)
2460 {
2461 PrintException(NULL, "CommandLineRPC()");
2462 }
2463
2464 if (strPrint != "")
2465 {
2466 fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
2467 }
2468 return nRet;
2469 }
2470
2471
2472
2473
2474 #ifdef TEST
2475 int main(int argc, char *argv[])
2476 {
2477 setbuf(stdin, NULL);
2478 setbuf(stdout, NULL);
2479 setbuf(stderr, NULL);
2480
2481 try
2482 {
2483 if (argc >= 2 && string(argv[1]) == "-server")
2484 {
2485 printf("server ready\n");
2486 ThreadRPCServer(NULL);
2487 }
2488 else
2489 {
2490 return CommandLineRPC(argc, argv);
2491 }
2492 }
2493 catch (std::exception& e) {
2494 PrintException(&e, "main()");
2495 } catch (...) {
2496 PrintException(NULL, "main()");
2497 }
2498 return 0;
2499 }
2500 #endif