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);
76 int64 AmountFromValue(const Value& value)
78 double dAmount = value.get_real();
79 if (dAmount <= 0.0 || dAmount > 21000000.0)
80 throw JSONRPCError(-3, "Invalid amount");
81 int64 nAmount = roundint64(dAmount * COIN);
82 if (!MoneyRange(nAmount))
83 throw JSONRPCError(-3, "Invalid amount");
87 Value ValueFromAmount(int64 amount)
89 return (double)amount / (double)COIN;
92 void WalletTxToJSON(const CWalletTx& wtx, Object& entry)
94 entry.push_back(Pair("confirmations", wtx.GetDepthInMainChain()));
95 entry.push_back(Pair("txid", wtx.GetHash().GetHex()));
96 entry.push_back(Pair("time", (boost::int64_t)wtx.GetTxTime()));
97 BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue)
98 entry.push_back(Pair(item.first, item.second));
101 string AccountFromValue(const Value& value)
103 string strAccount = value.get_str();
104 if (strAccount == "*")
105 throw JSONRPCError(-11, "Invalid account name");
112 /// Note: This interface may still be subject to change.
116 Value help(const Array& params, bool fHelp)
118 if (fHelp || params.size() > 1)
121 "List commands, or get help for a command.");
124 if (params.size() > 0)
125 strCommand = params[0].get_str();
128 set<rpcfn_type> setDone;
129 for (map<string, rpcfn_type>::iterator mi = mapCallTable.begin(); mi != mapCallTable.end(); ++mi)
131 string strMethod = (*mi).first;
132 // We already filter duplicates, but these deprecated screw up the sort order
133 if (strMethod == "getamountreceived" ||
134 strMethod == "getallreceived" ||
135 strMethod == "getblocknumber" || // deprecated
136 (strMethod.find("label") != string::npos))
138 if (strCommand != "" && strMethod != strCommand)
143 rpcfn_type pfn = (*mi).second;
144 if (setDone.insert(pfn).second)
145 (*pfn)(params, true);
147 catch (std::exception& e)
149 // Help text is returned in an exception
150 string strHelp = string(e.what());
151 if (strCommand == "")
152 if (strHelp.find('\n') != -1)
153 strHelp = strHelp.substr(0, strHelp.find('\n'));
154 strRet += strHelp + "\n";
158 strRet = strprintf("help: unknown command: %s\n", strCommand.c_str());
159 strRet = strRet.substr(0,strRet.size()-1);
164 Value stop(const Array& params, bool fHelp)
166 if (fHelp || params.size() != 0)
169 "Stop bitcoin server.");
171 // Shutdown will take long enough that the response should get back
172 CreateThread(Shutdown, NULL);
173 return "bitcoin server stopping";
175 throw runtime_error("NYI: cannot shut down GUI with RPC command");
180 Value getblockcount(const Array& params, bool fHelp)
182 if (fHelp || params.size() != 0)
185 "Returns the number of blocks in the longest block chain.");
192 Value getblocknumber(const Array& params, bool fHelp)
194 if (fHelp || params.size() != 0)
197 "Deprecated. Use getblockcount.");
203 Value getconnectioncount(const Array& params, bool fHelp)
205 if (fHelp || params.size() != 0)
207 "getconnectioncount\n"
208 "Returns the number of connections to other nodes.");
210 return (int)vNodes.size();
214 double GetDifficulty()
216 // Floating point number that is a multiple of the minimum difficulty,
217 // minimum difficulty = 1.0.
219 if (pindexBest == NULL)
221 int nShift = (pindexBest->nBits >> 24) & 0xff;
224 (double)0x0000ffff / (double)(pindexBest->nBits & 0x00ffffff);
240 Value getdifficulty(const Array& params, bool fHelp)
242 if (fHelp || params.size() != 0)
245 "Returns the proof-of-work difficulty as a multiple of the minimum difficulty.");
247 return GetDifficulty();
251 Value getgenerate(const Array& params, bool fHelp)
253 if (fHelp || params.size() != 0)
256 "Returns true or false.");
258 return (bool)fGenerateBitcoins;
262 Value setgenerate(const Array& params, bool fHelp)
264 if (fHelp || params.size() < 1 || params.size() > 2)
266 "setgenerate <generate> [genproclimit]\n"
267 "<generate> is true or false to turn generation on or off.\n"
268 "Generation is limited to [genproclimit] processors, -1 is unlimited.");
270 bool fGenerate = true;
271 if (params.size() > 0)
272 fGenerate = params[0].get_bool();
274 if (params.size() > 1)
276 int nGenProcLimit = params[1].get_int();
277 fLimitProcessors = (nGenProcLimit != -1);
278 WriteSetting("fLimitProcessors", fLimitProcessors);
279 if (nGenProcLimit != -1)
280 WriteSetting("nLimitProcessors", nLimitProcessors = nGenProcLimit);
281 if (nGenProcLimit == 0)
285 GenerateBitcoins(fGenerate, pwalletMain);
290 Value gethashespersec(const Array& params, bool fHelp)
292 if (fHelp || params.size() != 0)
295 "Returns a recent hashes per second performance measurement while generating.");
297 if (GetTimeMillis() - nHPSTimerStart > 8000)
298 return (boost::int64_t)0;
299 return (boost::int64_t)dHashesPerSec;
303 Value getinfo(const Array& params, bool fHelp)
305 if (fHelp || params.size() != 0)
308 "Returns an object containing various state info.");
311 obj.push_back(Pair("version", (int)CLIENT_VERSION));
312 obj.push_back(Pair("protocolversion",(int)PROTOCOL_VERSION));
313 obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance())));
314 obj.push_back(Pair("blocks", (int)nBestHeight));
315 obj.push_back(Pair("connections", (int)vNodes.size()));
316 obj.push_back(Pair("proxy", (fUseProxy ? addrProxy.ToStringIPPort() : string())));
317 obj.push_back(Pair("generate", (bool)fGenerateBitcoins));
318 obj.push_back(Pair("genproclimit", (int)(fLimitProcessors ? nLimitProcessors : -1)));
319 obj.push_back(Pair("difficulty", (double)GetDifficulty()));
320 obj.push_back(Pair("hashespersec", gethashespersec(params, false)));
321 obj.push_back(Pair("testnet", fTestNet));
322 obj.push_back(Pair("keypoololdest", (boost::int64_t)pwalletMain->GetOldestKeyPoolTime()));
323 obj.push_back(Pair("keypoolsize", pwalletMain->GetKeyPoolSize()));
324 obj.push_back(Pair("paytxfee", ValueFromAmount(nTransactionFee)));
325 if (pwalletMain->IsCrypted())
326 obj.push_back(Pair("unlocked_until", (boost::int64_t)nWalletUnlockTime));
327 obj.push_back(Pair("errors", GetWarnings("statusbar")));
332 Value getnewaddress(const Array& params, bool fHelp)
334 if (fHelp || params.size() > 1)
336 "getnewaddress [account]\n"
337 "Returns a new bitcoin address for receiving payments. "
338 "If [account] is specified (recommended), it is added to the address book "
339 "so payments received with the address will be credited to [account].");
341 // Parse the account first so we don't generate a key if there's an error
343 if (params.size() > 0)
344 strAccount = AccountFromValue(params[0]);
346 if (!pwalletMain->IsLocked())
347 pwalletMain->TopUpKeyPool();
349 // Generate a new key that is added to wallet
350 std::vector<unsigned char> newKey;
351 if (!pwalletMain->GetKeyFromPool(newKey, false))
352 throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
353 CBitcoinAddress address(newKey);
355 pwalletMain->SetAddressBookName(address, strAccount);
357 return address.ToString();
361 CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false)
363 CWalletDB walletdb(pwalletMain->strWalletFile);
366 walletdb.ReadAccount(strAccount, account);
368 bool bKeyUsed = false;
370 // Check if the current key has been used
371 if (!account.vchPubKey.empty())
373 CScript scriptPubKey;
374 scriptPubKey.SetBitcoinAddress(account.vchPubKey);
375 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
376 it != pwalletMain->mapWallet.end() && !account.vchPubKey.empty();
379 const CWalletTx& wtx = (*it).second;
380 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
381 if (txout.scriptPubKey == scriptPubKey)
386 // Generate a new key
387 if (account.vchPubKey.empty() || bForceNew || bKeyUsed)
389 if (!pwalletMain->GetKeyFromPool(account.vchPubKey, false))
390 throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
392 pwalletMain->SetAddressBookName(CBitcoinAddress(account.vchPubKey), strAccount);
393 walletdb.WriteAccount(strAccount, account);
396 return CBitcoinAddress(account.vchPubKey);
399 Value getaccountaddress(const Array& params, bool fHelp)
401 if (fHelp || params.size() != 1)
403 "getaccountaddress <account>\n"
404 "Returns the current bitcoin address for receiving payments to this account.");
406 // Parse the account first so we don't generate a key if there's an error
407 string strAccount = AccountFromValue(params[0]);
411 ret = GetAccountAddress(strAccount).ToString();
418 Value setaccount(const Array& params, bool fHelp)
420 if (fHelp || params.size() < 1 || params.size() > 2)
422 "setaccount <bitcoinaddress> <account>\n"
423 "Sets the account associated with the given address.");
425 CBitcoinAddress address(params[0].get_str());
426 if (!address.IsValid())
427 throw JSONRPCError(-5, "Invalid bitcoin address");
431 if (params.size() > 1)
432 strAccount = AccountFromValue(params[1]);
434 // Detect when changing the account of an address that is the 'unused current key' of another account:
435 if (pwalletMain->mapAddressBook.count(address))
437 string strOldAccount = pwalletMain->mapAddressBook[address];
438 if (address == GetAccountAddress(strOldAccount))
439 GetAccountAddress(strOldAccount, true);
442 pwalletMain->SetAddressBookName(address, strAccount);
448 Value getaccount(const Array& params, bool fHelp)
450 if (fHelp || params.size() != 1)
452 "getaccount <bitcoinaddress>\n"
453 "Returns the account associated with the given address.");
455 CBitcoinAddress address(params[0].get_str());
456 if (!address.IsValid())
457 throw JSONRPCError(-5, "Invalid bitcoin address");
460 map<CBitcoinAddress, string>::iterator mi = pwalletMain->mapAddressBook.find(address);
461 if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.empty())
462 strAccount = (*mi).second;
467 Value getaddressesbyaccount(const Array& params, bool fHelp)
469 if (fHelp || params.size() != 1)
471 "getaddressesbyaccount <account>\n"
472 "Returns the list of addresses for the given account.");
474 string strAccount = AccountFromValue(params[0]);
476 // Find all addresses that have the given account
478 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
480 const CBitcoinAddress& address = item.first;
481 const string& strName = item.second;
482 if (strName == strAccount)
483 ret.push_back(address.ToString());
488 Value settxfee(const Array& params, bool fHelp)
490 if (fHelp || params.size() < 1 || params.size() > 1)
492 "settxfee <amount>\n"
493 "<amount> is a real and is rounded to the nearest 0.00000001");
497 if (params[0].get_real() != 0.0)
498 nAmount = AmountFromValue(params[0]); // rejects 0.0 amounts
500 nTransactionFee = nAmount;
504 Value sendtoaddress(const Array& params, bool fHelp)
506 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
508 "sendtoaddress <bitcoinaddress> <amount> [comment] [comment-to]\n"
509 "<amount> is a real and is rounded to the nearest 0.00000001\n"
510 "requires wallet passphrase to be set with walletpassphrase first");
511 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
513 "sendtoaddress <bitcoinaddress> <amount> [comment] [comment-to]\n"
514 "<amount> is a real and is rounded to the nearest 0.00000001");
516 CBitcoinAddress address(params[0].get_str());
517 if (!address.IsValid())
518 throw JSONRPCError(-5, "Invalid bitcoin address");
521 int64 nAmount = AmountFromValue(params[1]);
525 if (params.size() > 2 && params[2].type() != null_type && !params[2].get_str().empty())
526 wtx.mapValue["comment"] = params[2].get_str();
527 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
528 wtx.mapValue["to"] = params[3].get_str();
530 if (pwalletMain->IsLocked())
531 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
533 string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
535 throw JSONRPCError(-4, strError);
537 return wtx.GetHash().GetHex();
540 static const string strMessageMagic = "Bitcoin Signed Message:\n";
542 Value signmessage(const Array& params, bool fHelp)
544 if (fHelp || params.size() != 2)
546 "signmessage <bitcoinaddress> <message>\n"
547 "Sign a message with the private key of an address");
549 if (pwalletMain->IsLocked())
550 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
552 string strAddress = params[0].get_str();
553 string strMessage = params[1].get_str();
555 CBitcoinAddress addr(strAddress);
557 throw JSONRPCError(-3, "Invalid address");
560 if (!pwalletMain->GetKey(addr, key))
561 throw JSONRPCError(-4, "Private key not available");
563 CDataStream ss(SER_GETHASH);
564 ss << strMessageMagic;
567 vector<unsigned char> vchSig;
568 if (!key.SignCompact(Hash(ss.begin(), ss.end()), vchSig))
569 throw JSONRPCError(-5, "Sign failed");
571 return EncodeBase64(&vchSig[0], vchSig.size());
574 Value verifymessage(const Array& params, bool fHelp)
576 if (fHelp || params.size() != 3)
578 "verifymessage <bitcoinaddress> <signature> <message>\n"
579 "Verify a signed message");
581 string strAddress = params[0].get_str();
582 string strSign = params[1].get_str();
583 string strMessage = params[2].get_str();
585 CBitcoinAddress addr(strAddress);
587 throw JSONRPCError(-3, "Invalid address");
589 bool fInvalid = false;
590 vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid);
593 throw JSONRPCError(-5, "Malformed base64 encoding");
595 CDataStream ss(SER_GETHASH);
596 ss << strMessageMagic;
600 if (!key.SetCompactSignature(Hash(ss.begin(), ss.end()), vchSig))
603 return (CBitcoinAddress(key.GetPubKey()) == addr);
607 Value getreceivedbyaddress(const Array& params, bool fHelp)
609 if (fHelp || params.size() < 1 || params.size() > 2)
611 "getreceivedbyaddress <bitcoinaddress> [minconf=1]\n"
612 "Returns the total amount received by <bitcoinaddress> in transactions with at least [minconf] confirmations.");
615 CBitcoinAddress address = CBitcoinAddress(params[0].get_str());
616 CScript scriptPubKey;
617 if (!address.IsValid())
618 throw JSONRPCError(-5, "Invalid bitcoin address");
619 scriptPubKey.SetBitcoinAddress(address);
620 if (!IsMine(*pwalletMain,scriptPubKey))
623 // Minimum confirmations
625 if (params.size() > 1)
626 nMinDepth = params[1].get_int();
630 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
632 const CWalletTx& wtx = (*it).second;
633 if (wtx.IsCoinBase() || !wtx.IsFinal())
636 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
637 if (txout.scriptPubKey == scriptPubKey)
638 if (wtx.GetDepthInMainChain() >= nMinDepth)
639 nAmount += txout.nValue;
642 return ValueFromAmount(nAmount);
646 void GetAccountAddresses(string strAccount, set<CBitcoinAddress>& setAddress)
648 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
650 const CBitcoinAddress& address = item.first;
651 const string& strName = item.second;
652 if (strName == strAccount)
653 setAddress.insert(address);
658 Value getreceivedbyaccount(const Array& params, bool fHelp)
660 if (fHelp || params.size() < 1 || params.size() > 2)
662 "getreceivedbyaccount <account> [minconf=1]\n"
663 "Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.");
665 // Minimum confirmations
667 if (params.size() > 1)
668 nMinDepth = params[1].get_int();
670 // Get the set of pub keys that have the label
671 string strAccount = AccountFromValue(params[0]);
672 set<CBitcoinAddress> setAddress;
673 GetAccountAddresses(strAccount, setAddress);
677 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
679 const CWalletTx& wtx = (*it).second;
680 if (wtx.IsCoinBase() || !wtx.IsFinal())
683 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
685 CBitcoinAddress address;
686 if (ExtractAddress(txout.scriptPubKey, pwalletMain, address) && setAddress.count(address))
687 if (wtx.GetDepthInMainChain() >= nMinDepth)
688 nAmount += txout.nValue;
692 return (double)nAmount / (double)COIN;
696 int64 GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth)
700 // Tally wallet transactions
701 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
703 const CWalletTx& wtx = (*it).second;
707 int64 nGenerated, nReceived, nSent, nFee;
708 wtx.GetAccountAmounts(strAccount, nGenerated, nReceived, nSent, nFee);
710 if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
711 nBalance += nReceived;
712 nBalance += nGenerated - nSent - nFee;
715 // Tally internal accounting entries
716 nBalance += walletdb.GetAccountCreditDebit(strAccount);
721 int64 GetAccountBalance(const string& strAccount, int nMinDepth)
723 CWalletDB walletdb(pwalletMain->strWalletFile);
724 return GetAccountBalance(walletdb, strAccount, nMinDepth);
728 Value getbalance(const Array& params, bool fHelp)
730 if (fHelp || params.size() > 2)
732 "getbalance [account] [minconf=1]\n"
733 "If [account] is not specified, returns the server's total available balance.\n"
734 "If [account] is specified, returns the balance in the account.");
736 if (params.size() == 0)
737 return ValueFromAmount(pwalletMain->GetBalance());
740 if (params.size() > 1)
741 nMinDepth = params[1].get_int();
743 if (params[0].get_str() == "*") {
744 // Calculate total balance a different way from GetBalance()
745 // (GetBalance() sums up all unspent TxOuts)
746 // getbalance and getbalance '*' should always return the same number.
748 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
750 const CWalletTx& wtx = (*it).second;
754 int64 allGeneratedImmature, allGeneratedMature, allFee;
755 allGeneratedImmature = allGeneratedMature = allFee = 0;
756 string strSentAccount;
757 list<pair<CBitcoinAddress, int64> > listReceived;
758 list<pair<CBitcoinAddress, int64> > listSent;
759 wtx.GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount);
760 if (wtx.GetDepthInMainChain() >= nMinDepth)
761 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listReceived)
762 nBalance += r.second;
763 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listSent)
764 nBalance -= r.second;
766 nBalance += allGeneratedMature;
768 return ValueFromAmount(nBalance);
771 string strAccount = AccountFromValue(params[0]);
773 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
775 return ValueFromAmount(nBalance);
779 Value movecmd(const Array& params, bool fHelp)
781 if (fHelp || params.size() < 3 || params.size() > 5)
783 "move <fromaccount> <toaccount> <amount> [minconf=1] [comment]\n"
784 "Move from one account in your wallet to another.");
786 string strFrom = AccountFromValue(params[0]);
787 string strTo = AccountFromValue(params[1]);
788 int64 nAmount = AmountFromValue(params[2]);
789 if (params.size() > 3)
790 // unused parameter, used to be nMinDepth, keep type-checking it though
791 (void)params[3].get_int();
793 if (params.size() > 4)
794 strComment = params[4].get_str();
796 CWalletDB walletdb(pwalletMain->strWalletFile);
799 int64 nNow = GetAdjustedTime();
802 CAccountingEntry debit;
803 debit.strAccount = strFrom;
804 debit.nCreditDebit = -nAmount;
806 debit.strOtherAccount = strTo;
807 debit.strComment = strComment;
808 walletdb.WriteAccountingEntry(debit);
811 CAccountingEntry credit;
812 credit.strAccount = strTo;
813 credit.nCreditDebit = nAmount;
815 credit.strOtherAccount = strFrom;
816 credit.strComment = strComment;
817 walletdb.WriteAccountingEntry(credit);
819 walletdb.TxnCommit();
825 Value sendfrom(const Array& params, bool fHelp)
827 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
829 "sendfrom <fromaccount> <tobitcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
830 "<amount> is a real and is rounded to the nearest 0.00000001\n"
831 "requires wallet passphrase to be set with walletpassphrase first");
832 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
834 "sendfrom <fromaccount> <tobitcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
835 "<amount> is a real and is rounded to the nearest 0.00000001");
837 string strAccount = AccountFromValue(params[0]);
838 CBitcoinAddress address(params[1].get_str());
839 if (!address.IsValid())
840 throw JSONRPCError(-5, "Invalid bitcoin address");
841 int64 nAmount = AmountFromValue(params[2]);
843 if (params.size() > 3)
844 nMinDepth = params[3].get_int();
847 wtx.strFromAccount = strAccount;
848 if (params.size() > 4 && params[4].type() != null_type && !params[4].get_str().empty())
849 wtx.mapValue["comment"] = params[4].get_str();
850 if (params.size() > 5 && params[5].type() != null_type && !params[5].get_str().empty())
851 wtx.mapValue["to"] = params[5].get_str();
853 if (pwalletMain->IsLocked())
854 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
857 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
858 if (nAmount > nBalance)
859 throw JSONRPCError(-6, "Account has insufficient funds");
862 string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
864 throw JSONRPCError(-4, strError);
866 return wtx.GetHash().GetHex();
870 Value sendmany(const Array& params, bool fHelp)
872 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
874 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
875 "amounts are double-precision floating point numbers\n"
876 "requires wallet passphrase to be set with walletpassphrase first");
877 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
879 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
880 "amounts are double-precision floating point numbers");
882 string strAccount = AccountFromValue(params[0]);
883 Object sendTo = params[1].get_obj();
885 if (params.size() > 2)
886 nMinDepth = params[2].get_int();
889 wtx.strFromAccount = strAccount;
890 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
891 wtx.mapValue["comment"] = params[3].get_str();
893 set<CBitcoinAddress> setAddress;
894 vector<pair<CScript, int64> > vecSend;
896 int64 totalAmount = 0;
897 BOOST_FOREACH(const Pair& s, sendTo)
899 CBitcoinAddress address(s.name_);
900 if (!address.IsValid())
901 throw JSONRPCError(-5, string("Invalid bitcoin address:")+s.name_);
903 if (setAddress.count(address))
904 throw JSONRPCError(-8, string("Invalid parameter, duplicated address: ")+s.name_);
905 setAddress.insert(address);
907 CScript scriptPubKey;
908 scriptPubKey.SetBitcoinAddress(address);
909 int64 nAmount = AmountFromValue(s.value_);
910 totalAmount += nAmount;
912 vecSend.push_back(make_pair(scriptPubKey, nAmount));
915 if (pwalletMain->IsLocked())
916 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
919 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
920 if (totalAmount > nBalance)
921 throw JSONRPCError(-6, "Account has insufficient funds");
924 CReserveKey keyChange(pwalletMain);
925 int64 nFeeRequired = 0;
926 bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired);
929 if (totalAmount + nFeeRequired > pwalletMain->GetBalance())
930 throw JSONRPCError(-6, "Insufficient funds");
931 throw JSONRPCError(-4, "Transaction creation failed");
933 if (!pwalletMain->CommitTransaction(wtx, keyChange))
934 throw JSONRPCError(-4, "Transaction commit failed");
936 return wtx.GetHash().GetHex();
939 Value sendmultisig(const Array& params, bool fHelp)
941 if (fHelp || params.size() < 4 || params.size() > 7)
943 string msg = "sendmultisig <fromaccount> <type> <[\"key\",\"key\"]> <amount> [minconf=1] [comment] [comment-to]\n"
944 "<type> is one of: \"and\", \"or\", \"escrow\"\n"
945 "<keys> is an array of strings (in JSON array format); each key is a bitcoin address, hex or base58 public key\n"
946 "<amount> is a real and is rounded to the nearest 0.00000001";
947 if (pwalletMain->IsCrypted())
948 msg += "\nrequires wallet passphrase to be set with walletpassphrase first";
949 throw runtime_error(msg);
952 string strAccount = AccountFromValue(params[0]);
953 string strType = params[1].get_str();
954 const Array& keys = params[2].get_array();
955 int64 nAmount = AmountFromValue(params[3]);
957 if (params.size() > 4)
958 nMinDepth = params[4].get_int();
961 wtx.strFromAccount = strAccount;
962 if (params.size() > 5 && params[5].type() != null_type && !params[5].get_str().empty())
963 wtx.mapValue["comment"] = params[5].get_str();
964 if (params.size() > 6 && params[6].type() != null_type && !params[6].get_str().empty())
965 wtx.mapValue["to"] = params[6].get_str();
967 if (pwalletMain->IsLocked())
968 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
971 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
972 if (nAmount > nBalance)
973 throw JSONRPCError(-6, "Account has insufficient funds");
975 // Gather public keys
977 if (strType == "and" || strType == "or")
979 else if (strType == "escrow")
982 throw runtime_error("sendmultisig: <type> must be one of: and or and_or");
983 if (keys.size() != nKeysNeeded)
985 strprintf("sendmultisig: wrong number of keys (got %d, need %d)", keys.size(), nKeysNeeded));
986 std::vector<CKey> pubkeys;
987 pubkeys.resize(nKeysNeeded);
988 for (int i = 0; i < nKeysNeeded; i++)
990 const std::string& ks = keys[i].get_str();
991 if (ks.size() == 130) // hex public key
992 pubkeys[i].SetPubKey(ParseHex(ks));
993 else if (ks.size() > 34) // base58-encoded
995 std::vector<unsigned char> vchPubKey;
996 if (DecodeBase58(ks, vchPubKey))
997 pubkeys[i].SetPubKey(vchPubKey);
999 throw runtime_error("Error base58 decoding key: "+ks);
1001 else // bitcoin address for key in this wallet
1003 CBitcoinAddress address(ks);
1004 if (!pwalletMain->GetKey(address, pubkeys[i]))
1005 throw runtime_error(
1006 strprintf("sendmultisig: unknown address: %s",ks.c_str()));
1011 CScript scriptPubKey;
1012 if (strType == "and")
1013 scriptPubKey.SetMultisigAnd(pubkeys);
1014 else if (strType == "or")
1015 scriptPubKey.SetMultisigOr(pubkeys);
1017 scriptPubKey.SetMultisigEscrow(pubkeys);
1019 CReserveKey keyChange(pwalletMain);
1020 int64 nFeeRequired = 0;
1021 bool fCreated = pwalletMain->CreateTransaction(scriptPubKey, nAmount, wtx, keyChange, nFeeRequired);
1024 if (nAmount + nFeeRequired > pwalletMain->GetBalance())
1025 throw JSONRPCError(-6, "Insufficient funds");
1026 throw JSONRPCError(-4, "Transaction creation failed");
1028 if (!pwalletMain->CommitTransaction(wtx, keyChange))
1029 throw JSONRPCError(-4, "Transaction commit failed");
1031 return wtx.GetHash().GetHex();
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;
1063 if (wtx.IsCoinBase() || !wtx.IsFinal())
1066 int nDepth = wtx.GetDepthInMainChain();
1067 if (nDepth < nMinDepth)
1070 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
1072 CBitcoinAddress address;
1073 if (!ExtractAddress(txout.scriptPubKey, pwalletMain, address) || !address.IsValid())
1076 tallyitem& item = mapTally[address];
1077 item.nAmount += txout.nValue;
1078 item.nConf = min(item.nConf, nDepth);
1084 map<string, tallyitem> mapAccountTally;
1085 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
1087 const CBitcoinAddress& address = item.first;
1088 const string& strAccount = item.second;
1089 map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
1090 if (it == mapTally.end() && !fIncludeEmpty)
1094 int nConf = INT_MAX;
1095 if (it != mapTally.end())
1097 nAmount = (*it).second.nAmount;
1098 nConf = (*it).second.nConf;
1103 tallyitem& item = mapAccountTally[strAccount];
1104 item.nAmount += nAmount;
1105 item.nConf = min(item.nConf, nConf);
1110 obj.push_back(Pair("address", address.ToString()));
1111 obj.push_back(Pair("account", strAccount));
1112 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1113 obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf)));
1120 for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
1122 int64 nAmount = (*it).second.nAmount;
1123 int nConf = (*it).second.nConf;
1125 obj.push_back(Pair("account", (*it).first));
1126 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1127 obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf)));
1135 Value listreceivedbyaddress(const Array& params, bool fHelp)
1137 if (fHelp || params.size() > 2)
1138 throw runtime_error(
1139 "listreceivedbyaddress [minconf=1] [includeempty=false]\n"
1140 "[minconf] is the minimum number of confirmations before payments are included.\n"
1141 "[includeempty] whether to include addresses that haven't received any payments.\n"
1142 "Returns an array of objects containing:\n"
1143 " \"address\" : receiving address\n"
1144 " \"account\" : the account of the receiving address\n"
1145 " \"amount\" : total amount received by the address\n"
1146 " \"confirmations\" : number of confirmations of the most recent transaction included");
1148 return ListReceived(params, false);
1151 Value listreceivedbyaccount(const Array& params, bool fHelp)
1153 if (fHelp || params.size() > 2)
1154 throw runtime_error(
1155 "listreceivedbyaccount [minconf=1] [includeempty=false]\n"
1156 "[minconf] is the minimum number of confirmations before payments are included.\n"
1157 "[includeempty] whether to include accounts that haven't received any payments.\n"
1158 "Returns an array of objects containing:\n"
1159 " \"account\" : the account of the receiving addresses\n"
1160 " \"amount\" : total amount received by addresses with this account\n"
1161 " \"confirmations\" : number of confirmations of the most recent transaction included");
1163 return ListReceived(params, true);
1166 void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret)
1168 int64 nGeneratedImmature, nGeneratedMature, nFee;
1169 string strSentAccount;
1170 list<pair<CBitcoinAddress, int64> > listReceived;
1171 list<pair<CBitcoinAddress, int64> > listSent;
1172 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1174 bool fAllAccounts = (strAccount == string("*"));
1176 // Generated blocks assigned to account ""
1177 if ((nGeneratedMature+nGeneratedImmature) != 0 && (fAllAccounts || strAccount == ""))
1180 entry.push_back(Pair("account", string("")));
1181 if (nGeneratedImmature)
1183 entry.push_back(Pair("category", wtx.GetDepthInMainChain() ? "immature" : "orphan"));
1184 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedImmature)));
1188 entry.push_back(Pair("category", "generate"));
1189 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedMature)));
1192 WalletTxToJSON(wtx, entry);
1193 ret.push_back(entry);
1197 if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
1199 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1202 entry.push_back(Pair("account", strSentAccount));
1203 entry.push_back(Pair("address", s.first.ToString()));
1204 entry.push_back(Pair("category", "send"));
1205 entry.push_back(Pair("amount", ValueFromAmount(-s.second)));
1206 entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
1208 WalletTxToJSON(wtx, entry);
1209 ret.push_back(entry);
1214 if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
1215 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1218 if (pwalletMain->mapAddressBook.count(r.first))
1219 account = pwalletMain->mapAddressBook[r.first];
1220 if (fAllAccounts || (account == strAccount))
1223 entry.push_back(Pair("account", account));
1224 entry.push_back(Pair("address", r.first.ToString()));
1225 entry.push_back(Pair("category", "receive"));
1226 entry.push_back(Pair("amount", ValueFromAmount(r.second)));
1228 WalletTxToJSON(wtx, entry);
1229 ret.push_back(entry);
1234 void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret)
1236 bool fAllAccounts = (strAccount == string("*"));
1238 if (fAllAccounts || acentry.strAccount == strAccount)
1241 entry.push_back(Pair("account", acentry.strAccount));
1242 entry.push_back(Pair("category", "move"));
1243 entry.push_back(Pair("time", (boost::int64_t)acentry.nTime));
1244 entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
1245 entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
1246 entry.push_back(Pair("comment", acentry.strComment));
1247 ret.push_back(entry);
1251 Value listtransactions(const Array& params, bool fHelp)
1253 if (fHelp || params.size() > 3)
1254 throw runtime_error(
1255 "listtransactions [account] [count=10] [from=0]\n"
1256 "Returns up to [count] most recent transactions skipping the first [from] transactions for account [account].");
1258 string strAccount = "*";
1259 if (params.size() > 0)
1260 strAccount = params[0].get_str();
1262 if (params.size() > 1)
1263 nCount = params[1].get_int();
1265 if (params.size() > 2)
1266 nFrom = params[2].get_int();
1269 CWalletDB walletdb(pwalletMain->strWalletFile);
1271 // Firs: get all CWalletTx and CAccountingEntry into a sorted-by-time multimap:
1272 typedef pair<CWalletTx*, CAccountingEntry*> TxPair;
1273 typedef multimap<int64, TxPair > TxItems;
1276 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1278 CWalletTx* wtx = &((*it).second);
1279 txByTime.insert(make_pair(wtx->GetTxTime(), TxPair(wtx, (CAccountingEntry*)0)));
1281 list<CAccountingEntry> acentries;
1282 walletdb.ListAccountCreditDebit(strAccount, acentries);
1283 BOOST_FOREACH(CAccountingEntry& entry, acentries)
1285 txByTime.insert(make_pair(entry.nTime, TxPair((CWalletTx*)0, &entry)));
1288 // Now: iterate backwards until we have nCount items to return:
1289 TxItems::reverse_iterator it = txByTime.rbegin();
1290 if (txByTime.size() > nFrom) std::advance(it, nFrom);
1291 for (; it != txByTime.rend(); ++it)
1293 CWalletTx *const pwtx = (*it).second.first;
1295 ListTransactions(*pwtx, strAccount, 0, true, ret);
1296 CAccountingEntry *const pacentry = (*it).second.second;
1298 AcentryToJSON(*pacentry, strAccount, ret);
1300 if (ret.size() >= nCount) break;
1302 // ret is now newest to oldest
1304 // Make sure we return only last nCount items (sends-to-self might give us an extra):
1305 if (ret.size() > nCount)
1307 Array::iterator last = ret.begin();
1308 std::advance(last, nCount);
1309 ret.erase(last, ret.end());
1311 std::reverse(ret.begin(), ret.end()); // oldest to newest
1316 Value listaccounts(const Array& params, bool fHelp)
1318 if (fHelp || params.size() > 1)
1319 throw runtime_error(
1320 "listaccounts [minconf=1]\n"
1321 "Returns Object that has account names as keys, account balances as values.");
1324 if (params.size() > 0)
1325 nMinDepth = params[0].get_int();
1327 map<string, int64> mapAccountBalances;
1328 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& entry, pwalletMain->mapAddressBook) {
1329 if (pwalletMain->HaveKey(entry.first)) // This address belongs to me
1330 mapAccountBalances[entry.second] = 0;
1333 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1335 const CWalletTx& wtx = (*it).second;
1336 int64 nGeneratedImmature, nGeneratedMature, nFee;
1337 string strSentAccount;
1338 list<pair<CBitcoinAddress, int64> > listReceived;
1339 list<pair<CBitcoinAddress, int64> > listSent;
1340 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1341 mapAccountBalances[strSentAccount] -= nFee;
1342 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1343 mapAccountBalances[strSentAccount] -= s.second;
1344 if (wtx.GetDepthInMainChain() >= nMinDepth)
1346 mapAccountBalances[""] += nGeneratedMature;
1347 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1348 if (pwalletMain->mapAddressBook.count(r.first))
1349 mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second;
1351 mapAccountBalances[""] += r.second;
1355 list<CAccountingEntry> acentries;
1356 CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
1357 BOOST_FOREACH(const CAccountingEntry& entry, acentries)
1358 mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
1361 BOOST_FOREACH(const PAIRTYPE(string, int64)& accountBalance, mapAccountBalances) {
1362 ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
1367 Value listsinceblock(const Array& params, bool fHelp)
1370 throw runtime_error(
1371 "listsinceblock [blockid] [target-confirmations]\n"
1372 "Get all transactions in blocks since block [blockid], or all transactions if omitted");
1374 CBlockIndex *pindex = NULL;
1375 int target_confirms = 1;
1377 if (params.size() > 0)
1379 uint256 blockId = 0;
1381 blockId.SetHex(params[0].get_str());
1382 pindex = CBlockLocator(blockId).GetBlockIndex();
1385 if (params.size() > 1)
1387 target_confirms = params[1].get_int();
1389 if (target_confirms < 1)
1390 throw JSONRPCError(-8, "Invalid parameter");
1393 int depth = pindex ? (1 + nBestHeight - pindex->nHeight) : -1;
1397 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++)
1399 CWalletTx tx = (*it).second;
1401 if (depth == -1 || tx.GetDepthInMainChain() < depth)
1402 ListTransactions(tx, "*", 0, true, transactions);
1407 if (target_confirms == 1)
1410 lastblock = hashBestChain;
1414 int target_height = pindexBest->nHeight + 1 - target_confirms;
1417 for (block = pindexBest;
1418 block && block->nHeight > target_height;
1419 block = block->pprev);
1421 lastblock = block ? block->GetBlockHash() : 0;
1425 ret.push_back(Pair("transactions", transactions));
1426 ret.push_back(Pair("lastblock", lastblock.GetHex()));
1431 Value gettransaction(const Array& params, bool fHelp)
1433 if (fHelp || params.size() != 1)
1434 throw runtime_error(
1435 "gettransaction <txid>\n"
1436 "Get detailed information about <txid>");
1439 hash.SetHex(params[0].get_str());
1443 if (!pwalletMain->mapWallet.count(hash))
1444 throw JSONRPCError(-5, "Invalid or non-wallet transaction id");
1445 const CWalletTx& wtx = pwalletMain->mapWallet[hash];
1447 int64 nCredit = wtx.GetCredit();
1448 int64 nDebit = wtx.GetDebit();
1449 int64 nNet = nCredit - nDebit;
1450 int64 nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0);
1452 entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
1454 entry.push_back(Pair("fee", ValueFromAmount(nFee)));
1456 WalletTxToJSON(pwalletMain->mapWallet[hash], entry);
1459 ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details);
1460 entry.push_back(Pair("details", details));
1466 Value backupwallet(const Array& params, bool fHelp)
1468 if (fHelp || params.size() != 1)
1469 throw runtime_error(
1470 "backupwallet <destination>\n"
1471 "Safely copies wallet.dat to destination, which can be a directory or a path with filename.");
1473 string strDest = params[0].get_str();
1474 BackupWallet(*pwalletMain, strDest);
1480 Value keypoolrefill(const Array& params, bool fHelp)
1482 if (pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1483 throw runtime_error(
1485 "Fills the keypool, requires wallet passphrase to be set.");
1486 if (!pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1487 throw runtime_error(
1489 "Fills the keypool.");
1491 if (pwalletMain->IsLocked())
1492 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
1494 pwalletMain->TopUpKeyPool();
1496 if (pwalletMain->GetKeyPoolSize() < GetArg("-keypool", 100))
1497 throw JSONRPCError(-4, "Error refreshing keypool.");
1503 void ThreadTopUpKeyPool(void* parg)
1505 pwalletMain->TopUpKeyPool();
1508 void ThreadCleanWalletPassphrase(void* parg)
1510 int64 nMyWakeTime = GetTime() + *((int*)parg);
1512 if (nWalletUnlockTime == 0)
1514 CRITICAL_BLOCK(cs_nWalletUnlockTime)
1516 nWalletUnlockTime = nMyWakeTime;
1519 while (GetTime() < nWalletUnlockTime)
1520 Sleep(GetTime() - nWalletUnlockTime);
1522 CRITICAL_BLOCK(cs_nWalletUnlockTime)
1524 nWalletUnlockTime = 0;
1529 CRITICAL_BLOCK(cs_nWalletUnlockTime)
1531 if (nWalletUnlockTime < nMyWakeTime)
1532 nWalletUnlockTime = nMyWakeTime;
1538 pwalletMain->Lock();
1543 Value walletpassphrase(const Array& params, bool fHelp)
1545 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1546 throw runtime_error(
1547 "walletpassphrase <passphrase> <timeout>\n"
1548 "Stores the wallet decryption key in memory for <timeout> seconds.");
1551 if (!pwalletMain->IsCrypted())
1552 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
1554 if (!pwalletMain->IsLocked())
1555 throw JSONRPCError(-17, "Error: Wallet is already unlocked.");
1557 // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
1558 SecureString strWalletPass;
1559 strWalletPass.reserve(100);
1560 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1561 // Alternately, find a way to make params[0] mlock()'d to begin with.
1562 strWalletPass = params[0].get_str().c_str();
1564 if (strWalletPass.length() > 0)
1566 if (!pwalletMain->Unlock(strWalletPass))
1567 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1570 throw runtime_error(
1571 "walletpassphrase <passphrase> <timeout>\n"
1572 "Stores the wallet decryption key in memory for <timeout> seconds.");
1574 CreateThread(ThreadTopUpKeyPool, NULL);
1575 int* pnSleepTime = new int(params[1].get_int());
1576 CreateThread(ThreadCleanWalletPassphrase, pnSleepTime);
1582 Value walletpassphrasechange(const Array& params, bool fHelp)
1584 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1585 throw runtime_error(
1586 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1587 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1590 if (!pwalletMain->IsCrypted())
1591 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
1593 // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
1594 // Alternately, find a way to make params[0] mlock()'d to begin with.
1595 SecureString strOldWalletPass;
1596 strOldWalletPass.reserve(100);
1597 strOldWalletPass = params[0].get_str().c_str();
1599 SecureString strNewWalletPass;
1600 strNewWalletPass.reserve(100);
1601 strNewWalletPass = params[1].get_str().c_str();
1603 if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
1604 throw runtime_error(
1605 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1606 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1608 if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
1609 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1615 Value walletlock(const Array& params, bool fHelp)
1617 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
1618 throw runtime_error(
1620 "Removes the wallet encryption key from memory, locking the wallet.\n"
1621 "After calling this method, you will need to call walletpassphrase again\n"
1622 "before being able to call any methods which require the wallet to be unlocked.");
1625 if (!pwalletMain->IsCrypted())
1626 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletlock was called.");
1628 pwalletMain->Lock();
1629 CRITICAL_BLOCK(cs_nWalletUnlockTime)
1631 nWalletUnlockTime = 0;
1638 Value encryptwallet(const Array& params, bool fHelp)
1640 if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
1641 throw runtime_error(
1642 "encryptwallet <passphrase>\n"
1643 "Encrypts the wallet with <passphrase>.");
1646 if (pwalletMain->IsCrypted())
1647 throw JSONRPCError(-15, "Error: running with an encrypted wallet, but encryptwallet was called.");
1650 // shutting down via RPC while the GUI is running does not work (yet):
1651 throw runtime_error("Not Yet Implemented: use GUI to encrypt wallet, not RPC command");
1654 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1655 // Alternately, find a way to make params[0] mlock()'d to begin with.
1656 SecureString strWalletPass;
1657 strWalletPass.reserve(100);
1658 strWalletPass = params[0].get_str().c_str();
1660 if (strWalletPass.length() < 1)
1661 throw runtime_error(
1662 "encryptwallet <passphrase>\n"
1663 "Encrypts the wallet with <passphrase>.");
1665 if (!pwalletMain->EncryptWallet(strWalletPass))
1666 throw JSONRPCError(-16, "Error: Failed to encrypt the wallet.");
1668 // BDB seems to have a bad habit of writing old data into
1669 // slack space in .dat files; that is bad if the old data is
1670 // unencrypted private keys. So:
1671 CreateThread(Shutdown, NULL);
1672 return "wallet encrypted; bitcoin server stopping, restart to run with encrypted wallet";
1676 Value validateaddress(const Array& params, bool fHelp)
1678 if (fHelp || params.size() != 1)
1679 throw runtime_error(
1680 "validateaddress <bitcoinaddress>\n"
1681 "Return information about <bitcoinaddress>.");
1683 CBitcoinAddress address(params[0].get_str());
1684 bool isValid = address.IsValid();
1687 ret.push_back(Pair("isvalid", isValid));
1690 // Call Hash160ToAddress() so we always return current ADDRESSVERSION
1691 // version of the address:
1692 string currentAddress = address.ToString();
1693 ret.push_back(Pair("address", currentAddress));
1694 if (pwalletMain->HaveKey(address))
1696 ret.push_back(Pair("ismine", true));
1697 std::vector<unsigned char> vchPubKey;
1698 pwalletMain->GetPubKey(address, vchPubKey);
1699 ret.push_back(Pair("pubkey", HexStr(vchPubKey)));
1700 std::string strPubKey(vchPubKey.begin(), vchPubKey.end());
1701 ret.push_back(Pair("pubkey58", EncodeBase58(vchPubKey)));
1704 ret.push_back(Pair("ismine", false));
1705 if (pwalletMain->mapAddressBook.count(address))
1706 ret.push_back(Pair("account", pwalletMain->mapAddressBook[address]));
1711 Value getwork(const Array& params, bool fHelp)
1713 if (fHelp || params.size() > 1)
1714 throw runtime_error(
1716 "If [data] is not specified, returns formatted hash data to work on:\n"
1717 " \"midstate\" : precomputed hash state after hashing the first half of the data (DEPRECATED)\n" // deprecated
1718 " \"data\" : block data\n"
1719 " \"hash1\" : formatted hash buffer for second hash (DEPRECATED)\n" // deprecated
1720 " \"target\" : little endian hash target\n"
1721 "If [data] is specified, tries to solve the block and returns true if it was successful.");
1724 throw JSONRPCError(-9, "Bitcoin is not connected!");
1726 if (IsInitialBlockDownload())
1727 throw JSONRPCError(-10, "Bitcoin is downloading blocks...");
1729 typedef map<uint256, pair<CBlock*, CScript> > mapNewBlock_t;
1730 static mapNewBlock_t mapNewBlock;
1731 static vector<CBlock*> vNewBlock;
1732 static CReserveKey reservekey(pwalletMain);
1734 if (params.size() == 0)
1737 static unsigned int nTransactionsUpdatedLast;
1738 static CBlockIndex* pindexPrev;
1739 static int64 nStart;
1740 static CBlock* pblock;
1741 if (pindexPrev != pindexBest ||
1742 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60))
1744 if (pindexPrev != pindexBest)
1746 // Deallocate old blocks since they're obsolete now
1747 mapNewBlock.clear();
1748 BOOST_FOREACH(CBlock* pblock, vNewBlock)
1752 nTransactionsUpdatedLast = nTransactionsUpdated;
1753 pindexPrev = pindexBest;
1757 pblock = CreateNewBlock(reservekey);
1759 throw JSONRPCError(-7, "Out of memory");
1760 vNewBlock.push_back(pblock);
1764 pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
1767 // Update nExtraNonce
1768 static unsigned int nExtraNonce = 0;
1769 IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
1772 mapNewBlock[pblock->hashMerkleRoot] = make_pair(pblock, pblock->vtx[0].vin[0].scriptSig);
1774 // Prebuild hash buffers
1778 FormatHashBuffers(pblock, pmidstate, pdata, phash1);
1780 uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
1783 result.push_back(Pair("midstate", HexStr(BEGIN(pmidstate), END(pmidstate)))); // deprecated
1784 result.push_back(Pair("data", HexStr(BEGIN(pdata), END(pdata))));
1785 result.push_back(Pair("hash1", HexStr(BEGIN(phash1), END(phash1)))); // deprecated
1786 result.push_back(Pair("target", HexStr(BEGIN(hashTarget), END(hashTarget))));
1792 vector<unsigned char> vchData = ParseHex(params[0].get_str());
1793 if (vchData.size() != 128)
1794 throw JSONRPCError(-8, "Invalid parameter");
1795 CBlock* pdata = (CBlock*)&vchData[0];
1798 for (int i = 0; i < 128/4; i++)
1799 ((unsigned int*)pdata)[i] = ByteReverse(((unsigned int*)pdata)[i]);
1802 if (!mapNewBlock.count(pdata->hashMerkleRoot))
1804 CBlock* pblock = mapNewBlock[pdata->hashMerkleRoot].first;
1806 pblock->nTime = pdata->nTime;
1807 pblock->nNonce = pdata->nNonce;
1808 pblock->vtx[0].vin[0].scriptSig = mapNewBlock[pdata->hashMerkleRoot].second;
1809 pblock->hashMerkleRoot = pblock->BuildMerkleTree();
1811 return CheckWork(pblock, *pwalletMain, reservekey);
1816 Value getmemorypool(const Array& params, bool fHelp)
1818 if (fHelp || params.size() > 1)
1819 throw runtime_error(
1820 "getmemorypool [data]\n"
1821 "If [data] is not specified, returns data needed to construct a block to work on:\n"
1822 " \"version\" : block version\n"
1823 " \"previousblockhash\" : hash of current highest block\n"
1824 " \"transactions\" : contents of non-coinbase transactions that should be included in the next block\n"
1825 " \"coinbasevalue\" : maximum allowable input to coinbase transaction, including the generation award and transaction fees\n"
1826 " \"time\" : timestamp appropriate for next block\n"
1827 " \"bits\" : compressed target of next block\n"
1828 "If [data] is specified, tries to solve the block and returns true if it was successful.");
1830 if (params.size() == 0)
1833 throw JSONRPCError(-9, "Bitcoin is not connected!");
1835 if (IsInitialBlockDownload())
1836 throw JSONRPCError(-10, "Bitcoin is downloading blocks...");
1838 static CReserveKey reservekey(pwalletMain);
1841 static unsigned int nTransactionsUpdatedLast;
1842 static CBlockIndex* pindexPrev;
1843 static int64 nStart;
1844 static CBlock* pblock;
1845 if (pindexPrev != pindexBest ||
1846 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 5))
1848 nTransactionsUpdatedLast = nTransactionsUpdated;
1849 pindexPrev = pindexBest;
1855 pblock = CreateNewBlock(reservekey);
1857 throw JSONRPCError(-7, "Out of memory");
1861 pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
1865 BOOST_FOREACH(CTransaction tx, pblock->vtx) {
1872 transactions.push_back(HexStr(ssTx.begin(), ssTx.end()));
1876 result.push_back(Pair("version", pblock->nVersion));
1877 result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex()));
1878 result.push_back(Pair("transactions", transactions));
1879 result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue));
1880 result.push_back(Pair("time", (int64_t)pblock->nTime));
1886 uBits.nBits = htonl((int32_t)pblock->nBits);
1887 result.push_back(Pair("bits", HexStr(BEGIN(uBits.cBits), END(uBits.cBits))));
1894 CDataStream ssBlock(ParseHex(params[0].get_str()));
1898 return ProcessBlock(NULL, &pblock);
1916 pair<string, rpcfn_type> pCallTable[] =
1918 make_pair("help", &help),
1919 make_pair("stop", &stop),
1920 make_pair("getblockcount", &getblockcount),
1921 make_pair("getblocknumber", &getblocknumber),
1922 make_pair("getconnectioncount", &getconnectioncount),
1923 make_pair("getdifficulty", &getdifficulty),
1924 make_pair("getgenerate", &getgenerate),
1925 make_pair("setgenerate", &setgenerate),
1926 make_pair("gethashespersec", &gethashespersec),
1927 make_pair("getinfo", &getinfo),
1928 make_pair("getnewaddress", &getnewaddress),
1929 make_pair("getaccountaddress", &getaccountaddress),
1930 make_pair("setaccount", &setaccount),
1931 make_pair("getaccount", &getaccount),
1932 make_pair("getaddressesbyaccount", &getaddressesbyaccount),
1933 make_pair("sendtoaddress", &sendtoaddress),
1934 make_pair("getreceivedbyaddress", &getreceivedbyaddress),
1935 make_pair("getreceivedbyaccount", &getreceivedbyaccount),
1936 make_pair("listreceivedbyaddress", &listreceivedbyaddress),
1937 make_pair("listreceivedbyaccount", &listreceivedbyaccount),
1938 make_pair("backupwallet", &backupwallet),
1939 make_pair("keypoolrefill", &keypoolrefill),
1940 make_pair("walletpassphrase", &walletpassphrase),
1941 make_pair("walletpassphrasechange", &walletpassphrasechange),
1942 make_pair("walletlock", &walletlock),
1943 make_pair("encryptwallet", &encryptwallet),
1944 make_pair("validateaddress", &validateaddress),
1945 make_pair("getbalance", &getbalance),
1946 make_pair("move", &movecmd),
1947 make_pair("sendfrom", &sendfrom),
1948 make_pair("sendmany", &sendmany),
1949 make_pair("sendmultisig", &sendmultisig),
1950 make_pair("gettransaction", &gettransaction),
1951 make_pair("listtransactions", &listtransactions),
1952 make_pair("signmessage", &signmessage),
1953 make_pair("verifymessage", &verifymessage),
1954 make_pair("getwork", &getwork),
1955 make_pair("listaccounts", &listaccounts),
1956 make_pair("settxfee", &settxfee),
1957 make_pair("getmemorypool", &getmemorypool),
1958 make_pair("listsinceblock", &listsinceblock),
1959 make_pair("dumpprivkey", &dumpprivkey),
1960 make_pair("importprivkey", &importprivkey)
1962 map<string, rpcfn_type> mapCallTable(pCallTable, pCallTable + sizeof(pCallTable)/sizeof(pCallTable[0]));
1964 string pAllowInSafeMode[] =
1969 "getblocknumber", // deprecated
1970 "getconnectioncount",
1977 "getaccountaddress",
1979 "getaddressesbyaccount",
1988 set<string> setAllowInSafeMode(pAllowInSafeMode, pAllowInSafeMode + sizeof(pAllowInSafeMode)/sizeof(pAllowInSafeMode[0]));
1996 // This ain't Apache. We're just using HTTP header for the length field
1997 // and to be compatible with other JSON-RPC implementations.
2000 string HTTPPost(const string& strMsg, const map<string,string>& mapRequestHeaders)
2003 s << "POST / HTTP/1.1\r\n"
2004 << "User-Agent: bitcoin-json-rpc/" << FormatFullVersion() << "\r\n"
2005 << "Host: 127.0.0.1\r\n"
2006 << "Content-Type: application/json\r\n"
2007 << "Content-Length: " << strMsg.size() << "\r\n"
2008 << "Connection: close\r\n"
2009 << "Accept: application/json\r\n";
2010 BOOST_FOREACH(const PAIRTYPE(string, string)& item, mapRequestHeaders)
2011 s << item.first << ": " << item.second << "\r\n";
2012 s << "\r\n" << strMsg;
2017 string rfc1123Time()
2022 struct tm* now_gmt = gmtime(&now);
2023 string locale(setlocale(LC_TIME, NULL));
2024 setlocale(LC_TIME, "C"); // we want posix (aka "C") weekday/month strings
2025 strftime(buffer, sizeof(buffer), "%a, %d %b %Y %H:%M:%S +0000", now_gmt);
2026 setlocale(LC_TIME, locale.c_str());
2027 return string(buffer);
2030 static string HTTPReply(int nStatus, const string& strMsg)
2033 return strprintf("HTTP/1.0 401 Authorization Required\r\n"
2035 "Server: bitcoin-json-rpc/%s\r\n"
2036 "WWW-Authenticate: Basic realm=\"jsonrpc\"\r\n"
2037 "Content-Type: text/html\r\n"
2038 "Content-Length: 296\r\n"
2040 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\r\n"
2041 "\"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd\">\r\n"
2044 "<TITLE>Error</TITLE>\r\n"
2045 "<META HTTP-EQUIV='Content-Type' CONTENT='text/html; charset=ISO-8859-1'>\r\n"
2047 "<BODY><H1>401 Unauthorized.</H1></BODY>\r\n"
2048 "</HTML>\r\n", rfc1123Time().c_str(), FormatFullVersion().c_str());
2049 const char *cStatus;
2050 if (nStatus == 200) cStatus = "OK";
2051 else if (nStatus == 400) cStatus = "Bad Request";
2052 else if (nStatus == 403) cStatus = "Forbidden";
2053 else if (nStatus == 404) cStatus = "Not Found";
2054 else if (nStatus == 500) cStatus = "Internal Server Error";
2057 "HTTP/1.1 %d %s\r\n"
2059 "Connection: close\r\n"
2060 "Content-Length: %d\r\n"
2061 "Content-Type: application/json\r\n"
2062 "Server: bitcoin-json-rpc/%s\r\n"
2067 rfc1123Time().c_str(),
2069 FormatFullVersion().c_str(),
2073 int ReadHTTPStatus(std::basic_istream<char>& stream)
2076 getline(stream, str);
2077 vector<string> vWords;
2078 boost::split(vWords, str, boost::is_any_of(" "));
2079 if (vWords.size() < 2)
2081 return atoi(vWords[1].c_str());
2084 int ReadHTTPHeader(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet)
2090 std::getline(stream, str);
2091 if (str.empty() || str == "\r")
2093 string::size_type nColon = str.find(":");
2094 if (nColon != string::npos)
2096 string strHeader = str.substr(0, nColon);
2097 boost::trim(strHeader);
2098 boost::to_lower(strHeader);
2099 string strValue = str.substr(nColon+1);
2100 boost::trim(strValue);
2101 mapHeadersRet[strHeader] = strValue;
2102 if (strHeader == "content-length")
2103 nLen = atoi(strValue.c_str());
2109 int ReadHTTP(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet, string& strMessageRet)
2111 mapHeadersRet.clear();
2115 int nStatus = ReadHTTPStatus(stream);
2118 int nLen = ReadHTTPHeader(stream, mapHeadersRet);
2119 if (nLen < 0 || nLen > MAX_SIZE)
2125 vector<char> vch(nLen);
2126 stream.read(&vch[0], nLen);
2127 strMessageRet = string(vch.begin(), vch.end());
2133 bool HTTPAuthorized(map<string, string>& mapHeaders)
2135 string strAuth = mapHeaders["authorization"];
2136 if (strAuth.substr(0,6) != "Basic ")
2138 string strUserPass64 = strAuth.substr(6); boost::trim(strUserPass64);
2139 string strUserPass = DecodeBase64(strUserPass64);
2140 return strUserPass == strRPCUserColonPass;
2144 // JSON-RPC protocol. Bitcoin speaks version 1.0 for maximum compatibility,
2145 // but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
2146 // unspecified (HTTP errors and contents of 'error').
2148 // 1.0 spec: http://json-rpc.org/wiki/specification
2149 // 1.2 spec: http://groups.google.com/group/json-rpc/web/json-rpc-over-http
2150 // http://www.codeproject.com/KB/recipes/JSON_Spirit.aspx
2153 string JSONRPCRequest(const string& strMethod, const Array& params, const Value& id)
2156 request.push_back(Pair("method", strMethod));
2157 request.push_back(Pair("params", params));
2158 request.push_back(Pair("id", id));
2159 return write_string(Value(request), false) + "\n";
2162 string JSONRPCReply(const Value& result, const Value& error, const Value& id)
2165 if (error.type() != null_type)
2166 reply.push_back(Pair("result", Value::null));
2168 reply.push_back(Pair("result", result));
2169 reply.push_back(Pair("error", error));
2170 reply.push_back(Pair("id", id));
2171 return write_string(Value(reply), false) + "\n";
2174 void ErrorReply(std::ostream& stream, const Object& objError, const Value& id)
2176 // Send error reply from json-rpc error object
2178 int code = find_value(objError, "code").get_int();
2179 if (code == -32600) nStatus = 400;
2180 else if (code == -32601) nStatus = 404;
2181 string strReply = JSONRPCReply(Value::null, objError, id);
2182 stream << HTTPReply(nStatus, strReply) << std::flush;
2185 bool ClientAllowed(const string& strAddress)
2187 if (strAddress == asio::ip::address_v4::loopback().to_string())
2189 const vector<string>& vAllow = mapMultiArgs["-rpcallowip"];
2190 BOOST_FOREACH(string strAllow, vAllow)
2191 if (WildcardMatch(strAddress, strAllow))
2198 // IOStream device that speaks SSL but can also speak non-SSL
2200 class SSLIOStreamDevice : public iostreams::device<iostreams::bidirectional> {
2202 SSLIOStreamDevice(SSLStream &streamIn, bool fUseSSLIn) : stream(streamIn)
2204 fUseSSL = fUseSSLIn;
2205 fNeedHandshake = fUseSSLIn;
2208 void handshake(ssl::stream_base::handshake_type role)
2210 if (!fNeedHandshake) return;
2211 fNeedHandshake = false;
2212 stream.handshake(role);
2214 std::streamsize read(char* s, std::streamsize n)
2216 handshake(ssl::stream_base::server); // HTTPS servers read first
2217 if (fUseSSL) return stream.read_some(asio::buffer(s, n));
2218 return stream.next_layer().read_some(asio::buffer(s, n));
2220 std::streamsize write(const char* s, std::streamsize n)
2222 handshake(ssl::stream_base::client); // HTTPS clients write first
2223 if (fUseSSL) return asio::write(stream, asio::buffer(s, n));
2224 return asio::write(stream.next_layer(), asio::buffer(s, n));
2226 bool connect(const std::string& server, const std::string& port)
2228 ip::tcp::resolver resolver(stream.get_io_service());
2229 ip::tcp::resolver::query query(server.c_str(), port.c_str());
2230 ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
2231 ip::tcp::resolver::iterator end;
2232 boost::system::error_code error = asio::error::host_not_found;
2233 while (error && endpoint_iterator != end)
2235 stream.lowest_layer().close();
2236 stream.lowest_layer().connect(*endpoint_iterator++, error);
2244 bool fNeedHandshake;
2250 void ThreadRPCServer(void* parg)
2252 IMPLEMENT_RANDOMIZE_STACK(ThreadRPCServer(parg));
2255 vnThreadsRunning[4]++;
2256 ThreadRPCServer2(parg);
2257 vnThreadsRunning[4]--;
2259 catch (std::exception& e) {
2260 vnThreadsRunning[4]--;
2261 PrintException(&e, "ThreadRPCServer()");
2263 vnThreadsRunning[4]--;
2264 PrintException(NULL, "ThreadRPCServer()");
2266 printf("ThreadRPCServer exiting\n");
2269 void ThreadRPCServer2(void* parg)
2271 printf("ThreadRPCServer started\n");
2273 strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"];
2274 if (strRPCUserColonPass == ":")
2276 string strWhatAmI = "To use bitcoind";
2277 if (mapArgs.count("-server"))
2278 strWhatAmI = strprintf(_("To use the %s option"), "\"-server\"");
2279 else if (mapArgs.count("-daemon"))
2280 strWhatAmI = strprintf(_("To use the %s option"), "\"-daemon\"");
2282 _("Error: %s, you must set rpcpassword=<password>\nin the configuration file: %s\n"
2283 "If the file does not exist, create it with owner-readable-only file permissions.\n"),
2285 GetConfigFile().c_str());
2287 CreateThread(Shutdown, NULL);
2292 bool fUseSSL = GetBoolArg("-rpcssl");
2293 asio::ip::address bindAddress = mapArgs.count("-rpcallowip") ? asio::ip::address_v4::any() : asio::ip::address_v4::loopback();
2295 asio::io_service io_service;
2296 ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", 8332));
2297 ip::tcp::acceptor acceptor(io_service, endpoint);
2299 acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
2302 ssl::context context(io_service, ssl::context::sslv23);
2305 context.set_options(ssl::context::no_sslv2);
2306 filesystem::path certfile = GetArg("-rpcsslcertificatechainfile", "server.cert");
2307 if (!certfile.is_complete()) certfile = filesystem::path(GetDataDir()) / certfile;
2308 if (filesystem::exists(certfile)) context.use_certificate_chain_file(certfile.string().c_str());
2309 else printf("ThreadRPCServer ERROR: missing server certificate file %s\n", certfile.string().c_str());
2310 filesystem::path pkfile = GetArg("-rpcsslprivatekeyfile", "server.pem");
2311 if (!pkfile.is_complete()) pkfile = filesystem::path(GetDataDir()) / pkfile;
2312 if (filesystem::exists(pkfile)) context.use_private_key_file(pkfile.string().c_str(), ssl::context::pem);
2313 else printf("ThreadRPCServer ERROR: missing server private key file %s\n", pkfile.string().c_str());
2315 string ciphers = GetArg("-rpcsslciphers",
2316 "TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH");
2317 SSL_CTX_set_cipher_list(context.impl(), ciphers.c_str());
2321 throw runtime_error("-rpcssl=1, but bitcoin compiled without full openssl libraries.");
2326 // Accept connection
2328 SSLStream sslStream(io_service, context);
2329 SSLIOStreamDevice d(sslStream, fUseSSL);
2330 iostreams::stream<SSLIOStreamDevice> stream(d);
2332 ip::tcp::iostream stream;
2335 ip::tcp::endpoint peer;
2336 vnThreadsRunning[4]--;
2338 acceptor.accept(sslStream.lowest_layer(), peer);
2340 acceptor.accept(*stream.rdbuf(), peer);
2342 vnThreadsRunning[4]++;
2346 // Restrict callers by IP
2347 if (!ClientAllowed(peer.address().to_string()))
2349 // Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake.
2351 stream << HTTPReply(403, "") << std::flush;
2355 map<string, string> mapHeaders;
2358 boost::thread api_caller(ReadHTTP, boost::ref(stream), boost::ref(mapHeaders), boost::ref(strRequest));
2359 if (!api_caller.timed_join(boost::posix_time::seconds(GetArg("-rpctimeout", 30))))
2362 printf("ThreadRPCServer ReadHTTP timeout\n");
2366 // Check authorization
2367 if (mapHeaders.count("authorization") == 0)
2369 stream << HTTPReply(401, "") << std::flush;
2372 if (!HTTPAuthorized(mapHeaders))
2374 // Deter brute-forcing short passwords
2375 if (mapArgs["-rpcpassword"].size() < 15)
2378 stream << HTTPReply(401, "") << std::flush;
2379 printf("ThreadRPCServer incorrect password attempt\n");
2383 Value id = Value::null;
2388 if (!read_string(strRequest, valRequest) || valRequest.type() != obj_type)
2389 throw JSONRPCError(-32700, "Parse error");
2390 const Object& request = valRequest.get_obj();
2392 // Parse id now so errors from here on will have the id
2393 id = find_value(request, "id");
2396 Value valMethod = find_value(request, "method");
2397 if (valMethod.type() == null_type)
2398 throw JSONRPCError(-32600, "Missing method");
2399 if (valMethod.type() != str_type)
2400 throw JSONRPCError(-32600, "Method must be a string");
2401 string strMethod = valMethod.get_str();
2402 if (strMethod != "getwork" && strMethod != "getmemorypool")
2403 printf("ThreadRPCServer method=%s\n", strMethod.c_str());
2406 Value valParams = find_value(request, "params");
2408 if (valParams.type() == array_type)
2409 params = valParams.get_array();
2410 else if (valParams.type() == null_type)
2413 throw JSONRPCError(-32600, "Params must be an array");
2416 map<string, rpcfn_type>::iterator mi = mapCallTable.find(strMethod);
2417 if (mi == mapCallTable.end())
2418 throw JSONRPCError(-32601, "Method not found");
2420 // Observe safe mode
2421 string strWarning = GetWarnings("rpc");
2422 if (strWarning != "" && !GetBoolArg("-disablesafemode") && !setAllowInSafeMode.count(strMethod))
2423 throw JSONRPCError(-2, string("Safe mode: ") + strWarning);
2429 CRITICAL_BLOCK(cs_main)
2430 CRITICAL_BLOCK(pwalletMain->cs_wallet)
2431 result = (*(*mi).second)(params, false);
2434 string strReply = JSONRPCReply(result, Value::null, id);
2435 stream << HTTPReply(200, strReply) << std::flush;
2437 catch (std::exception& e)
2439 ErrorReply(stream, JSONRPCError(-1, e.what()), id);
2442 catch (Object& objError)
2444 ErrorReply(stream, objError, id);
2446 catch (std::exception& e)
2448 ErrorReply(stream, JSONRPCError(-32700, e.what()), id);
2456 Object CallRPC(const string& strMethod, const Array& params)
2458 if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
2459 throw runtime_error(strprintf(
2460 _("You must set rpcpassword=<password> in the configuration file:\n%s\n"
2461 "If the file does not exist, create it with owner-readable-only file permissions."),
2462 GetConfigFile().c_str()));
2464 // Connect to localhost
2465 bool fUseSSL = GetBoolArg("-rpcssl");
2467 asio::io_service io_service;
2468 ssl::context context(io_service, ssl::context::sslv23);
2469 context.set_options(ssl::context::no_sslv2);
2470 SSLStream sslStream(io_service, context);
2471 SSLIOStreamDevice d(sslStream, fUseSSL);
2472 iostreams::stream<SSLIOStreamDevice> stream(d);
2473 if (!d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332")))
2474 throw runtime_error("couldn't connect to server");
2477 throw runtime_error("-rpcssl=1, but bitcoin compiled without full openssl libraries.");
2479 ip::tcp::iostream stream(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332"));
2481 throw runtime_error("couldn't connect to server");
2485 // HTTP basic authentication
2486 string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
2487 map<string, string> mapRequestHeaders;
2488 mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64;
2491 string strRequest = JSONRPCRequest(strMethod, params, 1);
2492 string strPost = HTTPPost(strRequest, mapRequestHeaders);
2493 stream << strPost << std::flush;
2496 map<string, string> mapHeaders;
2498 int nStatus = ReadHTTP(stream, mapHeaders, strReply);
2500 throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
2501 else if (nStatus >= 400 && nStatus != 400 && nStatus != 404 && nStatus != 500)
2502 throw runtime_error(strprintf("server returned HTTP error %d", nStatus));
2503 else if (strReply.empty())
2504 throw runtime_error("no response from server");
2508 if (!read_string(strReply, valReply))
2509 throw runtime_error("couldn't parse reply from server");
2510 const Object& reply = valReply.get_obj();
2512 throw runtime_error("expected reply to have result, error and id properties");
2520 template<typename T>
2521 void ConvertTo(Value& value)
2523 if (value.type() == str_type)
2525 // reinterpret string as unquoted json value
2527 if (!read_string(value.get_str(), value2))
2528 throw runtime_error("type mismatch");
2529 value = value2.get_value<T>();
2533 value = value.get_value<T>();
2537 int CommandLineRPC(int argc, char *argv[])
2544 while (argc > 1 && IsSwitchChar(argv[1][0]))
2552 throw runtime_error("too few parameters");
2553 string strMethod = argv[1];
2555 // Parameters default to strings
2557 for (int i = 2; i < argc; i++)
2558 params.push_back(argv[i]);
2559 int n = params.size();
2562 // Special case non-string parameter types
2564 if (strMethod == "setgenerate" && n > 0) ConvertTo<bool>(params[0]);
2565 if (strMethod == "setgenerate" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2566 if (strMethod == "sendtoaddress" && n > 1) ConvertTo<double>(params[1]);
2567 if (strMethod == "settxfee" && n > 0) ConvertTo<double>(params[0]);
2568 if (strMethod == "getreceivedbyaddress" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2569 if (strMethod == "getreceivedbyaccount" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2570 if (strMethod == "listreceivedbyaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2571 if (strMethod == "listreceivedbyaddress" && n > 1) ConvertTo<bool>(params[1]);
2572 if (strMethod == "listreceivedbyaccount" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2573 if (strMethod == "listreceivedbyaccount" && n > 1) ConvertTo<bool>(params[1]);
2574 if (strMethod == "getbalance" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2575 if (strMethod == "move" && n > 2) ConvertTo<double>(params[2]);
2576 if (strMethod == "move" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2577 if (strMethod == "sendfrom" && n > 2) ConvertTo<double>(params[2]);
2578 if (strMethod == "sendfrom" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2579 if (strMethod == "listtransactions" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2580 if (strMethod == "listtransactions" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2581 if (strMethod == "listaccounts" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2582 if (strMethod == "walletpassphrase" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2583 if (strMethod == "listsinceblock" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2584 if (strMethod == "sendmany" && n > 1)
2586 string s = params[1].get_str();
2588 if (!read_string(s, v) || v.type() != obj_type)
2589 throw runtime_error("type mismatch");
2590 params[1] = v.get_obj();
2592 if (strMethod == "sendmany" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2593 if (strMethod == "sendmultisig" && n > 2)
2595 string s = params[2].get_str();
2597 if (!read_string(s, v) || v.type() != array_type)
2598 throw runtime_error("sendmultisig: type mismatch "+s);
2599 params[2] = v.get_array();
2601 if (strMethod == "sendmultisig" && n > 3) ConvertTo<double>(params[3]);
2602 if (strMethod == "sendmultisig" && n > 4) ConvertTo<boost::int64_t>(params[4]);
2605 Object reply = CallRPC(strMethod, params);
2608 const Value& result = find_value(reply, "result");
2609 const Value& error = find_value(reply, "error");
2611 if (error.type() != null_type)
2614 strPrint = "error: " + write_string(error, false);
2615 int code = find_value(error.get_obj(), "code").get_int();
2621 if (result.type() == null_type)
2623 else if (result.type() == str_type)
2624 strPrint = result.get_str();
2626 strPrint = write_string(result, true);
2629 catch (std::exception& e)
2631 strPrint = string("error: ") + e.what();
2636 PrintException(NULL, "CommandLineRPC()");
2641 fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
2650 int main(int argc, char *argv[])
2653 // Turn off microsoft heap dump noise
2654 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
2655 _CrtSetReportFile(_CRT_WARN, CreateFile("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0));
2657 setbuf(stdin, NULL);
2658 setbuf(stdout, NULL);
2659 setbuf(stderr, NULL);
2663 if (argc >= 2 && string(argv[1]) == "-server")
2665 printf("server ready\n");
2666 ThreadRPCServer(NULL);
2670 return CommandLineRPC(argc, argv);
2673 catch (std::exception& e) {
2674 PrintException(&e, "main()");
2676 PrintException(NULL, "main()");