1 // Copyright (c) 2010 Satoshi Nakamoto
2 // Copyright (c) 2011 The Bitcoin developers
3 // Distributed under the MIT/X11 software license, see the accompanying
4 // file license.txt or http://www.opensource.org/licenses/mit-license.php.
11 #include <boost/asio.hpp>
12 #include <boost/filesystem.hpp>
13 #include <boost/iostreams/concepts.hpp>
14 #include <boost/iostreams/stream.hpp>
15 #include <boost/algorithm/string.hpp>
16 #include <boost/lexical_cast.hpp>
18 #include <boost/asio/ssl.hpp>
19 #include <boost/filesystem.hpp>
20 #include <boost/filesystem/fstream.hpp>
21 typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> SSLStream;
23 #include "json/json_spirit_reader_template.h"
24 #include "json/json_spirit_writer_template.h"
25 #include "json/json_spirit_utils.h"
26 #define printf OutputDebugStringF
27 // MinGW 3.4.5 gets "fatal error: had to relocate PCH" if the json headers are
28 // precompiled in headers.h. The problem might be when the pch file goes over
29 // a certain size around 145MB. If we need access to json_spirit outside this
30 // file, we could use the compiled json_spirit option.
33 using namespace boost;
34 using namespace boost::asio;
35 using namespace json_spirit;
37 void ThreadRPCServer2(void* parg);
38 typedef Value(*rpcfn_type)(const Array& params, bool fHelp);
39 extern map<string, rpcfn_type> mapCallTable;
41 static std::string strRPCUserColonPass;
43 static int64 nWalletUnlockTime;
44 static CCriticalSection cs_nWalletUnlockTime;
46 extern Value dumpprivkey(const Array& params, bool fHelp);
47 extern Value importprivkey(const Array& params, bool fHelp);
49 Object JSONRPCError(int code, const string& message)
52 error.push_back(Pair("code", code));
53 error.push_back(Pair("message", message));
58 void PrintConsole(const std::string &format, ...)
61 int limit = sizeof(buffer);
63 va_start(arg_ptr, format);
64 int ret = _vsnprintf(buffer, limit, format.c_str(), arg_ptr);
66 if (ret < 0 || ret >= limit)
72 fprintf(stdout, "%s", buffer);
75 double GetDifficulty(const CBlockIndex* blockindex = NULL)
77 // Floating point number that is a multiple of the minimum difficulty,
78 // minimum difficulty = 1.0.
79 if (blockindex == NULL)
81 if (pindexBest == NULL)
84 blockindex = pindexBest;
87 int nShift = (blockindex->nBits >> 24) & 0xff;
90 (double)0x0000ffff / (double)(blockindex->nBits & 0x00ffffff);
107 int64 AmountFromValue(const Value& value)
109 double dAmount = value.get_real();
110 if (dAmount <= 0.0 || dAmount > 21000000.0)
111 throw JSONRPCError(-3, "Invalid amount");
112 int64 nAmount = roundint64(dAmount * COIN);
113 if (!MoneyRange(nAmount))
114 throw JSONRPCError(-3, "Invalid amount");
118 Value ValueFromAmount(int64 amount)
120 return (double)amount / (double)COIN;
123 void WalletTxToJSON(const CWalletTx& wtx, Object& entry)
125 int confirms = wtx.GetDepthInMainChain();
126 entry.push_back(Pair("confirmations", confirms));
129 entry.push_back(Pair("blockhash", wtx.hashBlock.GetHex()));
130 entry.push_back(Pair("blockindex", wtx.nIndex));
132 entry.push_back(Pair("txid", wtx.GetHash().GetHex()));
133 entry.push_back(Pair("time", (boost::int64_t)wtx.GetTxTime()));
134 BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue)
135 entry.push_back(Pair(item.first, item.second));
138 string AccountFromValue(const Value& value)
140 string strAccount = value.get_str();
141 if (strAccount == "*")
142 throw JSONRPCError(-11, "Invalid account name");
146 Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex)
149 result.push_back(Pair("hash", block.GetHash().GetHex()));
150 result.push_back(Pair("blockcount", blockindex->nHeight));
151 result.push_back(Pair("version", block.nVersion));
152 result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex()));
153 result.push_back(Pair("time", (boost::int64_t)block.GetBlockTime()));
154 result.push_back(Pair("nonce", (boost::uint64_t)block.nNonce));
155 result.push_back(Pair("difficulty", GetDifficulty(blockindex)));
157 BOOST_FOREACH (const CTransaction&tx, block.vtx)
158 txhashes.push_back(tx.GetHash().GetHex());
159 result.push_back(Pair("tx", txhashes));
161 if (blockindex->pprev)
162 result.push_back(Pair("hashprevious", blockindex->pprev->GetBlockHash().GetHex()));
163 if (blockindex->pnext)
164 result.push_back(Pair("hashnext", blockindex->pnext->GetBlockHash().GetHex()));
171 /// Note: This interface may still be subject to change.
175 Value help(const Array& params, bool fHelp)
177 if (fHelp || params.size() > 1)
180 "List commands, or get help for a command.");
183 if (params.size() > 0)
184 strCommand = params[0].get_str();
187 set<rpcfn_type> setDone;
188 for (map<string, rpcfn_type>::iterator mi = mapCallTable.begin(); mi != mapCallTable.end(); ++mi)
190 string strMethod = (*mi).first;
191 // We already filter duplicates, but these deprecated screw up the sort order
192 if (strMethod == "getamountreceived" ||
193 strMethod == "getallreceived" ||
194 strMethod == "getblocknumber" || // deprecated
195 (strMethod.find("label") != string::npos))
197 if (strCommand != "" && strMethod != strCommand)
202 rpcfn_type pfn = (*mi).second;
203 if (setDone.insert(pfn).second)
204 (*pfn)(params, true);
206 catch (std::exception& e)
208 // Help text is returned in an exception
209 string strHelp = string(e.what());
210 if (strCommand == "")
211 if (strHelp.find('\n') != -1)
212 strHelp = strHelp.substr(0, strHelp.find('\n'));
213 strRet += strHelp + "\n";
217 strRet = strprintf("help: unknown command: %s\n", strCommand.c_str());
218 strRet = strRet.substr(0,strRet.size()-1);
223 Value stop(const Array& params, bool fHelp)
225 if (fHelp || params.size() != 0)
228 "Stop bitcoin server.");
230 // Shutdown will take long enough that the response should get back
231 CreateThread(Shutdown, NULL);
232 return "bitcoin server stopping";
234 throw runtime_error("NYI: cannot shut down GUI with RPC command");
239 Value getblockcount(const Array& params, bool fHelp)
241 if (fHelp || params.size() != 0)
244 "Returns the number of blocks in the longest block chain.");
251 Value getblocknumber(const Array& params, bool fHelp)
253 if (fHelp || params.size() != 0)
256 "Deprecated. Use getblockcount.");
262 Value getconnectioncount(const Array& params, bool fHelp)
264 if (fHelp || params.size() != 0)
266 "getconnectioncount\n"
267 "Returns the number of connections to other nodes.");
269 return (int)vNodes.size();
273 Value getdifficulty(const Array& params, bool fHelp)
275 if (fHelp || params.size() != 0)
278 "Returns the proof-of-work difficulty as a multiple of the minimum difficulty.");
280 return GetDifficulty();
284 Value getgenerate(const Array& params, bool fHelp)
286 if (fHelp || params.size() != 0)
289 "Returns true or false.");
291 return (bool)fGenerateBitcoins;
295 Value setgenerate(const Array& params, bool fHelp)
297 if (fHelp || params.size() < 1 || params.size() > 2)
299 "setgenerate <generate> [genproclimit]\n"
300 "<generate> is true or false to turn generation on or off.\n"
301 "Generation is limited to [genproclimit] processors, -1 is unlimited.");
303 bool fGenerate = true;
304 if (params.size() > 0)
305 fGenerate = params[0].get_bool();
307 if (params.size() > 1)
309 int nGenProcLimit = params[1].get_int();
310 fLimitProcessors = (nGenProcLimit != -1);
311 WriteSetting("fLimitProcessors", fLimitProcessors);
312 if (nGenProcLimit != -1)
313 WriteSetting("nLimitProcessors", nLimitProcessors = nGenProcLimit);
314 if (nGenProcLimit == 0)
318 GenerateBitcoins(fGenerate, pwalletMain);
323 Value gethashespersec(const Array& params, bool fHelp)
325 if (fHelp || params.size() != 0)
328 "Returns a recent hashes per second performance measurement while generating.");
330 if (GetTimeMillis() - nHPSTimerStart > 8000)
331 return (boost::int64_t)0;
332 return (boost::int64_t)dHashesPerSec;
336 Value getinfo(const Array& params, bool fHelp)
338 if (fHelp || params.size() != 0)
341 "Returns an object containing various state info.");
344 obj.push_back(Pair("version", (int)CLIENT_VERSION));
345 obj.push_back(Pair("protocolversion",(int)PROTOCOL_VERSION));
346 obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance())));
347 obj.push_back(Pair("blocks", (int)nBestHeight));
348 obj.push_back(Pair("connections", (int)vNodes.size()));
349 obj.push_back(Pair("proxy", (fUseProxy ? addrProxy.ToStringIPPort() : string())));
350 obj.push_back(Pair("generate", (bool)fGenerateBitcoins));
351 obj.push_back(Pair("genproclimit", (int)(fLimitProcessors ? nLimitProcessors : -1)));
352 obj.push_back(Pair("difficulty", (double)GetDifficulty()));
353 obj.push_back(Pair("hashespersec", gethashespersec(params, false)));
354 obj.push_back(Pair("testnet", fTestNet));
355 obj.push_back(Pair("keypoololdest", (boost::int64_t)pwalletMain->GetOldestKeyPoolTime()));
356 obj.push_back(Pair("keypoolsize", pwalletMain->GetKeyPoolSize()));
357 obj.push_back(Pair("paytxfee", ValueFromAmount(nTransactionFee)));
358 if (pwalletMain->IsCrypted())
359 obj.push_back(Pair("unlocked_until", (boost::int64_t)nWalletUnlockTime));
360 obj.push_back(Pair("errors", GetWarnings("statusbar")));
365 Value getnewaddress(const Array& params, bool fHelp)
367 if (fHelp || params.size() > 1)
369 "getnewaddress [account]\n"
370 "Returns a new bitcoin address for receiving payments. "
371 "If [account] is specified (recommended), it is added to the address book "
372 "so payments received with the address will be credited to [account].");
374 // Parse the account first so we don't generate a key if there's an error
376 if (params.size() > 0)
377 strAccount = AccountFromValue(params[0]);
379 if (!pwalletMain->IsLocked())
380 pwalletMain->TopUpKeyPool();
382 // Generate a new key that is added to wallet
383 std::vector<unsigned char> newKey;
384 if (!pwalletMain->GetKeyFromPool(newKey, false))
385 throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
386 CBitcoinAddress address(newKey);
388 pwalletMain->SetAddressBookName(address, strAccount);
390 return address.ToString();
394 CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false)
396 CWalletDB walletdb(pwalletMain->strWalletFile);
399 walletdb.ReadAccount(strAccount, account);
401 bool bKeyUsed = false;
403 // Check if the current key has been used
404 if (!account.vchPubKey.empty())
406 CScript scriptPubKey;
407 scriptPubKey.SetBitcoinAddress(account.vchPubKey);
408 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
409 it != pwalletMain->mapWallet.end() && !account.vchPubKey.empty();
412 const CWalletTx& wtx = (*it).second;
413 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
414 if (txout.scriptPubKey == scriptPubKey)
419 // Generate a new key
420 if (account.vchPubKey.empty() || bForceNew || bKeyUsed)
422 if (!pwalletMain->GetKeyFromPool(account.vchPubKey, false))
423 throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
425 pwalletMain->SetAddressBookName(CBitcoinAddress(account.vchPubKey), strAccount);
426 walletdb.WriteAccount(strAccount, account);
429 return CBitcoinAddress(account.vchPubKey);
432 Value getaccountaddress(const Array& params, bool fHelp)
434 if (fHelp || params.size() != 1)
436 "getaccountaddress <account>\n"
437 "Returns the current bitcoin address for receiving payments to this account.");
439 // Parse the account first so we don't generate a key if there's an error
440 string strAccount = AccountFromValue(params[0]);
444 ret = GetAccountAddress(strAccount).ToString();
451 Value setaccount(const Array& params, bool fHelp)
453 if (fHelp || params.size() < 1 || params.size() > 2)
455 "setaccount <bitcoinaddress> <account>\n"
456 "Sets the account associated with the given address.");
458 CBitcoinAddress address(params[0].get_str());
459 if (!address.IsValid())
460 throw JSONRPCError(-5, "Invalid bitcoin address");
464 if (params.size() > 1)
465 strAccount = AccountFromValue(params[1]);
467 // Detect when changing the account of an address that is the 'unused current key' of another account:
468 if (pwalletMain->mapAddressBook.count(address))
470 string strOldAccount = pwalletMain->mapAddressBook[address];
471 if (address == GetAccountAddress(strOldAccount))
472 GetAccountAddress(strOldAccount, true);
475 pwalletMain->SetAddressBookName(address, strAccount);
481 Value getaccount(const Array& params, bool fHelp)
483 if (fHelp || params.size() != 1)
485 "getaccount <bitcoinaddress>\n"
486 "Returns the account associated with the given address.");
488 CBitcoinAddress address(params[0].get_str());
489 if (!address.IsValid())
490 throw JSONRPCError(-5, "Invalid bitcoin address");
493 map<CBitcoinAddress, string>::iterator mi = pwalletMain->mapAddressBook.find(address);
494 if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.empty())
495 strAccount = (*mi).second;
500 Value getaddressesbyaccount(const Array& params, bool fHelp)
502 if (fHelp || params.size() != 1)
504 "getaddressesbyaccount <account>\n"
505 "Returns the list of addresses for the given account.");
507 string strAccount = AccountFromValue(params[0]);
509 // Find all addresses that have the given account
511 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
513 const CBitcoinAddress& address = item.first;
514 const string& strName = item.second;
515 if (strName == strAccount)
516 ret.push_back(address.ToString());
521 Value settxfee(const Array& params, bool fHelp)
523 if (fHelp || params.size() < 1 || params.size() > 1)
525 "settxfee <amount>\n"
526 "<amount> is a real and is rounded to the nearest 0.00000001");
530 if (params[0].get_real() != 0.0)
531 nAmount = AmountFromValue(params[0]); // rejects 0.0 amounts
533 nTransactionFee = nAmount;
537 Value sendtoaddress(const Array& params, bool fHelp)
539 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
541 "sendtoaddress <bitcoinaddress> <amount> [comment] [comment-to]\n"
542 "<amount> is a real and is rounded to the nearest 0.00000001\n"
543 "requires wallet passphrase to be set with walletpassphrase first");
544 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
546 "sendtoaddress <bitcoinaddress> <amount> [comment] [comment-to]\n"
547 "<amount> is a real and is rounded to the nearest 0.00000001");
549 CBitcoinAddress address(params[0].get_str());
550 if (!address.IsValid())
551 throw JSONRPCError(-5, "Invalid bitcoin address");
554 int64 nAmount = AmountFromValue(params[1]);
558 if (params.size() > 2 && params[2].type() != null_type && !params[2].get_str().empty())
559 wtx.mapValue["comment"] = params[2].get_str();
560 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
561 wtx.mapValue["to"] = params[3].get_str();
563 if (pwalletMain->IsLocked())
564 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
566 string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
568 throw JSONRPCError(-4, strError);
570 return wtx.GetHash().GetHex();
573 static const string strMessageMagic = "Bitcoin Signed Message:\n";
575 Value signmessage(const Array& params, bool fHelp)
577 if (fHelp || params.size() != 2)
579 "signmessage <bitcoinaddress> <message>\n"
580 "Sign a message with the private key of an address");
582 if (pwalletMain->IsLocked())
583 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
585 string strAddress = params[0].get_str();
586 string strMessage = params[1].get_str();
588 CBitcoinAddress addr(strAddress);
590 throw JSONRPCError(-3, "Invalid address");
593 if (!pwalletMain->GetKey(addr, key))
594 throw JSONRPCError(-4, "Private key not available");
596 CDataStream ss(SER_GETHASH);
597 ss << strMessageMagic;
600 vector<unsigned char> vchSig;
601 if (!key.SignCompact(Hash(ss.begin(), ss.end()), vchSig))
602 throw JSONRPCError(-5, "Sign failed");
604 return EncodeBase64(&vchSig[0], vchSig.size());
607 Value verifymessage(const Array& params, bool fHelp)
609 if (fHelp || params.size() != 3)
611 "verifymessage <bitcoinaddress> <signature> <message>\n"
612 "Verify a signed message");
614 string strAddress = params[0].get_str();
615 string strSign = params[1].get_str();
616 string strMessage = params[2].get_str();
618 CBitcoinAddress addr(strAddress);
620 throw JSONRPCError(-3, "Invalid address");
622 bool fInvalid = false;
623 vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid);
626 throw JSONRPCError(-5, "Malformed base64 encoding");
628 CDataStream ss(SER_GETHASH);
629 ss << strMessageMagic;
633 if (!key.SetCompactSignature(Hash(ss.begin(), ss.end()), vchSig))
636 return (CBitcoinAddress(key.GetPubKey()) == addr);
640 Value getreceivedbyaddress(const Array& params, bool fHelp)
642 if (fHelp || params.size() < 1 || params.size() > 2)
644 "getreceivedbyaddress <bitcoinaddress> [minconf=1]\n"
645 "Returns the total amount received by <bitcoinaddress> in transactions with at least [minconf] confirmations.");
648 CBitcoinAddress address = CBitcoinAddress(params[0].get_str());
649 CScript scriptPubKey;
650 if (!address.IsValid())
651 throw JSONRPCError(-5, "Invalid bitcoin address");
652 scriptPubKey.SetBitcoinAddress(address);
653 if (!IsMine(*pwalletMain,scriptPubKey))
656 // Minimum confirmations
658 if (params.size() > 1)
659 nMinDepth = params[1].get_int();
663 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
665 const CWalletTx& wtx = (*it).second;
666 if (wtx.IsCoinBase() || !wtx.IsFinal())
669 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
670 if (txout.scriptPubKey == scriptPubKey)
671 if (wtx.GetDepthInMainChain() >= nMinDepth)
672 nAmount += txout.nValue;
675 return ValueFromAmount(nAmount);
679 void GetAccountAddresses(string strAccount, set<CBitcoinAddress>& setAddress)
681 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
683 const CBitcoinAddress& address = item.first;
684 const string& strName = item.second;
685 if (strName == strAccount)
686 setAddress.insert(address);
691 Value getreceivedbyaccount(const Array& params, bool fHelp)
693 if (fHelp || params.size() < 1 || params.size() > 2)
695 "getreceivedbyaccount <account> [minconf=1]\n"
696 "Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.");
698 // Minimum confirmations
700 if (params.size() > 1)
701 nMinDepth = params[1].get_int();
703 // Get the set of pub keys assigned to account
704 string strAccount = AccountFromValue(params[0]);
705 set<CBitcoinAddress> setAddress;
706 GetAccountAddresses(strAccount, setAddress);
710 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
712 const CWalletTx& wtx = (*it).second;
713 if (wtx.IsCoinBase() || !wtx.IsFinal())
716 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
718 CBitcoinAddress address;
719 if (ExtractAddress(txout.scriptPubKey, address) && pwalletMain->HaveKey(address) && setAddress.count(address))
720 if (wtx.GetDepthInMainChain() >= nMinDepth)
721 nAmount += txout.nValue;
725 return (double)nAmount / (double)COIN;
729 int64 GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth)
733 // Tally wallet transactions
734 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
736 const CWalletTx& wtx = (*it).second;
740 int64 nGenerated, nReceived, nSent, nFee;
741 wtx.GetAccountAmounts(strAccount, nGenerated, nReceived, nSent, nFee);
743 if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
744 nBalance += nReceived;
745 nBalance += nGenerated - nSent - nFee;
748 // Tally internal accounting entries
749 nBalance += walletdb.GetAccountCreditDebit(strAccount);
754 int64 GetAccountBalance(const string& strAccount, int nMinDepth)
756 CWalletDB walletdb(pwalletMain->strWalletFile);
757 return GetAccountBalance(walletdb, strAccount, nMinDepth);
761 Value getbalance(const Array& params, bool fHelp)
763 if (fHelp || params.size() > 2)
765 "getbalance [account] [minconf=1]\n"
766 "If [account] is not specified, returns the server's total available balance.\n"
767 "If [account] is specified, returns the balance in the account.");
769 if (params.size() == 0)
770 return ValueFromAmount(pwalletMain->GetBalance());
773 if (params.size() > 1)
774 nMinDepth = params[1].get_int();
776 if (params[0].get_str() == "*") {
777 // Calculate total balance a different way from GetBalance()
778 // (GetBalance() sums up all unspent TxOuts)
779 // getbalance and getbalance '*' should always return the same number.
781 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
783 const CWalletTx& wtx = (*it).second;
787 int64 allGeneratedImmature, allGeneratedMature, allFee;
788 allGeneratedImmature = allGeneratedMature = allFee = 0;
789 string strSentAccount;
790 list<pair<CBitcoinAddress, int64> > listReceived;
791 list<pair<CBitcoinAddress, int64> > listSent;
792 wtx.GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount);
793 if (wtx.GetDepthInMainChain() >= nMinDepth)
794 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listReceived)
795 nBalance += r.second;
796 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listSent)
797 nBalance -= r.second;
799 nBalance += allGeneratedMature;
801 return ValueFromAmount(nBalance);
804 string strAccount = AccountFromValue(params[0]);
806 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
808 return ValueFromAmount(nBalance);
812 Value movecmd(const Array& params, bool fHelp)
814 if (fHelp || params.size() < 3 || params.size() > 5)
816 "move <fromaccount> <toaccount> <amount> [minconf=1] [comment]\n"
817 "Move from one account in your wallet to another.");
819 string strFrom = AccountFromValue(params[0]);
820 string strTo = AccountFromValue(params[1]);
821 int64 nAmount = AmountFromValue(params[2]);
822 if (params.size() > 3)
823 // unused parameter, used to be nMinDepth, keep type-checking it though
824 (void)params[3].get_int();
826 if (params.size() > 4)
827 strComment = params[4].get_str();
829 CWalletDB walletdb(pwalletMain->strWalletFile);
832 int64 nNow = GetAdjustedTime();
835 CAccountingEntry debit;
836 debit.strAccount = strFrom;
837 debit.nCreditDebit = -nAmount;
839 debit.strOtherAccount = strTo;
840 debit.strComment = strComment;
841 walletdb.WriteAccountingEntry(debit);
844 CAccountingEntry credit;
845 credit.strAccount = strTo;
846 credit.nCreditDebit = nAmount;
848 credit.strOtherAccount = strFrom;
849 credit.strComment = strComment;
850 walletdb.WriteAccountingEntry(credit);
852 walletdb.TxnCommit();
858 Value sendfrom(const Array& params, bool fHelp)
860 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
862 "sendfrom <fromaccount> <tobitcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
863 "<amount> is a real and is rounded to the nearest 0.00000001\n"
864 "requires wallet passphrase to be set with walletpassphrase first");
865 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
867 "sendfrom <fromaccount> <tobitcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
868 "<amount> is a real and is rounded to the nearest 0.00000001");
870 string strAccount = AccountFromValue(params[0]);
871 CBitcoinAddress address(params[1].get_str());
872 if (!address.IsValid())
873 throw JSONRPCError(-5, "Invalid bitcoin address");
874 int64 nAmount = AmountFromValue(params[2]);
876 if (params.size() > 3)
877 nMinDepth = params[3].get_int();
880 wtx.strFromAccount = strAccount;
881 if (params.size() > 4 && params[4].type() != null_type && !params[4].get_str().empty())
882 wtx.mapValue["comment"] = params[4].get_str();
883 if (params.size() > 5 && params[5].type() != null_type && !params[5].get_str().empty())
884 wtx.mapValue["to"] = params[5].get_str();
886 if (pwalletMain->IsLocked())
887 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
890 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
891 if (nAmount > nBalance)
892 throw JSONRPCError(-6, "Account has insufficient funds");
895 string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
897 throw JSONRPCError(-4, strError);
899 return wtx.GetHash().GetHex();
903 Value sendmany(const Array& params, bool fHelp)
905 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
907 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
908 "amounts are double-precision floating point numbers\n"
909 "requires wallet passphrase to be set with walletpassphrase first");
910 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
912 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
913 "amounts are double-precision floating point numbers");
915 string strAccount = AccountFromValue(params[0]);
916 Object sendTo = params[1].get_obj();
918 if (params.size() > 2)
919 nMinDepth = params[2].get_int();
922 wtx.strFromAccount = strAccount;
923 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
924 wtx.mapValue["comment"] = params[3].get_str();
926 set<CBitcoinAddress> setAddress;
927 vector<pair<CScript, int64> > vecSend;
929 int64 totalAmount = 0;
930 BOOST_FOREACH(const Pair& s, sendTo)
932 CBitcoinAddress address(s.name_);
933 if (!address.IsValid())
934 throw JSONRPCError(-5, string("Invalid bitcoin address:")+s.name_);
936 if (setAddress.count(address))
937 throw JSONRPCError(-8, string("Invalid parameter, duplicated address: ")+s.name_);
938 setAddress.insert(address);
940 CScript scriptPubKey;
941 scriptPubKey.SetBitcoinAddress(address);
942 int64 nAmount = AmountFromValue(s.value_);
943 totalAmount += nAmount;
945 vecSend.push_back(make_pair(scriptPubKey, nAmount));
948 if (pwalletMain->IsLocked())
949 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
952 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
953 if (totalAmount > nBalance)
954 throw JSONRPCError(-6, "Account has insufficient funds");
957 CReserveKey keyChange(pwalletMain);
958 int64 nFeeRequired = 0;
959 bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired);
962 if (totalAmount + nFeeRequired > pwalletMain->GetBalance())
963 throw JSONRPCError(-6, "Insufficient funds");
964 throw JSONRPCError(-4, "Transaction creation failed");
966 if (!pwalletMain->CommitTransaction(wtx, keyChange))
967 throw JSONRPCError(-4, "Transaction commit failed");
969 return wtx.GetHash().GetHex();
972 Value addmultisigaddress(const Array& params, bool fHelp)
974 if (fHelp || params.size() < 2 || params.size() > 3)
976 string msg = "addmultisigaddress <nrequired> <'[\"key\",\"key\"]'> [account]\n"
977 "Add a nrequired-to-sign multisignature address to the wallet\"\n"
978 "each key is a bitcoin address, hex or base58 public key\n"
979 "If [account] is specified, assign address to [account].";
980 throw runtime_error(msg);
983 throw runtime_error("addmultisigaddress available only when running -testnet\n");
985 int nRequired = params[0].get_int();
986 const Array& keys = params[1].get_array();
988 if (params.size() > 2)
989 strAccount = AccountFromValue(params[2]);
991 // Gather public keys
992 if (keys.size() < nRequired)
994 strprintf("addmultisigaddress: wrong number of keys (got %d, need at least %d)", keys.size(), nRequired));
995 std::vector<CKey> pubkeys;
996 pubkeys.resize(keys.size());
997 for (int i = 0; i < keys.size(); i++)
999 const std::string& ks = keys[i].get_str();
1000 if (ks.size() == 130) // hex public key
1001 pubkeys[i].SetPubKey(ParseHex(ks));
1002 else if (ks.size() > 34) // base58-encoded
1004 std::vector<unsigned char> vchPubKey;
1005 if (DecodeBase58(ks, vchPubKey))
1006 pubkeys[i].SetPubKey(vchPubKey);
1008 throw runtime_error("Error base58 decoding key: "+ks);
1010 else // bitcoin address for key in this wallet
1012 CBitcoinAddress address(ks);
1013 if (!pwalletMain->GetKey(address, pubkeys[i]))
1014 throw runtime_error(
1015 strprintf("addmultisigaddress: unknown address: %s",ks.c_str()));
1019 // Construct using OP_EVAL
1021 inner.SetMultisig(nRequired, pubkeys);
1023 uint160 scriptHash = Hash160(inner);
1024 CScript scriptPubKey;
1025 scriptPubKey.SetEval(inner);
1026 pwalletMain->AddCScript(scriptHash, inner);
1027 CBitcoinAddress address;
1028 address.SetScriptHash160(scriptHash);
1030 pwalletMain->SetAddressBookName(address, strAccount);
1031 return address.ToString();
1042 nConf = std::numeric_limits<int>::max();
1046 Value ListReceived(const Array& params, bool fByAccounts)
1048 // Minimum confirmations
1050 if (params.size() > 0)
1051 nMinDepth = params[0].get_int();
1053 // Whether to include empty accounts
1054 bool fIncludeEmpty = false;
1055 if (params.size() > 1)
1056 fIncludeEmpty = params[1].get_bool();
1059 map<CBitcoinAddress, tallyitem> mapTally;
1060 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1062 const CWalletTx& wtx = (*it).second;
1064 if (wtx.IsCoinBase() || !wtx.IsFinal())
1067 int nDepth = wtx.GetDepthInMainChain();
1068 if (nDepth < nMinDepth)
1071 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
1073 CBitcoinAddress address;
1074 if (!ExtractAddress(txout.scriptPubKey, address) || !pwalletMain->HaveKey(address) || !address.IsValid())
1077 tallyitem& item = mapTally[address];
1078 item.nAmount += txout.nValue;
1079 item.nConf = min(item.nConf, nDepth);
1085 map<string, tallyitem> mapAccountTally;
1086 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
1088 const CBitcoinAddress& address = item.first;
1089 const string& strAccount = item.second;
1090 map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
1091 if (it == mapTally.end() && !fIncludeEmpty)
1095 int nConf = std::numeric_limits<int>::max();
1096 if (it != mapTally.end())
1098 nAmount = (*it).second.nAmount;
1099 nConf = (*it).second.nConf;
1104 tallyitem& item = mapAccountTally[strAccount];
1105 item.nAmount += nAmount;
1106 item.nConf = min(item.nConf, nConf);
1111 obj.push_back(Pair("address", address.ToString()));
1112 obj.push_back(Pair("account", strAccount));
1113 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1114 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
1121 for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
1123 int64 nAmount = (*it).second.nAmount;
1124 int nConf = (*it).second.nConf;
1126 obj.push_back(Pair("account", (*it).first));
1127 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1128 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
1136 Value listreceivedbyaddress(const Array& params, bool fHelp)
1138 if (fHelp || params.size() > 2)
1139 throw runtime_error(
1140 "listreceivedbyaddress [minconf=1] [includeempty=false]\n"
1141 "[minconf] is the minimum number of confirmations before payments are included.\n"
1142 "[includeempty] whether to include addresses that haven't received any payments.\n"
1143 "Returns an array of objects containing:\n"
1144 " \"address\" : receiving address\n"
1145 " \"account\" : the account of the receiving address\n"
1146 " \"amount\" : total amount received by the address\n"
1147 " \"confirmations\" : number of confirmations of the most recent transaction included");
1149 return ListReceived(params, false);
1152 Value listreceivedbyaccount(const Array& params, bool fHelp)
1154 if (fHelp || params.size() > 2)
1155 throw runtime_error(
1156 "listreceivedbyaccount [minconf=1] [includeempty=false]\n"
1157 "[minconf] is the minimum number of confirmations before payments are included.\n"
1158 "[includeempty] whether to include accounts that haven't received any payments.\n"
1159 "Returns an array of objects containing:\n"
1160 " \"account\" : the account of the receiving addresses\n"
1161 " \"amount\" : total amount received by addresses with this account\n"
1162 " \"confirmations\" : number of confirmations of the most recent transaction included");
1164 return ListReceived(params, true);
1167 void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret)
1169 int64 nGeneratedImmature, nGeneratedMature, nFee;
1170 string strSentAccount;
1171 list<pair<CBitcoinAddress, int64> > listReceived;
1172 list<pair<CBitcoinAddress, int64> > listSent;
1174 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1176 bool fAllAccounts = (strAccount == string("*"));
1178 // Generated blocks assigned to account ""
1179 if ((nGeneratedMature+nGeneratedImmature) != 0 && (fAllAccounts || strAccount == ""))
1182 entry.push_back(Pair("account", string("")));
1183 if (nGeneratedImmature)
1185 entry.push_back(Pair("category", wtx.GetDepthInMainChain() ? "immature" : "orphan"));
1186 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedImmature)));
1190 entry.push_back(Pair("category", "generate"));
1191 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedMature)));
1194 WalletTxToJSON(wtx, entry);
1195 ret.push_back(entry);
1199 if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
1201 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1204 entry.push_back(Pair("account", strSentAccount));
1205 entry.push_back(Pair("address", s.first.ToString()));
1206 entry.push_back(Pair("category", "send"));
1207 entry.push_back(Pair("amount", ValueFromAmount(-s.second)));
1208 entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
1210 WalletTxToJSON(wtx, entry);
1211 ret.push_back(entry);
1216 if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
1217 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1220 if (pwalletMain->mapAddressBook.count(r.first))
1221 account = pwalletMain->mapAddressBook[r.first];
1222 if (fAllAccounts || (account == strAccount))
1225 entry.push_back(Pair("account", account));
1226 entry.push_back(Pair("address", r.first.ToString()));
1227 entry.push_back(Pair("category", "receive"));
1228 entry.push_back(Pair("amount", ValueFromAmount(r.second)));
1230 WalletTxToJSON(wtx, entry);
1231 ret.push_back(entry);
1236 void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret)
1238 bool fAllAccounts = (strAccount == string("*"));
1240 if (fAllAccounts || acentry.strAccount == strAccount)
1243 entry.push_back(Pair("account", acentry.strAccount));
1244 entry.push_back(Pair("category", "move"));
1245 entry.push_back(Pair("time", (boost::int64_t)acentry.nTime));
1246 entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
1247 entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
1248 entry.push_back(Pair("comment", acentry.strComment));
1249 ret.push_back(entry);
1253 Value listtransactions(const Array& params, bool fHelp)
1255 if (fHelp || params.size() > 3)
1256 throw runtime_error(
1257 "listtransactions [account] [count=10] [from=0]\n"
1258 "Returns up to [count] most recent transactions skipping the first [from] transactions for account [account].");
1260 string strAccount = "*";
1261 if (params.size() > 0)
1262 strAccount = params[0].get_str();
1264 if (params.size() > 1)
1265 nCount = params[1].get_int();
1267 if (params.size() > 2)
1268 nFrom = params[2].get_int();
1271 CWalletDB walletdb(pwalletMain->strWalletFile);
1273 // Firs: get all CWalletTx and CAccountingEntry into a sorted-by-time multimap:
1274 typedef pair<CWalletTx*, CAccountingEntry*> TxPair;
1275 typedef multimap<int64, TxPair > TxItems;
1278 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1280 CWalletTx* wtx = &((*it).second);
1281 txByTime.insert(make_pair(wtx->GetTxTime(), TxPair(wtx, (CAccountingEntry*)0)));
1283 list<CAccountingEntry> acentries;
1284 walletdb.ListAccountCreditDebit(strAccount, acentries);
1285 BOOST_FOREACH(CAccountingEntry& entry, acentries)
1287 txByTime.insert(make_pair(entry.nTime, TxPair((CWalletTx*)0, &entry)));
1290 // Now: iterate backwards until we have nCount items to return:
1291 TxItems::reverse_iterator it = txByTime.rbegin();
1292 if (txByTime.size() > nFrom) std::advance(it, nFrom);
1293 for (; it != txByTime.rend(); ++it)
1295 CWalletTx *const pwtx = (*it).second.first;
1297 ListTransactions(*pwtx, strAccount, 0, true, ret);
1298 CAccountingEntry *const pacentry = (*it).second.second;
1300 AcentryToJSON(*pacentry, strAccount, ret);
1302 if (ret.size() >= nCount) break;
1304 // ret is now newest to oldest
1306 // Make sure we return only last nCount items (sends-to-self might give us an extra):
1307 if (ret.size() > nCount)
1309 Array::iterator last = ret.begin();
1310 std::advance(last, nCount);
1311 ret.erase(last, ret.end());
1313 std::reverse(ret.begin(), ret.end()); // oldest to newest
1318 Value listaccounts(const Array& params, bool fHelp)
1320 if (fHelp || params.size() > 1)
1321 throw runtime_error(
1322 "listaccounts [minconf=1]\n"
1323 "Returns Object that has account names as keys, account balances as values.");
1326 if (params.size() > 0)
1327 nMinDepth = params[0].get_int();
1329 map<string, int64> mapAccountBalances;
1330 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& entry, pwalletMain->mapAddressBook) {
1331 if (pwalletMain->HaveKey(entry.first)) // This address belongs to me
1332 mapAccountBalances[entry.second] = 0;
1335 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1337 const CWalletTx& wtx = (*it).second;
1338 int64 nGeneratedImmature, nGeneratedMature, nFee;
1339 string strSentAccount;
1340 list<pair<CBitcoinAddress, int64> > listReceived;
1341 list<pair<CBitcoinAddress, int64> > listSent;
1342 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1343 mapAccountBalances[strSentAccount] -= nFee;
1344 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1345 mapAccountBalances[strSentAccount] -= s.second;
1346 if (wtx.GetDepthInMainChain() >= nMinDepth)
1348 mapAccountBalances[""] += nGeneratedMature;
1349 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1350 if (pwalletMain->mapAddressBook.count(r.first))
1351 mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second;
1353 mapAccountBalances[""] += r.second;
1357 list<CAccountingEntry> acentries;
1358 CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
1359 BOOST_FOREACH(const CAccountingEntry& entry, acentries)
1360 mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
1363 BOOST_FOREACH(const PAIRTYPE(string, int64)& accountBalance, mapAccountBalances) {
1364 ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
1369 Value listsinceblock(const Array& params, bool fHelp)
1372 throw runtime_error(
1373 "listsinceblock [blockid] [target-confirmations]\n"
1374 "Get all transactions in blocks since block [blockid], or all transactions if omitted");
1376 CBlockIndex *pindex = NULL;
1377 int target_confirms = 1;
1379 if (params.size() > 0)
1381 uint256 blockId = 0;
1383 blockId.SetHex(params[0].get_str());
1384 pindex = CBlockLocator(blockId).GetBlockIndex();
1387 if (params.size() > 1)
1389 target_confirms = params[1].get_int();
1391 if (target_confirms < 1)
1392 throw JSONRPCError(-8, "Invalid parameter");
1395 int depth = pindex ? (1 + nBestHeight - pindex->nHeight) : -1;
1399 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++)
1401 CWalletTx tx = (*it).second;
1403 if (depth == -1 || tx.GetDepthInMainChain() < depth)
1404 ListTransactions(tx, "*", 0, true, transactions);
1409 if (target_confirms == 1)
1412 lastblock = hashBestChain;
1416 int target_height = pindexBest->nHeight + 1 - target_confirms;
1419 for (block = pindexBest;
1420 block && block->nHeight > target_height;
1421 block = block->pprev);
1423 lastblock = block ? block->GetBlockHash() : 0;
1427 ret.push_back(Pair("transactions", transactions));
1428 ret.push_back(Pair("lastblock", lastblock.GetHex()));
1433 Value gettransaction(const Array& params, bool fHelp)
1435 if (fHelp || params.size() != 1)
1436 throw runtime_error(
1437 "gettransaction <txid>\n"
1438 "Get detailed information about <txid>");
1441 hash.SetHex(params[0].get_str());
1445 if (!pwalletMain->mapWallet.count(hash))
1446 throw JSONRPCError(-5, "Invalid or non-wallet transaction id");
1447 const CWalletTx& wtx = pwalletMain->mapWallet[hash];
1449 int64 nCredit = wtx.GetCredit();
1450 int64 nDebit = wtx.GetDebit();
1451 int64 nNet = nCredit - nDebit;
1452 int64 nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0);
1454 entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
1456 entry.push_back(Pair("fee", ValueFromAmount(nFee)));
1458 WalletTxToJSON(pwalletMain->mapWallet[hash], entry);
1461 ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details);
1462 entry.push_back(Pair("details", details));
1468 Value backupwallet(const Array& params, bool fHelp)
1470 if (fHelp || params.size() != 1)
1471 throw runtime_error(
1472 "backupwallet <destination>\n"
1473 "Safely copies wallet.dat to destination, which can be a directory or a path with filename.");
1475 string strDest = params[0].get_str();
1476 BackupWallet(*pwalletMain, strDest);
1482 Value keypoolrefill(const Array& params, bool fHelp)
1484 if (pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1485 throw runtime_error(
1487 "Fills the keypool, requires wallet passphrase to be set.");
1488 if (!pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1489 throw runtime_error(
1491 "Fills the keypool.");
1493 if (pwalletMain->IsLocked())
1494 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
1496 pwalletMain->TopUpKeyPool();
1498 if (pwalletMain->GetKeyPoolSize() < GetArg("-keypool", 100))
1499 throw JSONRPCError(-4, "Error refreshing keypool.");
1505 void ThreadTopUpKeyPool(void* parg)
1507 pwalletMain->TopUpKeyPool();
1510 void ThreadCleanWalletPassphrase(void* parg)
1512 int64 nMyWakeTime = GetTime() + *((int*)parg);
1514 if (nWalletUnlockTime == 0)
1516 CRITICAL_BLOCK(cs_nWalletUnlockTime)
1518 nWalletUnlockTime = nMyWakeTime;
1521 while (GetTime() < nWalletUnlockTime)
1522 Sleep(GetTime() - nWalletUnlockTime);
1524 CRITICAL_BLOCK(cs_nWalletUnlockTime)
1526 nWalletUnlockTime = 0;
1531 CRITICAL_BLOCK(cs_nWalletUnlockTime)
1533 if (nWalletUnlockTime < nMyWakeTime)
1534 nWalletUnlockTime = nMyWakeTime;
1540 pwalletMain->Lock();
1545 Value walletpassphrase(const Array& params, bool fHelp)
1547 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1548 throw runtime_error(
1549 "walletpassphrase <passphrase> <timeout>\n"
1550 "Stores the wallet decryption key in memory for <timeout> seconds.");
1553 if (!pwalletMain->IsCrypted())
1554 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
1556 if (!pwalletMain->IsLocked())
1557 throw JSONRPCError(-17, "Error: Wallet is already unlocked.");
1559 // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
1560 SecureString strWalletPass;
1561 strWalletPass.reserve(100);
1562 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1563 // Alternately, find a way to make params[0] mlock()'d to begin with.
1564 strWalletPass = params[0].get_str().c_str();
1566 if (strWalletPass.length() > 0)
1568 if (!pwalletMain->Unlock(strWalletPass))
1569 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1572 throw runtime_error(
1573 "walletpassphrase <passphrase> <timeout>\n"
1574 "Stores the wallet decryption key in memory for <timeout> seconds.");
1576 CreateThread(ThreadTopUpKeyPool, NULL);
1577 int* pnSleepTime = new int(params[1].get_int());
1578 CreateThread(ThreadCleanWalletPassphrase, pnSleepTime);
1584 Value walletpassphrasechange(const Array& params, bool fHelp)
1586 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1587 throw runtime_error(
1588 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1589 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1592 if (!pwalletMain->IsCrypted())
1593 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
1595 // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
1596 // Alternately, find a way to make params[0] mlock()'d to begin with.
1597 SecureString strOldWalletPass;
1598 strOldWalletPass.reserve(100);
1599 strOldWalletPass = params[0].get_str().c_str();
1601 SecureString strNewWalletPass;
1602 strNewWalletPass.reserve(100);
1603 strNewWalletPass = params[1].get_str().c_str();
1605 if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
1606 throw runtime_error(
1607 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1608 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1610 if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
1611 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1617 Value walletlock(const Array& params, bool fHelp)
1619 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
1620 throw runtime_error(
1622 "Removes the wallet encryption key from memory, locking the wallet.\n"
1623 "After calling this method, you will need to call walletpassphrase again\n"
1624 "before being able to call any methods which require the wallet to be unlocked.");
1627 if (!pwalletMain->IsCrypted())
1628 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletlock was called.");
1630 pwalletMain->Lock();
1631 CRITICAL_BLOCK(cs_nWalletUnlockTime)
1633 nWalletUnlockTime = 0;
1640 Value encryptwallet(const Array& params, bool fHelp)
1642 if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
1643 throw runtime_error(
1644 "encryptwallet <passphrase>\n"
1645 "Encrypts the wallet with <passphrase>.");
1648 if (pwalletMain->IsCrypted())
1649 throw JSONRPCError(-15, "Error: running with an encrypted wallet, but encryptwallet was called.");
1652 // shutting down via RPC while the GUI is running does not work (yet):
1653 throw runtime_error("Not Yet Implemented: use GUI to encrypt wallet, not RPC command");
1656 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1657 // Alternately, find a way to make params[0] mlock()'d to begin with.
1658 SecureString strWalletPass;
1659 strWalletPass.reserve(100);
1660 strWalletPass = params[0].get_str().c_str();
1662 if (strWalletPass.length() < 1)
1663 throw runtime_error(
1664 "encryptwallet <passphrase>\n"
1665 "Encrypts the wallet with <passphrase>.");
1667 if (!pwalletMain->EncryptWallet(strWalletPass))
1668 throw JSONRPCError(-16, "Error: Failed to encrypt the wallet.");
1670 // BDB seems to have a bad habit of writing old data into
1671 // slack space in .dat files; that is bad if the old data is
1672 // unencrypted private keys. So:
1673 CreateThread(Shutdown, NULL);
1674 return "wallet encrypted; bitcoin server stopping, restart to run with encrypted wallet";
1678 Value validateaddress(const Array& params, bool fHelp)
1680 if (fHelp || params.size() != 1)
1681 throw runtime_error(
1682 "validateaddress <bitcoinaddress>\n"
1683 "Return information about <bitcoinaddress>.");
1685 CBitcoinAddress address(params[0].get_str());
1686 bool isValid = address.IsValid();
1689 ret.push_back(Pair("isvalid", isValid));
1692 // Call Hash160ToAddress() so we always return current ADDRESSVERSION
1693 // version of the address:
1694 string currentAddress = address.ToString();
1695 ret.push_back(Pair("address", currentAddress));
1696 if (pwalletMain->HaveKey(address))
1698 ret.push_back(Pair("ismine", true));
1699 std::vector<unsigned char> vchPubKey;
1700 pwalletMain->GetPubKey(address, vchPubKey);
1701 ret.push_back(Pair("pubkey", HexStr(vchPubKey)));
1702 std::string strPubKey(vchPubKey.begin(), vchPubKey.end());
1703 ret.push_back(Pair("pubkey58", EncodeBase58(vchPubKey)));
1705 else if (pwalletMain->HaveCScript(address.GetHash160()))
1707 ret.push_back(Pair("isscript", true));
1709 pwalletMain->GetCScript(address.GetHash160(), subscript);
1710 ret.push_back(Pair("ismine", ::IsMine(*pwalletMain, subscript)));
1711 std::vector<CBitcoinAddress> addresses;
1712 txnouttype whichType;
1714 ExtractAddresses(subscript, whichType, addresses, nRequired);
1715 ret.push_back(Pair("script", GetTxnOutputType(whichType)));
1717 BOOST_FOREACH(const CBitcoinAddress& addr, addresses)
1718 a.push_back(addr.ToString());
1719 ret.push_back(Pair("addresses", a));
1720 if (whichType == TX_MULTISIG)
1721 ret.push_back(Pair("sigsrequired", nRequired));
1724 ret.push_back(Pair("ismine", false));
1725 if (pwalletMain->mapAddressBook.count(address))
1726 ret.push_back(Pair("account", pwalletMain->mapAddressBook[address]));
1731 Value getwork(const Array& params, bool fHelp)
1733 if (fHelp || params.size() > 1)
1734 throw runtime_error(
1736 "If [data] is not specified, returns formatted hash data to work on:\n"
1737 " \"midstate\" : precomputed hash state after hashing the first half of the data (DEPRECATED)\n" // deprecated
1738 " \"data\" : block data\n"
1739 " \"hash1\" : formatted hash buffer for second hash (DEPRECATED)\n" // deprecated
1740 " \"target\" : little endian hash target\n"
1741 "If [data] is specified, tries to solve the block and returns true if it was successful.");
1744 throw JSONRPCError(-9, "Bitcoin is not connected!");
1746 if (IsInitialBlockDownload())
1747 throw JSONRPCError(-10, "Bitcoin is downloading blocks...");
1749 typedef map<uint256, pair<CBlock*, CScript> > mapNewBlock_t;
1750 static mapNewBlock_t mapNewBlock;
1751 static vector<CBlock*> vNewBlock;
1752 static CReserveKey reservekey(pwalletMain);
1754 if (params.size() == 0)
1757 static unsigned int nTransactionsUpdatedLast;
1758 static CBlockIndex* pindexPrev;
1759 static int64 nStart;
1760 static CBlock* pblock;
1761 if (pindexPrev != pindexBest ||
1762 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60))
1764 if (pindexPrev != pindexBest)
1766 // Deallocate old blocks since they're obsolete now
1767 mapNewBlock.clear();
1768 BOOST_FOREACH(CBlock* pblock, vNewBlock)
1772 nTransactionsUpdatedLast = nTransactionsUpdated;
1773 pindexPrev = pindexBest;
1777 pblock = CreateNewBlock(reservekey);
1779 throw JSONRPCError(-7, "Out of memory");
1780 vNewBlock.push_back(pblock);
1784 pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
1787 // Update nExtraNonce
1788 static unsigned int nExtraNonce = 0;
1789 IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
1792 mapNewBlock[pblock->hashMerkleRoot] = make_pair(pblock, pblock->vtx[0].vin[0].scriptSig);
1794 // Prebuild hash buffers
1798 FormatHashBuffers(pblock, pmidstate, pdata, phash1);
1800 uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
1803 result.push_back(Pair("midstate", HexStr(BEGIN(pmidstate), END(pmidstate)))); // deprecated
1804 result.push_back(Pair("data", HexStr(BEGIN(pdata), END(pdata))));
1805 result.push_back(Pair("hash1", HexStr(BEGIN(phash1), END(phash1)))); // deprecated
1806 result.push_back(Pair("target", HexStr(BEGIN(hashTarget), END(hashTarget))));
1812 vector<unsigned char> vchData = ParseHex(params[0].get_str());
1813 if (vchData.size() != 128)
1814 throw JSONRPCError(-8, "Invalid parameter");
1815 CBlock* pdata = (CBlock*)&vchData[0];
1818 for (int i = 0; i < 128/4; i++)
1819 ((unsigned int*)pdata)[i] = ByteReverse(((unsigned int*)pdata)[i]);
1822 if (!mapNewBlock.count(pdata->hashMerkleRoot))
1824 CBlock* pblock = mapNewBlock[pdata->hashMerkleRoot].first;
1826 pblock->nTime = pdata->nTime;
1827 pblock->nNonce = pdata->nNonce;
1828 pblock->vtx[0].vin[0].scriptSig = mapNewBlock[pdata->hashMerkleRoot].second;
1829 pblock->hashMerkleRoot = pblock->BuildMerkleTree();
1831 return CheckWork(pblock, *pwalletMain, reservekey);
1836 Value getmemorypool(const Array& params, bool fHelp)
1838 if (fHelp || params.size() > 1)
1839 throw runtime_error(
1840 "getmemorypool [data]\n"
1841 "If [data] is not specified, returns data needed to construct a block to work on:\n"
1842 " \"version\" : block version\n"
1843 " \"previousblockhash\" : hash of current highest block\n"
1844 " \"transactions\" : contents of non-coinbase transactions that should be included in the next block\n"
1845 " \"coinbasevalue\" : maximum allowable input to coinbase transaction, including the generation award and transaction fees\n"
1846 " \"time\" : timestamp appropriate for next block\n"
1847 " \"bits\" : compressed target of next block\n"
1848 "If [data] is specified, tries to solve the block and returns true if it was successful.");
1850 if (params.size() == 0)
1853 throw JSONRPCError(-9, "Bitcoin is not connected!");
1855 if (IsInitialBlockDownload())
1856 throw JSONRPCError(-10, "Bitcoin is downloading blocks...");
1858 static CReserveKey reservekey(pwalletMain);
1861 static unsigned int nTransactionsUpdatedLast;
1862 static CBlockIndex* pindexPrev;
1863 static int64 nStart;
1864 static CBlock* pblock;
1865 if (pindexPrev != pindexBest ||
1866 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 5))
1868 nTransactionsUpdatedLast = nTransactionsUpdated;
1869 pindexPrev = pindexBest;
1875 pblock = CreateNewBlock(reservekey);
1877 throw JSONRPCError(-7, "Out of memory");
1881 pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
1885 BOOST_FOREACH(CTransaction tx, pblock->vtx) {
1892 transactions.push_back(HexStr(ssTx.begin(), ssTx.end()));
1896 result.push_back(Pair("version", pblock->nVersion));
1897 result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex()));
1898 result.push_back(Pair("transactions", transactions));
1899 result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue));
1900 result.push_back(Pair("time", (int64_t)pblock->nTime));
1906 uBits.nBits = htonl((int32_t)pblock->nBits);
1907 result.push_back(Pair("bits", HexStr(BEGIN(uBits.cBits), END(uBits.cBits))));
1914 CDataStream ssBlock(ParseHex(params[0].get_str()));
1918 return ProcessBlock(NULL, &pblock);
1922 Value getblockhash(const Array& params, bool fHelp)
1924 if (fHelp || params.size() != 1)
1925 throw runtime_error(
1926 "getblockhash <index>\n"
1927 "Returns hash of block in best-block-chain at <index>.");
1929 int nHeight = params[0].get_int();
1930 if (nHeight < 0 || nHeight > nBestHeight)
1931 throw runtime_error("Block number out of range.");
1934 CBlockIndex* pblockindex = mapBlockIndex[hashBestChain];
1935 while (pblockindex->nHeight > nHeight)
1936 pblockindex = pblockindex->pprev;
1937 return pblockindex->phashBlock->GetHex();
1940 Value getblock(const Array& params, bool fHelp)
1942 if (fHelp || params.size() != 1)
1943 throw runtime_error(
1945 "Returns details of a block with given block-hash.");
1947 std::string strHash = params[0].get_str();
1948 uint256 hash(strHash);
1950 if (mapBlockIndex.count(hash) == 0)
1951 throw JSONRPCError(-5, "Block not found");
1954 CBlockIndex* pblockindex = mapBlockIndex[hash];
1955 block.ReadFromDisk(pblockindex, true);
1957 return blockToJSON(block, pblockindex);
1974 pair<string, rpcfn_type> pCallTable[] =
1976 make_pair("help", &help),
1977 make_pair("stop", &stop),
1978 make_pair("getblockcount", &getblockcount),
1979 make_pair("getblocknumber", &getblocknumber),
1980 make_pair("getconnectioncount", &getconnectioncount),
1981 make_pair("getdifficulty", &getdifficulty),
1982 make_pair("getgenerate", &getgenerate),
1983 make_pair("setgenerate", &setgenerate),
1984 make_pair("gethashespersec", &gethashespersec),
1985 make_pair("getinfo", &getinfo),
1986 make_pair("getnewaddress", &getnewaddress),
1987 make_pair("getaccountaddress", &getaccountaddress),
1988 make_pair("setaccount", &setaccount),
1989 make_pair("getaccount", &getaccount),
1990 make_pair("getaddressesbyaccount", &getaddressesbyaccount),
1991 make_pair("sendtoaddress", &sendtoaddress),
1992 make_pair("getreceivedbyaddress", &getreceivedbyaddress),
1993 make_pair("getreceivedbyaccount", &getreceivedbyaccount),
1994 make_pair("listreceivedbyaddress", &listreceivedbyaddress),
1995 make_pair("listreceivedbyaccount", &listreceivedbyaccount),
1996 make_pair("backupwallet", &backupwallet),
1997 make_pair("keypoolrefill", &keypoolrefill),
1998 make_pair("walletpassphrase", &walletpassphrase),
1999 make_pair("walletpassphrasechange", &walletpassphrasechange),
2000 make_pair("walletlock", &walletlock),
2001 make_pair("encryptwallet", &encryptwallet),
2002 make_pair("validateaddress", &validateaddress),
2003 make_pair("getbalance", &getbalance),
2004 make_pair("move", &movecmd),
2005 make_pair("sendfrom", &sendfrom),
2006 make_pair("sendmany", &sendmany),
2007 make_pair("addmultisigaddress", &addmultisigaddress),
2008 make_pair("getblock", &getblock),
2009 make_pair("getblockhash", &getblockhash),
2010 make_pair("gettransaction", &gettransaction),
2011 make_pair("listtransactions", &listtransactions),
2012 make_pair("signmessage", &signmessage),
2013 make_pair("verifymessage", &verifymessage),
2014 make_pair("getwork", &getwork),
2015 make_pair("listaccounts", &listaccounts),
2016 make_pair("settxfee", &settxfee),
2017 make_pair("getmemorypool", &getmemorypool),
2018 make_pair("listsinceblock", &listsinceblock),
2019 make_pair("dumpprivkey", &dumpprivkey),
2020 make_pair("importprivkey", &importprivkey)
2022 map<string, rpcfn_type> mapCallTable(pCallTable, pCallTable + sizeof(pCallTable)/sizeof(pCallTable[0]));
2024 string pAllowInSafeMode[] =
2029 "getblocknumber", // deprecated
2030 "getconnectioncount",
2037 "getaccountaddress",
2039 "getaddressesbyaccount",
2048 set<string> setAllowInSafeMode(pAllowInSafeMode, pAllowInSafeMode + sizeof(pAllowInSafeMode)/sizeof(pAllowInSafeMode[0]));
2056 // This ain't Apache. We're just using HTTP header for the length field
2057 // and to be compatible with other JSON-RPC implementations.
2060 string HTTPPost(const string& strMsg, const map<string,string>& mapRequestHeaders)
2063 s << "POST / HTTP/1.1\r\n"
2064 << "User-Agent: bitcoin-json-rpc/" << FormatFullVersion() << "\r\n"
2065 << "Host: 127.0.0.1\r\n"
2066 << "Content-Type: application/json\r\n"
2067 << "Content-Length: " << strMsg.size() << "\r\n"
2068 << "Connection: close\r\n"
2069 << "Accept: application/json\r\n";
2070 BOOST_FOREACH(const PAIRTYPE(string, string)& item, mapRequestHeaders)
2071 s << item.first << ": " << item.second << "\r\n";
2072 s << "\r\n" << strMsg;
2077 string rfc1123Time()
2082 struct tm* now_gmt = gmtime(&now);
2083 string locale(setlocale(LC_TIME, NULL));
2084 setlocale(LC_TIME, "C"); // we want posix (aka "C") weekday/month strings
2085 strftime(buffer, sizeof(buffer), "%a, %d %b %Y %H:%M:%S +0000", now_gmt);
2086 setlocale(LC_TIME, locale.c_str());
2087 return string(buffer);
2090 static string HTTPReply(int nStatus, const string& strMsg)
2093 return strprintf("HTTP/1.0 401 Authorization Required\r\n"
2095 "Server: bitcoin-json-rpc/%s\r\n"
2096 "WWW-Authenticate: Basic realm=\"jsonrpc\"\r\n"
2097 "Content-Type: text/html\r\n"
2098 "Content-Length: 296\r\n"
2100 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\r\n"
2101 "\"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd\">\r\n"
2104 "<TITLE>Error</TITLE>\r\n"
2105 "<META HTTP-EQUIV='Content-Type' CONTENT='text/html; charset=ISO-8859-1'>\r\n"
2107 "<BODY><H1>401 Unauthorized.</H1></BODY>\r\n"
2108 "</HTML>\r\n", rfc1123Time().c_str(), FormatFullVersion().c_str());
2109 const char *cStatus;
2110 if (nStatus == 200) cStatus = "OK";
2111 else if (nStatus == 400) cStatus = "Bad Request";
2112 else if (nStatus == 403) cStatus = "Forbidden";
2113 else if (nStatus == 404) cStatus = "Not Found";
2114 else if (nStatus == 500) cStatus = "Internal Server Error";
2117 "HTTP/1.1 %d %s\r\n"
2119 "Connection: close\r\n"
2120 "Content-Length: %d\r\n"
2121 "Content-Type: application/json\r\n"
2122 "Server: bitcoin-json-rpc/%s\r\n"
2127 rfc1123Time().c_str(),
2129 FormatFullVersion().c_str(),
2133 int ReadHTTPStatus(std::basic_istream<char>& stream)
2136 getline(stream, str);
2137 vector<string> vWords;
2138 boost::split(vWords, str, boost::is_any_of(" "));
2139 if (vWords.size() < 2)
2141 return atoi(vWords[1].c_str());
2144 int ReadHTTPHeader(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet)
2150 std::getline(stream, str);
2151 if (str.empty() || str == "\r")
2153 string::size_type nColon = str.find(":");
2154 if (nColon != string::npos)
2156 string strHeader = str.substr(0, nColon);
2157 boost::trim(strHeader);
2158 boost::to_lower(strHeader);
2159 string strValue = str.substr(nColon+1);
2160 boost::trim(strValue);
2161 mapHeadersRet[strHeader] = strValue;
2162 if (strHeader == "content-length")
2163 nLen = atoi(strValue.c_str());
2169 int ReadHTTP(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet, string& strMessageRet)
2171 mapHeadersRet.clear();
2175 int nStatus = ReadHTTPStatus(stream);
2178 int nLen = ReadHTTPHeader(stream, mapHeadersRet);
2179 if (nLen < 0 || nLen > MAX_SIZE)
2185 vector<char> vch(nLen);
2186 stream.read(&vch[0], nLen);
2187 strMessageRet = string(vch.begin(), vch.end());
2193 bool HTTPAuthorized(map<string, string>& mapHeaders)
2195 string strAuth = mapHeaders["authorization"];
2196 if (strAuth.substr(0,6) != "Basic ")
2198 string strUserPass64 = strAuth.substr(6); boost::trim(strUserPass64);
2199 string strUserPass = DecodeBase64(strUserPass64);
2200 return strUserPass == strRPCUserColonPass;
2204 // JSON-RPC protocol. Bitcoin speaks version 1.0 for maximum compatibility,
2205 // but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
2206 // unspecified (HTTP errors and contents of 'error').
2208 // 1.0 spec: http://json-rpc.org/wiki/specification
2209 // 1.2 spec: http://groups.google.com/group/json-rpc/web/json-rpc-over-http
2210 // http://www.codeproject.com/KB/recipes/JSON_Spirit.aspx
2213 string JSONRPCRequest(const string& strMethod, const Array& params, const Value& id)
2216 request.push_back(Pair("method", strMethod));
2217 request.push_back(Pair("params", params));
2218 request.push_back(Pair("id", id));
2219 return write_string(Value(request), false) + "\n";
2222 string JSONRPCReply(const Value& result, const Value& error, const Value& id)
2225 if (error.type() != null_type)
2226 reply.push_back(Pair("result", Value::null));
2228 reply.push_back(Pair("result", result));
2229 reply.push_back(Pair("error", error));
2230 reply.push_back(Pair("id", id));
2231 return write_string(Value(reply), false) + "\n";
2234 void ErrorReply(std::ostream& stream, const Object& objError, const Value& id)
2236 // Send error reply from json-rpc error object
2238 int code = find_value(objError, "code").get_int();
2239 if (code == -32600) nStatus = 400;
2240 else if (code == -32601) nStatus = 404;
2241 string strReply = JSONRPCReply(Value::null, objError, id);
2242 stream << HTTPReply(nStatus, strReply) << std::flush;
2245 bool ClientAllowed(const string& strAddress)
2247 if (strAddress == asio::ip::address_v4::loopback().to_string())
2249 const vector<string>& vAllow = mapMultiArgs["-rpcallowip"];
2250 BOOST_FOREACH(string strAllow, vAllow)
2251 if (WildcardMatch(strAddress, strAllow))
2258 // IOStream device that speaks SSL but can also speak non-SSL
2260 class SSLIOStreamDevice : public iostreams::device<iostreams::bidirectional> {
2262 SSLIOStreamDevice(SSLStream &streamIn, bool fUseSSLIn) : stream(streamIn)
2264 fUseSSL = fUseSSLIn;
2265 fNeedHandshake = fUseSSLIn;
2268 void handshake(ssl::stream_base::handshake_type role)
2270 if (!fNeedHandshake) return;
2271 fNeedHandshake = false;
2272 stream.handshake(role);
2274 std::streamsize read(char* s, std::streamsize n)
2276 handshake(ssl::stream_base::server); // HTTPS servers read first
2277 if (fUseSSL) return stream.read_some(asio::buffer(s, n));
2278 return stream.next_layer().read_some(asio::buffer(s, n));
2280 std::streamsize write(const char* s, std::streamsize n)
2282 handshake(ssl::stream_base::client); // HTTPS clients write first
2283 if (fUseSSL) return asio::write(stream, asio::buffer(s, n));
2284 return asio::write(stream.next_layer(), asio::buffer(s, n));
2286 bool connect(const std::string& server, const std::string& port)
2288 ip::tcp::resolver resolver(stream.get_io_service());
2289 ip::tcp::resolver::query query(server.c_str(), port.c_str());
2290 ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
2291 ip::tcp::resolver::iterator end;
2292 boost::system::error_code error = asio::error::host_not_found;
2293 while (error && endpoint_iterator != end)
2295 stream.lowest_layer().close();
2296 stream.lowest_layer().connect(*endpoint_iterator++, error);
2304 bool fNeedHandshake;
2310 void ThreadRPCServer(void* parg)
2312 IMPLEMENT_RANDOMIZE_STACK(ThreadRPCServer(parg));
2315 vnThreadsRunning[4]++;
2316 ThreadRPCServer2(parg);
2317 vnThreadsRunning[4]--;
2319 catch (std::exception& e) {
2320 vnThreadsRunning[4]--;
2321 PrintException(&e, "ThreadRPCServer()");
2323 vnThreadsRunning[4]--;
2324 PrintException(NULL, "ThreadRPCServer()");
2326 printf("ThreadRPCServer exiting\n");
2329 void ThreadRPCServer2(void* parg)
2331 printf("ThreadRPCServer started\n");
2333 strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"];
2334 if (strRPCUserColonPass == ":")
2336 string strWhatAmI = "To use bitcoind";
2337 if (mapArgs.count("-server"))
2338 strWhatAmI = strprintf(_("To use the %s option"), "\"-server\"");
2339 else if (mapArgs.count("-daemon"))
2340 strWhatAmI = strprintf(_("To use the %s option"), "\"-daemon\"");
2342 _("Error: %s, you must set rpcpassword=<password>\nin the configuration file: %s\n"
2343 "If the file does not exist, create it with owner-readable-only file permissions.\n"),
2345 GetConfigFile().c_str());
2347 CreateThread(Shutdown, NULL);
2352 bool fUseSSL = GetBoolArg("-rpcssl");
2353 asio::ip::address bindAddress = mapArgs.count("-rpcallowip") ? asio::ip::address_v4::any() : asio::ip::address_v4::loopback();
2355 asio::io_service io_service;
2356 ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", 8332));
2357 ip::tcp::acceptor acceptor(io_service, endpoint);
2359 acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
2362 ssl::context context(io_service, ssl::context::sslv23);
2365 context.set_options(ssl::context::no_sslv2);
2366 filesystem::path certfile = GetArg("-rpcsslcertificatechainfile", "server.cert");
2367 if (!certfile.is_complete()) certfile = filesystem::path(GetDataDir()) / certfile;
2368 if (filesystem::exists(certfile)) context.use_certificate_chain_file(certfile.string().c_str());
2369 else printf("ThreadRPCServer ERROR: missing server certificate file %s\n", certfile.string().c_str());
2370 filesystem::path pkfile = GetArg("-rpcsslprivatekeyfile", "server.pem");
2371 if (!pkfile.is_complete()) pkfile = filesystem::path(GetDataDir()) / pkfile;
2372 if (filesystem::exists(pkfile)) context.use_private_key_file(pkfile.string().c_str(), ssl::context::pem);
2373 else printf("ThreadRPCServer ERROR: missing server private key file %s\n", pkfile.string().c_str());
2375 string ciphers = GetArg("-rpcsslciphers",
2376 "TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH");
2377 SSL_CTX_set_cipher_list(context.impl(), ciphers.c_str());
2381 throw runtime_error("-rpcssl=1, but bitcoin compiled without full openssl libraries.");
2386 // Accept connection
2388 SSLStream sslStream(io_service, context);
2389 SSLIOStreamDevice d(sslStream, fUseSSL);
2390 iostreams::stream<SSLIOStreamDevice> stream(d);
2392 ip::tcp::iostream stream;
2395 ip::tcp::endpoint peer;
2396 vnThreadsRunning[4]--;
2398 acceptor.accept(sslStream.lowest_layer(), peer);
2400 acceptor.accept(*stream.rdbuf(), peer);
2402 vnThreadsRunning[4]++;
2406 // Restrict callers by IP
2407 if (!ClientAllowed(peer.address().to_string()))
2409 // Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake.
2411 stream << HTTPReply(403, "") << std::flush;
2415 map<string, string> mapHeaders;
2418 boost::thread api_caller(ReadHTTP, boost::ref(stream), boost::ref(mapHeaders), boost::ref(strRequest));
2419 if (!api_caller.timed_join(boost::posix_time::seconds(GetArg("-rpctimeout", 30))))
2422 printf("ThreadRPCServer ReadHTTP timeout\n");
2426 // Check authorization
2427 if (mapHeaders.count("authorization") == 0)
2429 stream << HTTPReply(401, "") << std::flush;
2432 if (!HTTPAuthorized(mapHeaders))
2434 // Deter brute-forcing short passwords
2435 if (mapArgs["-rpcpassword"].size() < 15)
2438 stream << HTTPReply(401, "") << std::flush;
2439 printf("ThreadRPCServer incorrect password attempt\n");
2443 Value id = Value::null;
2448 if (!read_string(strRequest, valRequest) || valRequest.type() != obj_type)
2449 throw JSONRPCError(-32700, "Parse error");
2450 const Object& request = valRequest.get_obj();
2452 // Parse id now so errors from here on will have the id
2453 id = find_value(request, "id");
2456 Value valMethod = find_value(request, "method");
2457 if (valMethod.type() == null_type)
2458 throw JSONRPCError(-32600, "Missing method");
2459 if (valMethod.type() != str_type)
2460 throw JSONRPCError(-32600, "Method must be a string");
2461 string strMethod = valMethod.get_str();
2462 if (strMethod != "getwork" && strMethod != "getmemorypool")
2463 printf("ThreadRPCServer method=%s\n", strMethod.c_str());
2466 Value valParams = find_value(request, "params");
2468 if (valParams.type() == array_type)
2469 params = valParams.get_array();
2470 else if (valParams.type() == null_type)
2473 throw JSONRPCError(-32600, "Params must be an array");
2476 map<string, rpcfn_type>::iterator mi = mapCallTable.find(strMethod);
2477 if (mi == mapCallTable.end())
2478 throw JSONRPCError(-32601, "Method not found");
2480 // Observe safe mode
2481 string strWarning = GetWarnings("rpc");
2482 if (strWarning != "" && !GetBoolArg("-disablesafemode") && !setAllowInSafeMode.count(strMethod))
2483 throw JSONRPCError(-2, string("Safe mode: ") + strWarning);
2489 CRITICAL_BLOCK(cs_main)
2490 CRITICAL_BLOCK(pwalletMain->cs_wallet)
2491 result = (*(*mi).second)(params, false);
2494 string strReply = JSONRPCReply(result, Value::null, id);
2495 stream << HTTPReply(200, strReply) << std::flush;
2497 catch (std::exception& e)
2499 ErrorReply(stream, JSONRPCError(-1, e.what()), id);
2502 catch (Object& objError)
2504 ErrorReply(stream, objError, id);
2506 catch (std::exception& e)
2508 ErrorReply(stream, JSONRPCError(-32700, e.what()), id);
2516 Object CallRPC(const string& strMethod, const Array& params)
2518 if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
2519 throw runtime_error(strprintf(
2520 _("You must set rpcpassword=<password> in the configuration file:\n%s\n"
2521 "If the file does not exist, create it with owner-readable-only file permissions."),
2522 GetConfigFile().c_str()));
2524 // Connect to localhost
2525 bool fUseSSL = GetBoolArg("-rpcssl");
2527 asio::io_service io_service;
2528 ssl::context context(io_service, ssl::context::sslv23);
2529 context.set_options(ssl::context::no_sslv2);
2530 SSLStream sslStream(io_service, context);
2531 SSLIOStreamDevice d(sslStream, fUseSSL);
2532 iostreams::stream<SSLIOStreamDevice> stream(d);
2533 if (!d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332")))
2534 throw runtime_error("couldn't connect to server");
2537 throw runtime_error("-rpcssl=1, but bitcoin compiled without full openssl libraries.");
2539 ip::tcp::iostream stream(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332"));
2541 throw runtime_error("couldn't connect to server");
2545 // HTTP basic authentication
2546 string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
2547 map<string, string> mapRequestHeaders;
2548 mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64;
2551 string strRequest = JSONRPCRequest(strMethod, params, 1);
2552 string strPost = HTTPPost(strRequest, mapRequestHeaders);
2553 stream << strPost << std::flush;
2556 map<string, string> mapHeaders;
2558 int nStatus = ReadHTTP(stream, mapHeaders, strReply);
2560 throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
2561 else if (nStatus >= 400 && nStatus != 400 && nStatus != 404 && nStatus != 500)
2562 throw runtime_error(strprintf("server returned HTTP error %d", nStatus));
2563 else if (strReply.empty())
2564 throw runtime_error("no response from server");
2568 if (!read_string(strReply, valReply))
2569 throw runtime_error("couldn't parse reply from server");
2570 const Object& reply = valReply.get_obj();
2572 throw runtime_error("expected reply to have result, error and id properties");
2580 template<typename T>
2581 void ConvertTo(Value& value)
2583 if (value.type() == str_type)
2585 // reinterpret string as unquoted json value
2587 if (!read_string(value.get_str(), value2))
2588 throw runtime_error("type mismatch");
2589 value = value2.get_value<T>();
2593 value = value.get_value<T>();
2597 int CommandLineRPC(int argc, char *argv[])
2604 while (argc > 1 && IsSwitchChar(argv[1][0]))
2612 throw runtime_error("too few parameters");
2613 string strMethod = argv[1];
2615 // Parameters default to strings
2617 for (int i = 2; i < argc; i++)
2618 params.push_back(argv[i]);
2619 int n = params.size();
2622 // Special case non-string parameter types
2624 if (strMethod == "setgenerate" && n > 0) ConvertTo<bool>(params[0]);
2625 if (strMethod == "setgenerate" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2626 if (strMethod == "sendtoaddress" && n > 1) ConvertTo<double>(params[1]);
2627 if (strMethod == "settxfee" && n > 0) ConvertTo<double>(params[0]);
2628 if (strMethod == "getreceivedbyaddress" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2629 if (strMethod == "getreceivedbyaccount" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2630 if (strMethod == "listreceivedbyaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2631 if (strMethod == "listreceivedbyaddress" && n > 1) ConvertTo<bool>(params[1]);
2632 if (strMethod == "listreceivedbyaccount" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2633 if (strMethod == "listreceivedbyaccount" && n > 1) ConvertTo<bool>(params[1]);
2634 if (strMethod == "getbalance" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2635 if (strMethod == "getblockhash" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2636 if (strMethod == "move" && n > 2) ConvertTo<double>(params[2]);
2637 if (strMethod == "move" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2638 if (strMethod == "sendfrom" && n > 2) ConvertTo<double>(params[2]);
2639 if (strMethod == "sendfrom" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2640 if (strMethod == "listtransactions" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2641 if (strMethod == "listtransactions" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2642 if (strMethod == "listaccounts" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2643 if (strMethod == "walletpassphrase" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2644 if (strMethod == "listsinceblock" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2645 if (strMethod == "sendmany" && n > 1)
2647 string s = params[1].get_str();
2649 if (!read_string(s, v) || v.type() != obj_type)
2650 throw runtime_error("type mismatch");
2651 params[1] = v.get_obj();
2653 if (strMethod == "sendmany" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2654 if (strMethod == "addmultisigaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2655 if (strMethod == "addmultisigaddress" && n > 1)
2657 string s = params[1].get_str();
2659 if (!read_string(s, v) || v.type() != array_type)
2660 throw runtime_error("addmultisigaddress: type mismatch "+s);
2661 params[1] = v.get_array();
2665 Object reply = CallRPC(strMethod, params);
2668 const Value& result = find_value(reply, "result");
2669 const Value& error = find_value(reply, "error");
2671 if (error.type() != null_type)
2674 strPrint = "error: " + write_string(error, false);
2675 int code = find_value(error.get_obj(), "code").get_int();
2681 if (result.type() == null_type)
2683 else if (result.type() == str_type)
2684 strPrint = result.get_str();
2686 strPrint = write_string(result, true);
2689 catch (std::exception& e)
2691 strPrint = string("error: ") + e.what();
2696 PrintException(NULL, "CommandLineRPC()");
2701 fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
2710 int main(int argc, char *argv[])
2713 // Turn off microsoft heap dump noise
2714 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
2715 _CrtSetReportFile(_CRT_WARN, CreateFile("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0));
2717 setbuf(stdin, NULL);
2718 setbuf(stdout, NULL);
2719 setbuf(stderr, NULL);
2723 if (argc >= 2 && string(argv[1]) == "-server")
2725 printf("server ready\n");
2726 ThreadRPCServer(NULL);
2730 return CommandLineRPC(argc, argv);
2733 catch (std::exception& e) {
2734 PrintException(&e, "main()");
2736 PrintException(NULL, "main()");