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