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();
951 Value ListReceived(const Array& params, bool fByAccounts)
953 // Minimum confirmations
955 if (params.size() > 0)
956 nMinDepth = params[0].get_int();
958 // Whether to include empty accounts
959 bool fIncludeEmpty = false;
960 if (params.size() > 1)
961 fIncludeEmpty = params[1].get_bool();
964 map<CBitcoinAddress, tallyitem> mapTally;
965 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
967 const CWalletTx& wtx = (*it).second;
968 if (wtx.IsCoinBase() || !wtx.IsFinal())
971 int nDepth = wtx.GetDepthInMainChain();
972 if (nDepth < nMinDepth)
975 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
977 CBitcoinAddress address;
978 if (!ExtractAddress(txout.scriptPubKey, pwalletMain, address) || !address.IsValid())
981 tallyitem& item = mapTally[address];
982 item.nAmount += txout.nValue;
983 item.nConf = min(item.nConf, nDepth);
989 map<string, tallyitem> mapAccountTally;
990 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
992 const CBitcoinAddress& address = item.first;
993 const string& strAccount = item.second;
994 map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
995 if (it == mapTally.end() && !fIncludeEmpty)
1000 if (it != mapTally.end())
1002 nAmount = (*it).second.nAmount;
1003 nConf = (*it).second.nConf;
1008 tallyitem& item = mapAccountTally[strAccount];
1009 item.nAmount += nAmount;
1010 item.nConf = min(item.nConf, nConf);
1015 obj.push_back(Pair("address", address.ToString()));
1016 obj.push_back(Pair("account", strAccount));
1017 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1018 obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf)));
1025 for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
1027 int64 nAmount = (*it).second.nAmount;
1028 int nConf = (*it).second.nConf;
1030 obj.push_back(Pair("account", (*it).first));
1031 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1032 obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf)));
1040 Value listreceivedbyaddress(const Array& params, bool fHelp)
1042 if (fHelp || params.size() > 2)
1043 throw runtime_error(
1044 "listreceivedbyaddress [minconf=1] [includeempty=false]\n"
1045 "[minconf] is the minimum number of confirmations before payments are included.\n"
1046 "[includeempty] whether to include addresses that haven't received any payments.\n"
1047 "Returns an array of objects containing:\n"
1048 " \"address\" : receiving address\n"
1049 " \"account\" : the account of the receiving address\n"
1050 " \"amount\" : total amount received by the address\n"
1051 " \"confirmations\" : number of confirmations of the most recent transaction included");
1053 return ListReceived(params, false);
1056 Value listreceivedbyaccount(const Array& params, bool fHelp)
1058 if (fHelp || params.size() > 2)
1059 throw runtime_error(
1060 "listreceivedbyaccount [minconf=1] [includeempty=false]\n"
1061 "[minconf] is the minimum number of confirmations before payments are included.\n"
1062 "[includeempty] whether to include accounts that haven't received any payments.\n"
1063 "Returns an array of objects containing:\n"
1064 " \"account\" : the account of the receiving addresses\n"
1065 " \"amount\" : total amount received by addresses with this account\n"
1066 " \"confirmations\" : number of confirmations of the most recent transaction included");
1068 return ListReceived(params, true);
1071 void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret)
1073 int64 nGeneratedImmature, nGeneratedMature, nFee;
1074 string strSentAccount;
1075 list<pair<CBitcoinAddress, int64> > listReceived;
1076 list<pair<CBitcoinAddress, int64> > listSent;
1077 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1079 bool fAllAccounts = (strAccount == string("*"));
1081 // Generated blocks assigned to account ""
1082 if ((nGeneratedMature+nGeneratedImmature) != 0 && (fAllAccounts || strAccount == ""))
1085 entry.push_back(Pair("account", string("")));
1086 if (nGeneratedImmature)
1088 entry.push_back(Pair("category", wtx.GetDepthInMainChain() ? "immature" : "orphan"));
1089 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedImmature)));
1093 entry.push_back(Pair("category", "generate"));
1094 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedMature)));
1097 WalletTxToJSON(wtx, entry);
1098 ret.push_back(entry);
1102 if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
1104 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1107 entry.push_back(Pair("account", strSentAccount));
1108 entry.push_back(Pair("address", s.first.ToString()));
1109 entry.push_back(Pair("category", "send"));
1110 entry.push_back(Pair("amount", ValueFromAmount(-s.second)));
1111 entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
1113 WalletTxToJSON(wtx, entry);
1114 ret.push_back(entry);
1119 if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
1120 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1123 if (pwalletMain->mapAddressBook.count(r.first))
1124 account = pwalletMain->mapAddressBook[r.first];
1125 if (fAllAccounts || (account == strAccount))
1128 entry.push_back(Pair("account", account));
1129 entry.push_back(Pair("address", r.first.ToString()));
1130 entry.push_back(Pair("category", "receive"));
1131 entry.push_back(Pair("amount", ValueFromAmount(r.second)));
1133 WalletTxToJSON(wtx, entry);
1134 ret.push_back(entry);
1139 void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret)
1141 bool fAllAccounts = (strAccount == string("*"));
1143 if (fAllAccounts || acentry.strAccount == strAccount)
1146 entry.push_back(Pair("account", acentry.strAccount));
1147 entry.push_back(Pair("category", "move"));
1148 entry.push_back(Pair("time", (boost::int64_t)acentry.nTime));
1149 entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
1150 entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
1151 entry.push_back(Pair("comment", acentry.strComment));
1152 ret.push_back(entry);
1156 Value listtransactions(const Array& params, bool fHelp)
1158 if (fHelp || params.size() > 3)
1159 throw runtime_error(
1160 "listtransactions [account] [count=10] [from=0]\n"
1161 "Returns up to [count] most recent transactions skipping the first [from] transactions for account [account].");
1163 string strAccount = "*";
1164 if (params.size() > 0)
1165 strAccount = params[0].get_str();
1167 if (params.size() > 1)
1168 nCount = params[1].get_int();
1170 if (params.size() > 2)
1171 nFrom = params[2].get_int();
1174 CWalletDB walletdb(pwalletMain->strWalletFile);
1176 // Firs: get all CWalletTx and CAccountingEntry into a sorted-by-time multimap:
1177 typedef pair<CWalletTx*, CAccountingEntry*> TxPair;
1178 typedef multimap<int64, TxPair > TxItems;
1181 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1183 CWalletTx* wtx = &((*it).second);
1184 txByTime.insert(make_pair(wtx->GetTxTime(), TxPair(wtx, (CAccountingEntry*)0)));
1186 list<CAccountingEntry> acentries;
1187 walletdb.ListAccountCreditDebit(strAccount, acentries);
1188 BOOST_FOREACH(CAccountingEntry& entry, acentries)
1190 txByTime.insert(make_pair(entry.nTime, TxPair((CWalletTx*)0, &entry)));
1193 // Now: iterate backwards until we have nCount items to return:
1194 TxItems::reverse_iterator it = txByTime.rbegin();
1195 if (txByTime.size() > nFrom) std::advance(it, nFrom);
1196 for (; it != txByTime.rend(); ++it)
1198 CWalletTx *const pwtx = (*it).second.first;
1200 ListTransactions(*pwtx, strAccount, 0, true, ret);
1201 CAccountingEntry *const pacentry = (*it).second.second;
1203 AcentryToJSON(*pacentry, strAccount, ret);
1205 if (ret.size() >= nCount) break;
1207 // ret is now newest to oldest
1209 // Make sure we return only last nCount items (sends-to-self might give us an extra):
1210 if (ret.size() > nCount)
1212 Array::iterator last = ret.begin();
1213 std::advance(last, nCount);
1214 ret.erase(last, ret.end());
1216 std::reverse(ret.begin(), ret.end()); // oldest to newest
1221 Value listaccounts(const Array& params, bool fHelp)
1223 if (fHelp || params.size() > 1)
1224 throw runtime_error(
1225 "listaccounts [minconf=1]\n"
1226 "Returns Object that has account names as keys, account balances as values.");
1229 if (params.size() > 0)
1230 nMinDepth = params[0].get_int();
1232 map<string, int64> mapAccountBalances;
1233 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& entry, pwalletMain->mapAddressBook) {
1234 if (pwalletMain->HaveKey(entry.first)) // This address belongs to me
1235 mapAccountBalances[entry.second] = 0;
1238 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1240 const CWalletTx& wtx = (*it).second;
1241 int64 nGeneratedImmature, nGeneratedMature, nFee;
1242 string strSentAccount;
1243 list<pair<CBitcoinAddress, int64> > listReceived;
1244 list<pair<CBitcoinAddress, int64> > listSent;
1245 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1246 mapAccountBalances[strSentAccount] -= nFee;
1247 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1248 mapAccountBalances[strSentAccount] -= s.second;
1249 if (wtx.GetDepthInMainChain() >= nMinDepth)
1251 mapAccountBalances[""] += nGeneratedMature;
1252 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1253 if (pwalletMain->mapAddressBook.count(r.first))
1254 mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second;
1256 mapAccountBalances[""] += r.second;
1260 list<CAccountingEntry> acentries;
1261 CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
1262 BOOST_FOREACH(const CAccountingEntry& entry, acentries)
1263 mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
1266 BOOST_FOREACH(const PAIRTYPE(string, int64)& accountBalance, mapAccountBalances) {
1267 ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
1272 Value listsinceblock(const Array& params, bool fHelp)
1275 throw runtime_error(
1276 "listsinceblock [blockid] [target-confirmations]\n"
1277 "Get all transactions in blocks since block [blockid], or all transactions if omitted");
1279 CBlockIndex *pindex = NULL;
1280 int target_confirms = 1;
1282 if (params.size() > 0)
1284 uint256 blockId = 0;
1286 blockId.SetHex(params[0].get_str());
1287 pindex = CBlockLocator(blockId).GetBlockIndex();
1290 if (params.size() > 1)
1292 target_confirms = params[1].get_int();
1294 if (target_confirms < 1)
1295 throw JSONRPCError(-8, "Invalid parameter");
1298 int depth = pindex ? (1 + nBestHeight - pindex->nHeight) : -1;
1302 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++)
1304 CWalletTx tx = (*it).second;
1306 if (depth == -1 || tx.GetDepthInMainChain() < depth)
1307 ListTransactions(tx, "*", 0, true, transactions);
1312 if (target_confirms == 1)
1315 lastblock = hashBestChain;
1319 int target_height = pindexBest->nHeight + 1 - target_confirms;
1322 for (block = pindexBest;
1323 block && block->nHeight > target_height;
1324 block = block->pprev);
1326 lastblock = block ? block->GetBlockHash() : 0;
1330 ret.push_back(Pair("transactions", transactions));
1331 ret.push_back(Pair("lastblock", lastblock.GetHex()));
1336 Value gettransaction(const Array& params, bool fHelp)
1338 if (fHelp || params.size() != 1)
1339 throw runtime_error(
1340 "gettransaction <txid>\n"
1341 "Get detailed information about <txid>");
1344 hash.SetHex(params[0].get_str());
1348 if (!pwalletMain->mapWallet.count(hash))
1349 throw JSONRPCError(-5, "Invalid or non-wallet transaction id");
1350 const CWalletTx& wtx = pwalletMain->mapWallet[hash];
1352 int64 nCredit = wtx.GetCredit();
1353 int64 nDebit = wtx.GetDebit();
1354 int64 nNet = nCredit - nDebit;
1355 int64 nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0);
1357 entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
1359 entry.push_back(Pair("fee", ValueFromAmount(nFee)));
1361 WalletTxToJSON(pwalletMain->mapWallet[hash], entry);
1364 ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details);
1365 entry.push_back(Pair("details", details));
1371 Value backupwallet(const Array& params, bool fHelp)
1373 if (fHelp || params.size() != 1)
1374 throw runtime_error(
1375 "backupwallet <destination>\n"
1376 "Safely copies wallet.dat to destination, which can be a directory or a path with filename.");
1378 string strDest = params[0].get_str();
1379 BackupWallet(*pwalletMain, strDest);
1385 Value keypoolrefill(const Array& params, bool fHelp)
1387 if (pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1388 throw runtime_error(
1390 "Fills the keypool, requires wallet passphrase to be set.");
1391 if (!pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1392 throw runtime_error(
1394 "Fills the keypool.");
1396 if (pwalletMain->IsLocked())
1397 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
1399 pwalletMain->TopUpKeyPool();
1401 if (pwalletMain->GetKeyPoolSize() < GetArg("-keypool", 100))
1402 throw JSONRPCError(-4, "Error refreshing keypool.");
1408 void ThreadTopUpKeyPool(void* parg)
1410 pwalletMain->TopUpKeyPool();
1413 void ThreadCleanWalletPassphrase(void* parg)
1415 int64 nMyWakeTime = GetTime() + *((int*)parg);
1417 if (nWalletUnlockTime == 0)
1419 CRITICAL_BLOCK(cs_nWalletUnlockTime)
1421 nWalletUnlockTime = nMyWakeTime;
1424 while (GetTime() < nWalletUnlockTime)
1425 Sleep(GetTime() - nWalletUnlockTime);
1427 CRITICAL_BLOCK(cs_nWalletUnlockTime)
1429 nWalletUnlockTime = 0;
1434 CRITICAL_BLOCK(cs_nWalletUnlockTime)
1436 if (nWalletUnlockTime < nMyWakeTime)
1437 nWalletUnlockTime = nMyWakeTime;
1443 pwalletMain->Lock();
1448 Value walletpassphrase(const Array& params, bool fHelp)
1450 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1451 throw runtime_error(
1452 "walletpassphrase <passphrase> <timeout>\n"
1453 "Stores the wallet decryption key in memory for <timeout> seconds.");
1456 if (!pwalletMain->IsCrypted())
1457 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
1459 if (!pwalletMain->IsLocked())
1460 throw JSONRPCError(-17, "Error: Wallet is already unlocked.");
1462 // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
1463 SecureString strWalletPass;
1464 strWalletPass.reserve(100);
1465 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1466 // Alternately, find a way to make params[0] mlock()'d to begin with.
1467 strWalletPass = params[0].get_str().c_str();
1469 if (strWalletPass.length() > 0)
1471 if (!pwalletMain->Unlock(strWalletPass))
1472 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1475 throw runtime_error(
1476 "walletpassphrase <passphrase> <timeout>\n"
1477 "Stores the wallet decryption key in memory for <timeout> seconds.");
1479 CreateThread(ThreadTopUpKeyPool, NULL);
1480 int* pnSleepTime = new int(params[1].get_int());
1481 CreateThread(ThreadCleanWalletPassphrase, pnSleepTime);
1487 Value walletpassphrasechange(const Array& params, bool fHelp)
1489 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1490 throw runtime_error(
1491 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1492 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1495 if (!pwalletMain->IsCrypted())
1496 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
1498 // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
1499 // Alternately, find a way to make params[0] mlock()'d to begin with.
1500 SecureString strOldWalletPass;
1501 strOldWalletPass.reserve(100);
1502 strOldWalletPass = params[0].get_str().c_str();
1504 SecureString strNewWalletPass;
1505 strNewWalletPass.reserve(100);
1506 strNewWalletPass = params[1].get_str().c_str();
1508 if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
1509 throw runtime_error(
1510 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1511 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1513 if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
1514 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1520 Value walletlock(const Array& params, bool fHelp)
1522 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
1523 throw runtime_error(
1525 "Removes the wallet encryption key from memory, locking the wallet.\n"
1526 "After calling this method, you will need to call walletpassphrase again\n"
1527 "before being able to call any methods which require the wallet to be unlocked.");
1530 if (!pwalletMain->IsCrypted())
1531 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletlock was called.");
1533 pwalletMain->Lock();
1534 CRITICAL_BLOCK(cs_nWalletUnlockTime)
1536 nWalletUnlockTime = 0;
1543 Value encryptwallet(const Array& params, bool fHelp)
1545 if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
1546 throw runtime_error(
1547 "encryptwallet <passphrase>\n"
1548 "Encrypts the wallet with <passphrase>.");
1551 if (pwalletMain->IsCrypted())
1552 throw JSONRPCError(-15, "Error: running with an encrypted wallet, but encryptwallet was called.");
1555 // shutting down via RPC while the GUI is running does not work (yet):
1556 throw runtime_error("Not Yet Implemented: use GUI to encrypt wallet, not RPC command");
1559 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1560 // Alternately, find a way to make params[0] mlock()'d to begin with.
1561 SecureString strWalletPass;
1562 strWalletPass.reserve(100);
1563 strWalletPass = params[0].get_str().c_str();
1565 if (strWalletPass.length() < 1)
1566 throw runtime_error(
1567 "encryptwallet <passphrase>\n"
1568 "Encrypts the wallet with <passphrase>.");
1570 if (!pwalletMain->EncryptWallet(strWalletPass))
1571 throw JSONRPCError(-16, "Error: Failed to encrypt the wallet.");
1573 // BDB seems to have a bad habit of writing old data into
1574 // slack space in .dat files; that is bad if the old data is
1575 // unencrypted private keys. So:
1576 CreateThread(Shutdown, NULL);
1577 return "wallet encrypted; bitcoin server stopping, restart to run with encrypted wallet";
1581 Value validateaddress(const Array& params, bool fHelp)
1583 if (fHelp || params.size() != 1)
1584 throw runtime_error(
1585 "validateaddress <bitcoinaddress>\n"
1586 "Return information about <bitcoinaddress>.");
1588 CBitcoinAddress address(params[0].get_str());
1589 bool isValid = address.IsValid();
1592 ret.push_back(Pair("isvalid", isValid));
1595 // Call Hash160ToAddress() so we always return current ADDRESSVERSION
1596 // version of the address:
1597 string currentAddress = address.ToString();
1598 ret.push_back(Pair("address", currentAddress));
1599 ret.push_back(Pair("ismine", (pwalletMain->HaveKey(address) > 0)));
1600 if (pwalletMain->mapAddressBook.count(address))
1601 ret.push_back(Pair("account", pwalletMain->mapAddressBook[address]));
1606 Value getwork(const Array& params, bool fHelp)
1608 if (fHelp || params.size() > 1)
1609 throw runtime_error(
1611 "If [data] is not specified, returns formatted hash data to work on:\n"
1612 " \"midstate\" : precomputed hash state after hashing the first half of the data (DEPRECATED)\n" // deprecated
1613 " \"data\" : block data\n"
1614 " \"hash1\" : formatted hash buffer for second hash (DEPRECATED)\n" // deprecated
1615 " \"target\" : little endian hash target\n"
1616 "If [data] is specified, tries to solve the block and returns true if it was successful.");
1619 throw JSONRPCError(-9, "Bitcoin is not connected!");
1621 if (IsInitialBlockDownload())
1622 throw JSONRPCError(-10, "Bitcoin is downloading blocks...");
1624 typedef map<uint256, pair<CBlock*, CScript> > mapNewBlock_t;
1625 static mapNewBlock_t mapNewBlock;
1626 static vector<CBlock*> vNewBlock;
1627 static CReserveKey reservekey(pwalletMain);
1629 if (params.size() == 0)
1632 static unsigned int nTransactionsUpdatedLast;
1633 static CBlockIndex* pindexPrev;
1634 static int64 nStart;
1635 static CBlock* pblock;
1636 if (pindexPrev != pindexBest ||
1637 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60))
1639 if (pindexPrev != pindexBest)
1641 // Deallocate old blocks since they're obsolete now
1642 mapNewBlock.clear();
1643 BOOST_FOREACH(CBlock* pblock, vNewBlock)
1647 nTransactionsUpdatedLast = nTransactionsUpdated;
1648 pindexPrev = pindexBest;
1652 pblock = CreateNewBlock(reservekey);
1654 throw JSONRPCError(-7, "Out of memory");
1655 vNewBlock.push_back(pblock);
1659 pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
1662 // Update nExtraNonce
1663 static unsigned int nExtraNonce = 0;
1664 IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
1667 mapNewBlock[pblock->hashMerkleRoot] = make_pair(pblock, pblock->vtx[0].vin[0].scriptSig);
1669 // Prebuild hash buffers
1673 FormatHashBuffers(pblock, pmidstate, pdata, phash1);
1675 uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
1678 result.push_back(Pair("midstate", HexStr(BEGIN(pmidstate), END(pmidstate)))); // deprecated
1679 result.push_back(Pair("data", HexStr(BEGIN(pdata), END(pdata))));
1680 result.push_back(Pair("hash1", HexStr(BEGIN(phash1), END(phash1)))); // deprecated
1681 result.push_back(Pair("target", HexStr(BEGIN(hashTarget), END(hashTarget))));
1687 vector<unsigned char> vchData = ParseHex(params[0].get_str());
1688 if (vchData.size() != 128)
1689 throw JSONRPCError(-8, "Invalid parameter");
1690 CBlock* pdata = (CBlock*)&vchData[0];
1693 for (int i = 0; i < 128/4; i++)
1694 ((unsigned int*)pdata)[i] = ByteReverse(((unsigned int*)pdata)[i]);
1697 if (!mapNewBlock.count(pdata->hashMerkleRoot))
1699 CBlock* pblock = mapNewBlock[pdata->hashMerkleRoot].first;
1701 pblock->nTime = pdata->nTime;
1702 pblock->nNonce = pdata->nNonce;
1703 pblock->vtx[0].vin[0].scriptSig = mapNewBlock[pdata->hashMerkleRoot].second;
1704 pblock->hashMerkleRoot = pblock->BuildMerkleTree();
1706 return CheckWork(pblock, *pwalletMain, reservekey);
1711 Value getmemorypool(const Array& params, bool fHelp)
1713 if (fHelp || params.size() > 1)
1714 throw runtime_error(
1715 "getmemorypool [data]\n"
1716 "If [data] is not specified, returns data needed to construct a block to work on:\n"
1717 " \"version\" : block version\n"
1718 " \"previousblockhash\" : hash of current highest block\n"
1719 " \"transactions\" : contents of non-coinbase transactions that should be included in the next block\n"
1720 " \"coinbasevalue\" : maximum allowable input to coinbase transaction, including the generation award and transaction fees\n"
1721 " \"time\" : timestamp appropriate for next block\n"
1722 " \"bits\" : compressed target of next block\n"
1723 "If [data] is specified, tries to solve the block and returns true if it was successful.");
1725 if (params.size() == 0)
1728 throw JSONRPCError(-9, "Bitcoin is not connected!");
1730 if (IsInitialBlockDownload())
1731 throw JSONRPCError(-10, "Bitcoin is downloading blocks...");
1733 static CReserveKey reservekey(pwalletMain);
1736 static unsigned int nTransactionsUpdatedLast;
1737 static CBlockIndex* pindexPrev;
1738 static int64 nStart;
1739 static CBlock* pblock;
1740 if (pindexPrev != pindexBest ||
1741 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 5))
1743 nTransactionsUpdatedLast = nTransactionsUpdated;
1744 pindexPrev = pindexBest;
1750 pblock = CreateNewBlock(reservekey);
1752 throw JSONRPCError(-7, "Out of memory");
1756 pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
1760 BOOST_FOREACH(CTransaction tx, pblock->vtx) {
1767 transactions.push_back(HexStr(ssTx.begin(), ssTx.end()));
1771 result.push_back(Pair("version", pblock->nVersion));
1772 result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex()));
1773 result.push_back(Pair("transactions", transactions));
1774 result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue));
1775 result.push_back(Pair("time", (int64_t)pblock->nTime));
1781 uBits.nBits = htonl((int32_t)pblock->nBits);
1782 result.push_back(Pair("bits", HexStr(BEGIN(uBits.cBits), END(uBits.cBits))));
1789 CDataStream ssBlock(ParseHex(params[0].get_str()));
1793 return ProcessBlock(NULL, &pblock);
1811 pair<string, rpcfn_type> pCallTable[] =
1813 make_pair("help", &help),
1814 make_pair("stop", &stop),
1815 make_pair("getblockcount", &getblockcount),
1816 make_pair("getblocknumber", &getblocknumber),
1817 make_pair("getconnectioncount", &getconnectioncount),
1818 make_pair("getdifficulty", &getdifficulty),
1819 make_pair("getgenerate", &getgenerate),
1820 make_pair("setgenerate", &setgenerate),
1821 make_pair("gethashespersec", &gethashespersec),
1822 make_pair("getinfo", &getinfo),
1823 make_pair("getnewaddress", &getnewaddress),
1824 make_pair("getaccountaddress", &getaccountaddress),
1825 make_pair("setaccount", &setaccount),
1826 make_pair("getaccount", &getaccount),
1827 make_pair("getaddressesbyaccount", &getaddressesbyaccount),
1828 make_pair("sendtoaddress", &sendtoaddress),
1829 make_pair("getreceivedbyaddress", &getreceivedbyaddress),
1830 make_pair("getreceivedbyaccount", &getreceivedbyaccount),
1831 make_pair("listreceivedbyaddress", &listreceivedbyaddress),
1832 make_pair("listreceivedbyaccount", &listreceivedbyaccount),
1833 make_pair("backupwallet", &backupwallet),
1834 make_pair("keypoolrefill", &keypoolrefill),
1835 make_pair("walletpassphrase", &walletpassphrase),
1836 make_pair("walletpassphrasechange", &walletpassphrasechange),
1837 make_pair("walletlock", &walletlock),
1838 make_pair("encryptwallet", &encryptwallet),
1839 make_pair("validateaddress", &validateaddress),
1840 make_pair("getbalance", &getbalance),
1841 make_pair("move", &movecmd),
1842 make_pair("sendfrom", &sendfrom),
1843 make_pair("sendmany", &sendmany),
1844 make_pair("gettransaction", &gettransaction),
1845 make_pair("listtransactions", &listtransactions),
1846 make_pair("signmessage", &signmessage),
1847 make_pair("verifymessage", &verifymessage),
1848 make_pair("getwork", &getwork),
1849 make_pair("listaccounts", &listaccounts),
1850 make_pair("settxfee", &settxfee),
1851 make_pair("getmemorypool", &getmemorypool),
1852 make_pair("listsinceblock", &listsinceblock),
1853 make_pair("dumpprivkey", &dumpprivkey),
1854 make_pair("importprivkey", &importprivkey)
1856 map<string, rpcfn_type> mapCallTable(pCallTable, pCallTable + sizeof(pCallTable)/sizeof(pCallTable[0]));
1858 string pAllowInSafeMode[] =
1863 "getblocknumber", // deprecated
1864 "getconnectioncount",
1871 "getaccountaddress",
1873 "getaddressesbyaccount",
1882 set<string> setAllowInSafeMode(pAllowInSafeMode, pAllowInSafeMode + sizeof(pAllowInSafeMode)/sizeof(pAllowInSafeMode[0]));
1890 // This ain't Apache. We're just using HTTP header for the length field
1891 // and to be compatible with other JSON-RPC implementations.
1894 string HTTPPost(const string& strMsg, const map<string,string>& mapRequestHeaders)
1897 s << "POST / HTTP/1.1\r\n"
1898 << "User-Agent: bitcoin-json-rpc/" << FormatFullVersion() << "\r\n"
1899 << "Host: 127.0.0.1\r\n"
1900 << "Content-Type: application/json\r\n"
1901 << "Content-Length: " << strMsg.size() << "\r\n"
1902 << "Connection: close\r\n"
1903 << "Accept: application/json\r\n";
1904 BOOST_FOREACH(const PAIRTYPE(string, string)& item, mapRequestHeaders)
1905 s << item.first << ": " << item.second << "\r\n";
1906 s << "\r\n" << strMsg;
1911 string rfc1123Time()
1916 struct tm* now_gmt = gmtime(&now);
1917 string locale(setlocale(LC_TIME, NULL));
1918 setlocale(LC_TIME, "C"); // we want posix (aka "C") weekday/month strings
1919 strftime(buffer, sizeof(buffer), "%a, %d %b %Y %H:%M:%S +0000", now_gmt);
1920 setlocale(LC_TIME, locale.c_str());
1921 return string(buffer);
1924 static string HTTPReply(int nStatus, const string& strMsg)
1927 return strprintf("HTTP/1.0 401 Authorization Required\r\n"
1929 "Server: bitcoin-json-rpc/%s\r\n"
1930 "WWW-Authenticate: Basic realm=\"jsonrpc\"\r\n"
1931 "Content-Type: text/html\r\n"
1932 "Content-Length: 296\r\n"
1934 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\r\n"
1935 "\"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd\">\r\n"
1938 "<TITLE>Error</TITLE>\r\n"
1939 "<META HTTP-EQUIV='Content-Type' CONTENT='text/html; charset=ISO-8859-1'>\r\n"
1941 "<BODY><H1>401 Unauthorized.</H1></BODY>\r\n"
1942 "</HTML>\r\n", rfc1123Time().c_str(), FormatFullVersion().c_str());
1943 const char *cStatus;
1944 if (nStatus == 200) cStatus = "OK";
1945 else if (nStatus == 400) cStatus = "Bad Request";
1946 else if (nStatus == 403) cStatus = "Forbidden";
1947 else if (nStatus == 404) cStatus = "Not Found";
1948 else if (nStatus == 500) cStatus = "Internal Server Error";
1951 "HTTP/1.1 %d %s\r\n"
1953 "Connection: close\r\n"
1954 "Content-Length: %d\r\n"
1955 "Content-Type: application/json\r\n"
1956 "Server: bitcoin-json-rpc/%s\r\n"
1961 rfc1123Time().c_str(),
1963 FormatFullVersion().c_str(),
1967 int ReadHTTPStatus(std::basic_istream<char>& stream)
1970 getline(stream, str);
1971 vector<string> vWords;
1972 boost::split(vWords, str, boost::is_any_of(" "));
1973 if (vWords.size() < 2)
1975 return atoi(vWords[1].c_str());
1978 int ReadHTTPHeader(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet)
1984 std::getline(stream, str);
1985 if (str.empty() || str == "\r")
1987 string::size_type nColon = str.find(":");
1988 if (nColon != string::npos)
1990 string strHeader = str.substr(0, nColon);
1991 boost::trim(strHeader);
1992 boost::to_lower(strHeader);
1993 string strValue = str.substr(nColon+1);
1994 boost::trim(strValue);
1995 mapHeadersRet[strHeader] = strValue;
1996 if (strHeader == "content-length")
1997 nLen = atoi(strValue.c_str());
2003 int ReadHTTP(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet, string& strMessageRet)
2005 mapHeadersRet.clear();
2009 int nStatus = ReadHTTPStatus(stream);
2012 int nLen = ReadHTTPHeader(stream, mapHeadersRet);
2013 if (nLen < 0 || nLen > MAX_SIZE)
2019 vector<char> vch(nLen);
2020 stream.read(&vch[0], nLen);
2021 strMessageRet = string(vch.begin(), vch.end());
2027 bool HTTPAuthorized(map<string, string>& mapHeaders)
2029 string strAuth = mapHeaders["authorization"];
2030 if (strAuth.substr(0,6) != "Basic ")
2032 string strUserPass64 = strAuth.substr(6); boost::trim(strUserPass64);
2033 string strUserPass = DecodeBase64(strUserPass64);
2034 return strUserPass == strRPCUserColonPass;
2038 // JSON-RPC protocol. Bitcoin speaks version 1.0 for maximum compatibility,
2039 // but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
2040 // unspecified (HTTP errors and contents of 'error').
2042 // 1.0 spec: http://json-rpc.org/wiki/specification
2043 // 1.2 spec: http://groups.google.com/group/json-rpc/web/json-rpc-over-http
2044 // http://www.codeproject.com/KB/recipes/JSON_Spirit.aspx
2047 string JSONRPCRequest(const string& strMethod, const Array& params, const Value& id)
2050 request.push_back(Pair("method", strMethod));
2051 request.push_back(Pair("params", params));
2052 request.push_back(Pair("id", id));
2053 return write_string(Value(request), false) + "\n";
2056 string JSONRPCReply(const Value& result, const Value& error, const Value& id)
2059 if (error.type() != null_type)
2060 reply.push_back(Pair("result", Value::null));
2062 reply.push_back(Pair("result", result));
2063 reply.push_back(Pair("error", error));
2064 reply.push_back(Pair("id", id));
2065 return write_string(Value(reply), false) + "\n";
2068 void ErrorReply(std::ostream& stream, const Object& objError, const Value& id)
2070 // Send error reply from json-rpc error object
2072 int code = find_value(objError, "code").get_int();
2073 if (code == -32600) nStatus = 400;
2074 else if (code == -32601) nStatus = 404;
2075 string strReply = JSONRPCReply(Value::null, objError, id);
2076 stream << HTTPReply(nStatus, strReply) << std::flush;
2079 bool ClientAllowed(const string& strAddress)
2081 if (strAddress == asio::ip::address_v4::loopback().to_string())
2083 const vector<string>& vAllow = mapMultiArgs["-rpcallowip"];
2084 BOOST_FOREACH(string strAllow, vAllow)
2085 if (WildcardMatch(strAddress, strAllow))
2092 // IOStream device that speaks SSL but can also speak non-SSL
2094 class SSLIOStreamDevice : public iostreams::device<iostreams::bidirectional> {
2096 SSLIOStreamDevice(SSLStream &streamIn, bool fUseSSLIn) : stream(streamIn)
2098 fUseSSL = fUseSSLIn;
2099 fNeedHandshake = fUseSSLIn;
2102 void handshake(ssl::stream_base::handshake_type role)
2104 if (!fNeedHandshake) return;
2105 fNeedHandshake = false;
2106 stream.handshake(role);
2108 std::streamsize read(char* s, std::streamsize n)
2110 handshake(ssl::stream_base::server); // HTTPS servers read first
2111 if (fUseSSL) return stream.read_some(asio::buffer(s, n));
2112 return stream.next_layer().read_some(asio::buffer(s, n));
2114 std::streamsize write(const char* s, std::streamsize n)
2116 handshake(ssl::stream_base::client); // HTTPS clients write first
2117 if (fUseSSL) return asio::write(stream, asio::buffer(s, n));
2118 return asio::write(stream.next_layer(), asio::buffer(s, n));
2120 bool connect(const std::string& server, const std::string& port)
2122 ip::tcp::resolver resolver(stream.get_io_service());
2123 ip::tcp::resolver::query query(server.c_str(), port.c_str());
2124 ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
2125 ip::tcp::resolver::iterator end;
2126 boost::system::error_code error = asio::error::host_not_found;
2127 while (error && endpoint_iterator != end)
2129 stream.lowest_layer().close();
2130 stream.lowest_layer().connect(*endpoint_iterator++, error);
2138 bool fNeedHandshake;
2144 void ThreadRPCServer(void* parg)
2146 IMPLEMENT_RANDOMIZE_STACK(ThreadRPCServer(parg));
2149 vnThreadsRunning[4]++;
2150 ThreadRPCServer2(parg);
2151 vnThreadsRunning[4]--;
2153 catch (std::exception& e) {
2154 vnThreadsRunning[4]--;
2155 PrintException(&e, "ThreadRPCServer()");
2157 vnThreadsRunning[4]--;
2158 PrintException(NULL, "ThreadRPCServer()");
2160 printf("ThreadRPCServer exiting\n");
2163 void ThreadRPCServer2(void* parg)
2165 printf("ThreadRPCServer started\n");
2167 strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"];
2168 if (strRPCUserColonPass == ":")
2170 string strWhatAmI = "To use bitcoind";
2171 if (mapArgs.count("-server"))
2172 strWhatAmI = strprintf(_("To use the %s option"), "\"-server\"");
2173 else if (mapArgs.count("-daemon"))
2174 strWhatAmI = strprintf(_("To use the %s option"), "\"-daemon\"");
2176 _("Error: %s, you must set rpcpassword=<password>\nin the configuration file: %s\n"
2177 "If the file does not exist, create it with owner-readable-only file permissions.\n"),
2179 GetConfigFile().c_str());
2181 CreateThread(Shutdown, NULL);
2186 bool fUseSSL = GetBoolArg("-rpcssl");
2187 asio::ip::address bindAddress = mapArgs.count("-rpcallowip") ? asio::ip::address_v4::any() : asio::ip::address_v4::loopback();
2189 asio::io_service io_service;
2190 ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", 8332));
2191 ip::tcp::acceptor acceptor(io_service, endpoint);
2193 acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
2196 ssl::context context(io_service, ssl::context::sslv23);
2199 context.set_options(ssl::context::no_sslv2);
2200 filesystem::path certfile = GetArg("-rpcsslcertificatechainfile", "server.cert");
2201 if (!certfile.is_complete()) certfile = filesystem::path(GetDataDir()) / certfile;
2202 if (filesystem::exists(certfile)) context.use_certificate_chain_file(certfile.string().c_str());
2203 else printf("ThreadRPCServer ERROR: missing server certificate file %s\n", certfile.string().c_str());
2204 filesystem::path pkfile = GetArg("-rpcsslprivatekeyfile", "server.pem");
2205 if (!pkfile.is_complete()) pkfile = filesystem::path(GetDataDir()) / pkfile;
2206 if (filesystem::exists(pkfile)) context.use_private_key_file(pkfile.string().c_str(), ssl::context::pem);
2207 else printf("ThreadRPCServer ERROR: missing server private key file %s\n", pkfile.string().c_str());
2209 string ciphers = GetArg("-rpcsslciphers",
2210 "TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH");
2211 SSL_CTX_set_cipher_list(context.impl(), ciphers.c_str());
2215 throw runtime_error("-rpcssl=1, but bitcoin compiled without full openssl libraries.");
2220 // Accept connection
2222 SSLStream sslStream(io_service, context);
2223 SSLIOStreamDevice d(sslStream, fUseSSL);
2224 iostreams::stream<SSLIOStreamDevice> stream(d);
2226 ip::tcp::iostream stream;
2229 ip::tcp::endpoint peer;
2230 vnThreadsRunning[4]--;
2232 acceptor.accept(sslStream.lowest_layer(), peer);
2234 acceptor.accept(*stream.rdbuf(), peer);
2236 vnThreadsRunning[4]++;
2240 // Restrict callers by IP
2241 if (!ClientAllowed(peer.address().to_string()))
2243 // Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake.
2245 stream << HTTPReply(403, "") << std::flush;
2249 map<string, string> mapHeaders;
2252 boost::thread api_caller(ReadHTTP, boost::ref(stream), boost::ref(mapHeaders), boost::ref(strRequest));
2253 if (!api_caller.timed_join(boost::posix_time::seconds(GetArg("-rpctimeout", 30))))
2256 printf("ThreadRPCServer ReadHTTP timeout\n");
2260 // Check authorization
2261 if (mapHeaders.count("authorization") == 0)
2263 stream << HTTPReply(401, "") << std::flush;
2266 if (!HTTPAuthorized(mapHeaders))
2268 // Deter brute-forcing short passwords
2269 if (mapArgs["-rpcpassword"].size() < 15)
2272 stream << HTTPReply(401, "") << std::flush;
2273 printf("ThreadRPCServer incorrect password attempt\n");
2277 Value id = Value::null;
2282 if (!read_string(strRequest, valRequest) || valRequest.type() != obj_type)
2283 throw JSONRPCError(-32700, "Parse error");
2284 const Object& request = valRequest.get_obj();
2286 // Parse id now so errors from here on will have the id
2287 id = find_value(request, "id");
2290 Value valMethod = find_value(request, "method");
2291 if (valMethod.type() == null_type)
2292 throw JSONRPCError(-32600, "Missing method");
2293 if (valMethod.type() != str_type)
2294 throw JSONRPCError(-32600, "Method must be a string");
2295 string strMethod = valMethod.get_str();
2296 if (strMethod != "getwork" && strMethod != "getmemorypool")
2297 printf("ThreadRPCServer method=%s\n", strMethod.c_str());
2300 Value valParams = find_value(request, "params");
2302 if (valParams.type() == array_type)
2303 params = valParams.get_array();
2304 else if (valParams.type() == null_type)
2307 throw JSONRPCError(-32600, "Params must be an array");
2310 map<string, rpcfn_type>::iterator mi = mapCallTable.find(strMethod);
2311 if (mi == mapCallTable.end())
2312 throw JSONRPCError(-32601, "Method not found");
2314 // Observe safe mode
2315 string strWarning = GetWarnings("rpc");
2316 if (strWarning != "" && !GetBoolArg("-disablesafemode") && !setAllowInSafeMode.count(strMethod))
2317 throw JSONRPCError(-2, string("Safe mode: ") + strWarning);
2323 CRITICAL_BLOCK(cs_main)
2324 CRITICAL_BLOCK(pwalletMain->cs_wallet)
2325 result = (*(*mi).second)(params, false);
2328 string strReply = JSONRPCReply(result, Value::null, id);
2329 stream << HTTPReply(200, strReply) << std::flush;
2331 catch (std::exception& e)
2333 ErrorReply(stream, JSONRPCError(-1, e.what()), id);
2336 catch (Object& objError)
2338 ErrorReply(stream, objError, id);
2340 catch (std::exception& e)
2342 ErrorReply(stream, JSONRPCError(-32700, e.what()), id);
2350 Object CallRPC(const string& strMethod, const Array& params)
2352 if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
2353 throw runtime_error(strprintf(
2354 _("You must set rpcpassword=<password> in the configuration file:\n%s\n"
2355 "If the file does not exist, create it with owner-readable-only file permissions."),
2356 GetConfigFile().c_str()));
2358 // Connect to localhost
2359 bool fUseSSL = GetBoolArg("-rpcssl");
2361 asio::io_service io_service;
2362 ssl::context context(io_service, ssl::context::sslv23);
2363 context.set_options(ssl::context::no_sslv2);
2364 SSLStream sslStream(io_service, context);
2365 SSLIOStreamDevice d(sslStream, fUseSSL);
2366 iostreams::stream<SSLIOStreamDevice> stream(d);
2367 if (!d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332")))
2368 throw runtime_error("couldn't connect to server");
2371 throw runtime_error("-rpcssl=1, but bitcoin compiled without full openssl libraries.");
2373 ip::tcp::iostream stream(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332"));
2375 throw runtime_error("couldn't connect to server");
2379 // HTTP basic authentication
2380 string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
2381 map<string, string> mapRequestHeaders;
2382 mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64;
2385 string strRequest = JSONRPCRequest(strMethod, params, 1);
2386 string strPost = HTTPPost(strRequest, mapRequestHeaders);
2387 stream << strPost << std::flush;
2390 map<string, string> mapHeaders;
2392 int nStatus = ReadHTTP(stream, mapHeaders, strReply);
2394 throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
2395 else if (nStatus >= 400 && nStatus != 400 && nStatus != 404 && nStatus != 500)
2396 throw runtime_error(strprintf("server returned HTTP error %d", nStatus));
2397 else if (strReply.empty())
2398 throw runtime_error("no response from server");
2402 if (!read_string(strReply, valReply))
2403 throw runtime_error("couldn't parse reply from server");
2404 const Object& reply = valReply.get_obj();
2406 throw runtime_error("expected reply to have result, error and id properties");
2414 template<typename T>
2415 void ConvertTo(Value& value)
2417 if (value.type() == str_type)
2419 // reinterpret string as unquoted json value
2421 if (!read_string(value.get_str(), value2))
2422 throw runtime_error("type mismatch");
2423 value = value2.get_value<T>();
2427 value = value.get_value<T>();
2431 int CommandLineRPC(int argc, char *argv[])
2438 while (argc > 1 && IsSwitchChar(argv[1][0]))
2446 throw runtime_error("too few parameters");
2447 string strMethod = argv[1];
2449 // Parameters default to strings
2451 for (int i = 2; i < argc; i++)
2452 params.push_back(argv[i]);
2453 int n = params.size();
2456 // Special case non-string parameter types
2458 if (strMethod == "setgenerate" && n > 0) ConvertTo<bool>(params[0]);
2459 if (strMethod == "setgenerate" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2460 if (strMethod == "sendtoaddress" && n > 1) ConvertTo<double>(params[1]);
2461 if (strMethod == "settxfee" && n > 0) ConvertTo<double>(params[0]);
2462 if (strMethod == "getreceivedbyaddress" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2463 if (strMethod == "getreceivedbyaccount" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2464 if (strMethod == "listreceivedbyaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2465 if (strMethod == "listreceivedbyaddress" && n > 1) ConvertTo<bool>(params[1]);
2466 if (strMethod == "listreceivedbyaccount" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2467 if (strMethod == "listreceivedbyaccount" && n > 1) ConvertTo<bool>(params[1]);
2468 if (strMethod == "getbalance" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2469 if (strMethod == "move" && n > 2) ConvertTo<double>(params[2]);
2470 if (strMethod == "move" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2471 if (strMethod == "sendfrom" && n > 2) ConvertTo<double>(params[2]);
2472 if (strMethod == "sendfrom" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2473 if (strMethod == "listtransactions" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2474 if (strMethod == "listtransactions" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2475 if (strMethod == "listaccounts" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2476 if (strMethod == "walletpassphrase" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2477 if (strMethod == "listsinceblock" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2478 if (strMethod == "sendmany" && n > 1)
2480 string s = params[1].get_str();
2482 if (!read_string(s, v) || v.type() != obj_type)
2483 throw runtime_error("type mismatch");
2484 params[1] = v.get_obj();
2486 if (strMethod == "sendmany" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2489 Object reply = CallRPC(strMethod, params);
2492 const Value& result = find_value(reply, "result");
2493 const Value& error = find_value(reply, "error");
2495 if (error.type() != null_type)
2498 strPrint = "error: " + write_string(error, false);
2499 int code = find_value(error.get_obj(), "code").get_int();
2505 if (result.type() == null_type)
2507 else if (result.type() == str_type)
2508 strPrint = result.get_str();
2510 strPrint = write_string(result, true);
2513 catch (std::exception& e)
2515 strPrint = string("error: ") + e.what();
2520 PrintException(NULL, "CommandLineRPC()");
2525 fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
2534 int main(int argc, char *argv[])
2537 // Turn off microsoft heap dump noise
2538 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
2539 _CrtSetReportFile(_CRT_WARN, CreateFile("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0));
2541 setbuf(stdin, NULL);
2542 setbuf(stdout, NULL);
2543 setbuf(stderr, NULL);
2547 if (argc >= 2 && string(argv[1]) == "-server")
2549 printf("server ready\n");
2550 ThreadRPCServer(NULL);
2554 return CommandLineRPC(argc, argv);
2557 catch (std::exception& e) {
2558 PrintException(&e, "main()");
2560 PrintException(NULL, "main()");