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/iostreams/concepts.hpp>
13 #include <boost/iostreams/stream.hpp>
14 #include <boost/algorithm/string.hpp>
16 #include <boost/asio/ssl.hpp>
17 #include <boost/filesystem.hpp>
18 #include <boost/filesystem/fstream.hpp>
19 typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> SSLStream;
21 #include "json/json_spirit_reader_template.h"
22 #include "json/json_spirit_writer_template.h"
23 #include "json/json_spirit_utils.h"
24 #define printf OutputDebugStringF
25 // MinGW 3.4.5 gets "fatal error: had to relocate PCH" if the json headers are
26 // precompiled in headers.h. The problem might be when the pch file goes over
27 // a certain size around 145MB. If we need access to json_spirit outside this
28 // file, we could use the compiled json_spirit option.
31 using namespace boost;
32 using namespace boost::asio;
33 using namespace json_spirit;
35 void ThreadRPCServer2(void* parg);
36 typedef Value(*rpcfn_type)(const Array& params, bool fHelp);
37 extern map<string, rpcfn_type> mapCallTable;
39 static int64 nWalletUnlockTime;
40 static CCriticalSection cs_nWalletUnlockTime;
43 Object JSONRPCError(int code, const string& message)
46 error.push_back(Pair("code", code));
47 error.push_back(Pair("message", message));
52 void PrintConsole(const std::string &format, ...)
55 int limit = sizeof(buffer);
57 va_start(arg_ptr, format);
58 int ret = _vsnprintf(buffer, limit, format.c_str(), arg_ptr);
60 if (ret < 0 || ret >= limit)
66 fprintf(stdout, "%s", buffer);
70 int64 AmountFromValue(const Value& value)
72 double dAmount = value.get_real();
73 if (dAmount <= 0.0 || dAmount > 21000000.0)
74 throw JSONRPCError(-3, "Invalid amount");
75 int64 nAmount = roundint64(dAmount * COIN);
76 if (!MoneyRange(nAmount))
77 throw JSONRPCError(-3, "Invalid amount");
81 Value ValueFromAmount(int64 amount)
83 return (double)amount / (double)COIN;
86 void WalletTxToJSON(const CWalletTx& wtx, Object& entry)
88 entry.push_back(Pair("confirmations", wtx.GetDepthInMainChain()));
89 entry.push_back(Pair("txid", wtx.GetHash().GetHex()));
90 entry.push_back(Pair("time", (boost::int64_t)wtx.GetTxTime()));
91 BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue)
92 entry.push_back(Pair(item.first, item.second));
95 string AccountFromValue(const Value& value)
97 string strAccount = value.get_str();
98 if (strAccount == "*")
99 throw JSONRPCError(-11, "Invalid account name");
106 /// Note: This interface may still be subject to change.
110 Value help(const Array& params, bool fHelp)
112 if (fHelp || params.size() > 1)
115 "List commands, or get help for a command.");
118 if (params.size() > 0)
119 strCommand = params[0].get_str();
122 set<rpcfn_type> setDone;
123 for (map<string, rpcfn_type>::iterator mi = mapCallTable.begin(); mi != mapCallTable.end(); ++mi)
125 string strMethod = (*mi).first;
126 // We already filter duplicates, but these deprecated screw up the sort order
127 if (strMethod == "getamountreceived" ||
128 strMethod == "getallreceived" ||
129 (strMethod.find("label") != string::npos))
131 if (strCommand != "" && strMethod != strCommand)
136 rpcfn_type pfn = (*mi).second;
137 if (setDone.insert(pfn).second)
138 (*pfn)(params, true);
140 catch (std::exception& e)
142 // Help text is returned in an exception
143 string strHelp = string(e.what());
144 if (strCommand == "")
145 if (strHelp.find('\n') != -1)
146 strHelp = strHelp.substr(0, strHelp.find('\n'));
147 strRet += strHelp + "\n";
151 strRet = strprintf("help: unknown command: %s\n", strCommand.c_str());
152 strRet = strRet.substr(0,strRet.size()-1);
157 Value stop(const Array& params, bool fHelp)
159 if (fHelp || params.size() != 0)
162 "Stop bitcoin server.");
164 // Shutdown will take long enough that the response should get back
165 CreateThread(Shutdown, NULL);
166 return "bitcoin server stopping";
170 Value getblockcount(const Array& params, bool fHelp)
172 if (fHelp || params.size() != 0)
175 "Returns the number of blocks in the longest block chain.");
181 Value getblocknumber(const Array& params, bool fHelp)
183 if (fHelp || params.size() != 0)
186 "Returns the block number of the latest block in the longest block chain.");
192 Value getconnectioncount(const Array& params, bool fHelp)
194 if (fHelp || params.size() != 0)
196 "getconnectioncount\n"
197 "Returns the number of connections to other nodes.");
199 return (int)vNodes.size();
203 double GetDifficulty()
205 // Floating point number that is a multiple of the minimum difficulty,
206 // minimum difficulty = 1.0.
208 if (pindexBest == NULL)
210 int nShift = (pindexBest->nBits >> 24) & 0xff;
213 (double)0x0000ffff / (double)(pindexBest->nBits & 0x00ffffff);
229 Value getdifficulty(const Array& params, bool fHelp)
231 if (fHelp || params.size() != 0)
234 "Returns the proof-of-work difficulty as a multiple of the minimum difficulty.");
236 return GetDifficulty();
240 Value getgenerate(const Array& params, bool fHelp)
242 if (fHelp || params.size() != 0)
245 "Returns true or false.");
247 return (bool)fGenerateBitcoins;
251 Value setgenerate(const Array& params, bool fHelp)
253 if (fHelp || params.size() < 1 || params.size() > 2)
255 "setgenerate <generate> [genproclimit]\n"
256 "<generate> is true or false to turn generation on or off.\n"
257 "Generation is limited to [genproclimit] processors, -1 is unlimited.");
259 bool fGenerate = true;
260 if (params.size() > 0)
261 fGenerate = params[0].get_bool();
263 if (params.size() > 1)
265 int nGenProcLimit = params[1].get_int();
266 fLimitProcessors = (nGenProcLimit != -1);
267 WriteSetting("fLimitProcessors", fLimitProcessors);
268 if (nGenProcLimit != -1)
269 WriteSetting("nLimitProcessors", nLimitProcessors = nGenProcLimit);
270 if (nGenProcLimit == 0)
274 GenerateBitcoins(fGenerate, pwalletMain);
279 Value gethashespersec(const Array& params, bool fHelp)
281 if (fHelp || params.size() != 0)
284 "Returns a recent hashes per second performance measurement while generating.");
286 if (GetTimeMillis() - nHPSTimerStart > 8000)
287 return (boost::int64_t)0;
288 return (boost::int64_t)dHashesPerSec;
292 Value getinfo(const Array& params, bool fHelp)
294 if (fHelp || params.size() != 0)
297 "Returns an object containing various state info.");
300 obj.push_back(Pair("version", (int)VERSION));
301 obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance())));
302 obj.push_back(Pair("blocks", (int)nBestHeight));
303 obj.push_back(Pair("connections", (int)vNodes.size()));
304 obj.push_back(Pair("proxy", (fUseProxy ? addrProxy.ToStringIPPort() : string())));
305 obj.push_back(Pair("generate", (bool)fGenerateBitcoins));
306 obj.push_back(Pair("genproclimit", (int)(fLimitProcessors ? nLimitProcessors : -1)));
307 obj.push_back(Pair("difficulty", (double)GetDifficulty()));
308 obj.push_back(Pair("hashespersec", gethashespersec(params, false)));
309 obj.push_back(Pair("testnet", fTestNet));
310 obj.push_back(Pair("keypoololdest", (boost::int64_t)pwalletMain->GetOldestKeyPoolTime()));
311 obj.push_back(Pair("keypoolsize", pwalletMain->GetKeyPoolSize()));
312 obj.push_back(Pair("paytxfee", ValueFromAmount(nTransactionFee)));
313 if (pwalletMain->IsCrypted())
314 obj.push_back(Pair("unlocked_until", (boost::int64_t)nWalletUnlockTime));
315 obj.push_back(Pair("errors", GetWarnings("statusbar")));
320 Value getnewaddress(const Array& params, bool fHelp)
322 if (fHelp || params.size() > 1)
324 "getnewaddress [account]\n"
325 "Returns a new bitcoin address for receiving payments. "
326 "If [account] is specified (recommended), it is added to the address book "
327 "so payments received with the address will be credited to [account].");
329 // Parse the account first so we don't generate a key if there's an error
331 if (params.size() > 0)
332 strAccount = AccountFromValue(params[0]);
334 if (!pwalletMain->IsLocked())
335 pwalletMain->TopUpKeyPool();
337 // Generate a new key that is added to wallet
338 std::vector<unsigned char> newKey;
339 if (!pwalletMain->GetKeyFromPool(newKey, false))
340 throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
341 CBitcoinAddress address(newKey);
343 pwalletMain->SetAddressBookName(address, strAccount);
345 return address.ToString();
349 CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false)
351 CWalletDB walletdb(pwalletMain->strWalletFile);
354 walletdb.ReadAccount(strAccount, account);
356 bool bKeyUsed = false;
358 // Check if the current key has been used
359 if (!account.vchPubKey.empty())
361 CScript scriptPubKey;
362 scriptPubKey.SetBitcoinAddress(account.vchPubKey);
363 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
364 it != pwalletMain->mapWallet.end() && !account.vchPubKey.empty();
367 const CWalletTx& wtx = (*it).second;
368 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
369 if (txout.scriptPubKey == scriptPubKey)
374 // Generate a new key
375 if (account.vchPubKey.empty() || bForceNew || bKeyUsed)
377 if (!pwalletMain->GetKeyFromPool(account.vchPubKey, false))
378 throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
380 pwalletMain->SetAddressBookName(CBitcoinAddress(account.vchPubKey), strAccount);
381 walletdb.WriteAccount(strAccount, account);
384 return CBitcoinAddress(account.vchPubKey);
387 Value getaccountaddress(const Array& params, bool fHelp)
389 if (fHelp || params.size() != 1)
391 "getaccountaddress <account>\n"
392 "Returns the current bitcoin address for receiving payments to this account.");
394 // Parse the account first so we don't generate a key if there's an error
395 string strAccount = AccountFromValue(params[0]);
399 ret = GetAccountAddress(strAccount).ToString();
406 Value setaccount(const Array& params, bool fHelp)
408 if (fHelp || params.size() < 1 || params.size() > 2)
410 "setaccount <bitcoinaddress> <account>\n"
411 "Sets the account associated with the given address.");
413 CBitcoinAddress address(params[0].get_str());
414 if (!address.IsValid())
415 throw JSONRPCError(-5, "Invalid bitcoin address");
419 if (params.size() > 1)
420 strAccount = AccountFromValue(params[1]);
422 // Detect when changing the account of an address that is the 'unused current key' of another account:
423 if (pwalletMain->mapAddressBook.count(address))
425 string strOldAccount = pwalletMain->mapAddressBook[address];
426 if (address == GetAccountAddress(strOldAccount))
427 GetAccountAddress(strOldAccount, true);
430 pwalletMain->SetAddressBookName(address, strAccount);
436 Value getaccount(const Array& params, bool fHelp)
438 if (fHelp || params.size() != 1)
440 "getaccount <bitcoinaddress>\n"
441 "Returns the account associated with the given address.");
443 CBitcoinAddress address(params[0].get_str());
444 if (!address.IsValid())
445 throw JSONRPCError(-5, "Invalid bitcoin address");
448 map<CBitcoinAddress, string>::iterator mi = pwalletMain->mapAddressBook.find(address);
449 if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.empty())
450 strAccount = (*mi).second;
455 Value getaddressesbyaccount(const Array& params, bool fHelp)
457 if (fHelp || params.size() != 1)
459 "getaddressesbyaccount <account>\n"
460 "Returns the list of addresses for the given account.");
462 string strAccount = AccountFromValue(params[0]);
464 // Find all addresses that have the given account
466 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
468 const CBitcoinAddress& address = item.first;
469 const string& strName = item.second;
470 if (strName == strAccount)
471 ret.push_back(address.ToString());
476 Value settxfee(const Array& params, bool fHelp)
478 if (fHelp || params.size() < 1 || params.size() > 1)
480 "settxfee <amount>\n"
481 "<amount> is a real and is rounded to the nearest 0.00000001");
485 if (params[0].get_real() != 0.0)
486 nAmount = AmountFromValue(params[0]); // rejects 0.0 amounts
488 nTransactionFee = nAmount;
492 Value sendtoaddress(const Array& params, bool fHelp)
494 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
496 "sendtoaddress <bitcoinaddress> <amount> [comment] [comment-to]\n"
497 "<amount> is a real and is rounded to the nearest 0.00000001\n"
498 "requires wallet passphrase to be set with walletpassphrase first");
499 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
501 "sendtoaddress <bitcoinaddress> <amount> [comment] [comment-to]\n"
502 "<amount> is a real and is rounded to the nearest 0.00000001");
504 CBitcoinAddress address(params[0].get_str());
505 if (!address.IsValid())
506 throw JSONRPCError(-5, "Invalid bitcoin address");
509 int64 nAmount = AmountFromValue(params[1]);
513 if (params.size() > 2 && params[2].type() != null_type && !params[2].get_str().empty())
514 wtx.mapValue["comment"] = params[2].get_str();
515 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
516 wtx.mapValue["to"] = params[3].get_str();
518 if (pwalletMain->IsLocked())
519 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
521 string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
523 throw JSONRPCError(-4, strError);
525 return wtx.GetHash().GetHex();
528 static const string strMessageMagic = "Bitcoin Signed Message:\n";
530 Value signmessage(const Array& params, bool fHelp)
532 if (fHelp || params.size() != 2)
534 "signmessage <bitcoinaddress> <message>\n"
535 "Sign a message with the private key of an address");
537 if (pwalletMain->IsLocked())
538 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
540 string strAddress = params[0].get_str();
541 string strMessage = params[1].get_str();
543 CBitcoinAddress addr(strAddress);
545 throw JSONRPCError(-3, "Invalid address");
548 if (!pwalletMain->GetKey(addr, key))
549 throw JSONRPCError(-4, "Private key not available");
551 CDataStream ss(SER_GETHASH);
552 ss << strMessageMagic;
555 vector<unsigned char> vchSig;
556 if (!key.SignCompact(Hash(ss.begin(), ss.end()), vchSig))
557 throw JSONRPCError(-5, "Sign failed");
559 return EncodeBase64(&vchSig[0], vchSig.size());
562 Value verifymessage(const Array& params, bool fHelp)
564 if (fHelp || params.size() != 3)
566 "verifymessage <bitcoinaddress> <signature> <message>\n"
567 "Verify a signed message");
569 string strAddress = params[0].get_str();
570 string strSign = params[1].get_str();
571 string strMessage = params[2].get_str();
573 CBitcoinAddress addr(strAddress);
575 throw JSONRPCError(-3, "Invalid address");
577 bool fInvalid = false;
578 vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid);
581 throw JSONRPCError(-5, "Malformed base64 encoding");
583 CDataStream ss(SER_GETHASH);
584 ss << strMessageMagic;
588 if (!key.SetCompactSignature(Hash(ss.begin(), ss.end()), vchSig))
591 return (key.GetAddress() == addr);
595 Value getreceivedbyaddress(const Array& params, bool fHelp)
597 if (fHelp || params.size() < 1 || params.size() > 2)
599 "getreceivedbyaddress <bitcoinaddress> [minconf=1]\n"
600 "Returns the total amount received by <bitcoinaddress> in transactions with at least [minconf] confirmations.");
603 CBitcoinAddress address = CBitcoinAddress(params[0].get_str());
604 CScript scriptPubKey;
605 if (!address.IsValid())
606 throw JSONRPCError(-5, "Invalid bitcoin address");
607 scriptPubKey.SetBitcoinAddress(address);
608 if (!IsMine(*pwalletMain,scriptPubKey))
611 // Minimum confirmations
613 if (params.size() > 1)
614 nMinDepth = params[1].get_int();
618 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
620 const CWalletTx& wtx = (*it).second;
621 if (wtx.IsCoinBase() || !wtx.IsFinal())
624 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
625 if (txout.scriptPubKey == scriptPubKey)
626 if (wtx.GetDepthInMainChain() >= nMinDepth)
627 nAmount += txout.nValue;
630 return ValueFromAmount(nAmount);
634 void GetAccountAddresses(string strAccount, set<CBitcoinAddress>& setAddress)
636 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
638 const CBitcoinAddress& address = item.first;
639 const string& strName = item.second;
640 if (strName == strAccount)
641 setAddress.insert(address);
646 Value getreceivedbyaccount(const Array& params, bool fHelp)
648 if (fHelp || params.size() < 1 || params.size() > 2)
650 "getreceivedbyaccount <account> [minconf=1]\n"
651 "Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.");
653 // Minimum confirmations
655 if (params.size() > 1)
656 nMinDepth = params[1].get_int();
658 // Get the set of pub keys that have the label
659 string strAccount = AccountFromValue(params[0]);
660 set<CBitcoinAddress> setAddress;
661 GetAccountAddresses(strAccount, setAddress);
665 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
667 const CWalletTx& wtx = (*it).second;
668 if (wtx.IsCoinBase() || !wtx.IsFinal())
671 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
673 CBitcoinAddress address;
674 if (ExtractAddress(txout.scriptPubKey, pwalletMain, address) && setAddress.count(address))
675 if (wtx.GetDepthInMainChain() >= nMinDepth)
676 nAmount += txout.nValue;
680 return (double)nAmount / (double)COIN;
684 int64 GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth)
688 // Tally wallet transactions
689 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
691 const CWalletTx& wtx = (*it).second;
695 int64 nGenerated, nReceived, nSent, nFee;
696 wtx.GetAccountAmounts(strAccount, nGenerated, nReceived, nSent, nFee);
698 if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
699 nBalance += nReceived;
700 nBalance += nGenerated - nSent - nFee;
703 // Tally internal accounting entries
704 nBalance += walletdb.GetAccountCreditDebit(strAccount);
709 int64 GetAccountBalance(const string& strAccount, int nMinDepth)
711 CWalletDB walletdb(pwalletMain->strWalletFile);
712 return GetAccountBalance(walletdb, strAccount, nMinDepth);
716 Value getbalance(const Array& params, bool fHelp)
718 if (fHelp || params.size() > 2)
720 "getbalance [account] [minconf=1]\n"
721 "If [account] is not specified, returns the server's total available balance.\n"
722 "If [account] is specified, returns the balance in the account.");
724 if (params.size() == 0)
725 return ValueFromAmount(pwalletMain->GetBalance());
728 if (params.size() > 1)
729 nMinDepth = params[1].get_int();
731 if (params[0].get_str() == "*") {
732 // Calculate total balance a different way from GetBalance()
733 // (GetBalance() sums up all unspent TxOuts)
734 // getbalance and getbalance '*' should always return the same number.
736 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
738 const CWalletTx& wtx = (*it).second;
742 int64 allGeneratedImmature, allGeneratedMature, allFee;
743 allGeneratedImmature = allGeneratedMature = allFee = 0;
744 string strSentAccount;
745 list<pair<CBitcoinAddress, int64> > listReceived;
746 list<pair<CBitcoinAddress, int64> > listSent;
747 wtx.GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount);
748 if (wtx.GetDepthInMainChain() >= nMinDepth)
749 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listReceived)
750 nBalance += r.second;
751 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listSent)
752 nBalance -= r.second;
754 nBalance += allGeneratedMature;
756 return ValueFromAmount(nBalance);
759 string strAccount = AccountFromValue(params[0]);
761 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
763 return ValueFromAmount(nBalance);
767 Value movecmd(const Array& params, bool fHelp)
769 if (fHelp || params.size() < 3 || params.size() > 5)
771 "move <fromaccount> <toaccount> <amount> [minconf=1] [comment]\n"
772 "Move from one account in your wallet to another.");
774 string strFrom = AccountFromValue(params[0]);
775 string strTo = AccountFromValue(params[1]);
776 int64 nAmount = AmountFromValue(params[2]);
777 if (params.size() > 3)
778 // unused parameter, used to be nMinDepth, keep type-checking it though
779 (void)params[3].get_int();
781 if (params.size() > 4)
782 strComment = params[4].get_str();
784 CWalletDB walletdb(pwalletMain->strWalletFile);
787 int64 nNow = GetAdjustedTime();
790 CAccountingEntry debit;
791 debit.strAccount = strFrom;
792 debit.nCreditDebit = -nAmount;
794 debit.strOtherAccount = strTo;
795 debit.strComment = strComment;
796 walletdb.WriteAccountingEntry(debit);
799 CAccountingEntry credit;
800 credit.strAccount = strTo;
801 credit.nCreditDebit = nAmount;
803 credit.strOtherAccount = strFrom;
804 credit.strComment = strComment;
805 walletdb.WriteAccountingEntry(credit);
807 walletdb.TxnCommit();
813 Value sendfrom(const Array& params, bool fHelp)
815 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
817 "sendfrom <fromaccount> <tobitcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
818 "<amount> is a real and is rounded to the nearest 0.00000001\n"
819 "requires wallet passphrase to be set with walletpassphrase first");
820 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
822 "sendfrom <fromaccount> <tobitcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
823 "<amount> is a real and is rounded to the nearest 0.00000001");
825 string strAccount = AccountFromValue(params[0]);
826 CBitcoinAddress address(params[1].get_str());
827 if (!address.IsValid())
828 throw JSONRPCError(-5, "Invalid bitcoin address");
829 int64 nAmount = AmountFromValue(params[2]);
831 if (params.size() > 3)
832 nMinDepth = params[3].get_int();
835 wtx.strFromAccount = strAccount;
836 if (params.size() > 4 && params[4].type() != null_type && !params[4].get_str().empty())
837 wtx.mapValue["comment"] = params[4].get_str();
838 if (params.size() > 5 && params[5].type() != null_type && !params[5].get_str().empty())
839 wtx.mapValue["to"] = params[5].get_str();
841 if (pwalletMain->IsLocked())
842 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
845 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
846 if (nAmount > nBalance)
847 throw JSONRPCError(-6, "Account has insufficient funds");
850 string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
852 throw JSONRPCError(-4, strError);
854 return wtx.GetHash().GetHex();
858 Value sendmany(const Array& params, bool fHelp)
860 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
862 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
863 "amounts are double-precision floating point numbers\n"
864 "requires wallet passphrase to be set with walletpassphrase first");
865 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
867 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
868 "amounts are double-precision floating point numbers");
870 string strAccount = AccountFromValue(params[0]);
871 Object sendTo = params[1].get_obj();
873 if (params.size() > 2)
874 nMinDepth = params[2].get_int();
877 wtx.strFromAccount = strAccount;
878 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
879 wtx.mapValue["comment"] = params[3].get_str();
881 set<CBitcoinAddress> setAddress;
882 vector<pair<CScript, int64> > vecSend;
884 int64 totalAmount = 0;
885 BOOST_FOREACH(const Pair& s, sendTo)
887 CBitcoinAddress address(s.name_);
888 if (!address.IsValid())
889 throw JSONRPCError(-5, string("Invalid bitcoin address:")+s.name_);
891 if (setAddress.count(address))
892 throw JSONRPCError(-8, string("Invalid parameter, duplicated address: ")+s.name_);
893 setAddress.insert(address);
895 CScript scriptPubKey;
896 scriptPubKey.SetBitcoinAddress(address);
897 int64 nAmount = AmountFromValue(s.value_);
898 totalAmount += nAmount;
900 vecSend.push_back(make_pair(scriptPubKey, nAmount));
903 if (pwalletMain->IsLocked())
904 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
907 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
908 if (totalAmount > nBalance)
909 throw JSONRPCError(-6, "Account has insufficient funds");
912 CReserveKey keyChange(pwalletMain);
913 int64 nFeeRequired = 0;
914 bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired);
917 if (totalAmount + nFeeRequired > pwalletMain->GetBalance())
918 throw JSONRPCError(-6, "Insufficient funds");
919 throw JSONRPCError(-4, "Transaction creation failed");
921 if (!pwalletMain->CommitTransaction(wtx, keyChange))
922 throw JSONRPCError(-4, "Transaction commit failed");
924 return wtx.GetHash().GetHex();
939 Value ListReceived(const Array& params, bool fByAccounts)
941 // Minimum confirmations
943 if (params.size() > 0)
944 nMinDepth = params[0].get_int();
946 // Whether to include empty accounts
947 bool fIncludeEmpty = false;
948 if (params.size() > 1)
949 fIncludeEmpty = params[1].get_bool();
952 map<CBitcoinAddress, tallyitem> mapTally;
953 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
955 const CWalletTx& wtx = (*it).second;
956 if (wtx.IsCoinBase() || !wtx.IsFinal())
959 int nDepth = wtx.GetDepthInMainChain();
960 if (nDepth < nMinDepth)
963 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
965 CBitcoinAddress address;
966 if (!ExtractAddress(txout.scriptPubKey, pwalletMain, address) || !address.IsValid())
969 tallyitem& item = mapTally[address];
970 item.nAmount += txout.nValue;
971 item.nConf = min(item.nConf, nDepth);
977 map<string, tallyitem> mapAccountTally;
978 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
980 const CBitcoinAddress& address = item.first;
981 const string& strAccount = item.second;
982 map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
983 if (it == mapTally.end() && !fIncludeEmpty)
988 if (it != mapTally.end())
990 nAmount = (*it).second.nAmount;
991 nConf = (*it).second.nConf;
996 tallyitem& item = mapAccountTally[strAccount];
997 item.nAmount += nAmount;
998 item.nConf = min(item.nConf, nConf);
1003 obj.push_back(Pair("address", address.ToString()));
1004 obj.push_back(Pair("account", strAccount));
1005 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1006 obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf)));
1013 for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
1015 int64 nAmount = (*it).second.nAmount;
1016 int nConf = (*it).second.nConf;
1018 obj.push_back(Pair("account", (*it).first));
1019 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1020 obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf)));
1028 Value listreceivedbyaddress(const Array& params, bool fHelp)
1030 if (fHelp || params.size() > 2)
1031 throw runtime_error(
1032 "listreceivedbyaddress [minconf=1] [includeempty=false]\n"
1033 "[minconf] is the minimum number of confirmations before payments are included.\n"
1034 "[includeempty] whether to include addresses that haven't received any payments.\n"
1035 "Returns an array of objects containing:\n"
1036 " \"address\" : receiving address\n"
1037 " \"account\" : the account of the receiving address\n"
1038 " \"amount\" : total amount received by the address\n"
1039 " \"confirmations\" : number of confirmations of the most recent transaction included");
1041 return ListReceived(params, false);
1044 Value listreceivedbyaccount(const Array& params, bool fHelp)
1046 if (fHelp || params.size() > 2)
1047 throw runtime_error(
1048 "listreceivedbyaccount [minconf=1] [includeempty=false]\n"
1049 "[minconf] is the minimum number of confirmations before payments are included.\n"
1050 "[includeempty] whether to include accounts that haven't received any payments.\n"
1051 "Returns an array of objects containing:\n"
1052 " \"account\" : the account of the receiving addresses\n"
1053 " \"amount\" : total amount received by addresses with this account\n"
1054 " \"confirmations\" : number of confirmations of the most recent transaction included");
1056 return ListReceived(params, true);
1059 void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret)
1061 int64 nGeneratedImmature, nGeneratedMature, nFee;
1062 string strSentAccount;
1063 list<pair<CBitcoinAddress, int64> > listReceived;
1064 list<pair<CBitcoinAddress, int64> > listSent;
1065 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1067 bool fAllAccounts = (strAccount == string("*"));
1069 // Generated blocks assigned to account ""
1070 if ((nGeneratedMature+nGeneratedImmature) != 0 && (fAllAccounts || strAccount == ""))
1073 entry.push_back(Pair("account", string("")));
1074 if (nGeneratedImmature)
1076 entry.push_back(Pair("category", wtx.GetDepthInMainChain() ? "immature" : "orphan"));
1077 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedImmature)));
1081 entry.push_back(Pair("category", "generate"));
1082 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedMature)));
1085 WalletTxToJSON(wtx, entry);
1086 ret.push_back(entry);
1090 if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
1092 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1095 entry.push_back(Pair("account", strSentAccount));
1096 entry.push_back(Pair("address", s.first.ToString()));
1097 entry.push_back(Pair("category", "send"));
1098 entry.push_back(Pair("amount", ValueFromAmount(-s.second)));
1099 entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
1101 WalletTxToJSON(wtx, entry);
1102 ret.push_back(entry);
1107 if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
1108 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1111 if (pwalletMain->mapAddressBook.count(r.first))
1112 account = pwalletMain->mapAddressBook[r.first];
1113 if (fAllAccounts || (account == strAccount))
1116 entry.push_back(Pair("account", account));
1117 entry.push_back(Pair("address", r.first.ToString()));
1118 entry.push_back(Pair("category", "receive"));
1119 entry.push_back(Pair("amount", ValueFromAmount(r.second)));
1121 WalletTxToJSON(wtx, entry);
1122 ret.push_back(entry);
1127 void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret)
1129 bool fAllAccounts = (strAccount == string("*"));
1131 if (fAllAccounts || acentry.strAccount == strAccount)
1134 entry.push_back(Pair("account", acentry.strAccount));
1135 entry.push_back(Pair("category", "move"));
1136 entry.push_back(Pair("time", (boost::int64_t)acentry.nTime));
1137 entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
1138 entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
1139 entry.push_back(Pair("comment", acentry.strComment));
1140 ret.push_back(entry);
1144 Value listtransactions(const Array& params, bool fHelp)
1146 if (fHelp || params.size() > 3)
1147 throw runtime_error(
1148 "listtransactions [account] [count=10] [from=0]\n"
1149 "Returns up to [count] most recent transactions skipping the first [from] transactions for account [account].");
1151 string strAccount = "*";
1152 if (params.size() > 0)
1153 strAccount = params[0].get_str();
1155 if (params.size() > 1)
1156 nCount = params[1].get_int();
1158 if (params.size() > 2)
1159 nFrom = params[2].get_int();
1162 CWalletDB walletdb(pwalletMain->strWalletFile);
1164 // Firs: get all CWalletTx and CAccountingEntry into a sorted-by-time multimap:
1165 typedef pair<CWalletTx*, CAccountingEntry*> TxPair;
1166 typedef multimap<int64, TxPair > TxItems;
1169 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1171 CWalletTx* wtx = &((*it).second);
1172 txByTime.insert(make_pair(wtx->GetTxTime(), TxPair(wtx, (CAccountingEntry*)0)));
1174 list<CAccountingEntry> acentries;
1175 walletdb.ListAccountCreditDebit(strAccount, acentries);
1176 BOOST_FOREACH(CAccountingEntry& entry, acentries)
1178 txByTime.insert(make_pair(entry.nTime, TxPair((CWalletTx*)0, &entry)));
1181 // Now: iterate backwards until we have nCount items to return:
1182 TxItems::reverse_iterator it = txByTime.rbegin();
1183 if (txByTime.size() > nFrom) std::advance(it, nFrom);
1184 for (; it != txByTime.rend(); ++it)
1186 CWalletTx *const pwtx = (*it).second.first;
1188 ListTransactions(*pwtx, strAccount, 0, true, ret);
1189 CAccountingEntry *const pacentry = (*it).second.second;
1191 AcentryToJSON(*pacentry, strAccount, ret);
1193 if (ret.size() >= nCount) break;
1195 // ret is now newest to oldest
1197 // Make sure we return only last nCount items (sends-to-self might give us an extra):
1198 if (ret.size() > nCount)
1200 Array::iterator last = ret.begin();
1201 std::advance(last, nCount);
1202 ret.erase(last, ret.end());
1204 std::reverse(ret.begin(), ret.end()); // oldest to newest
1209 Value listaccounts(const Array& params, bool fHelp)
1211 if (fHelp || params.size() > 1)
1212 throw runtime_error(
1213 "listaccounts [minconf=1]\n"
1214 "Returns Object that has account names as keys, account balances as values.");
1217 if (params.size() > 0)
1218 nMinDepth = params[0].get_int();
1220 map<string, int64> mapAccountBalances;
1221 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& entry, pwalletMain->mapAddressBook) {
1222 if (pwalletMain->HaveKey(entry.first)) // This address belongs to me
1223 mapAccountBalances[entry.second] = 0;
1226 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1228 const CWalletTx& wtx = (*it).second;
1229 int64 nGeneratedImmature, nGeneratedMature, nFee;
1230 string strSentAccount;
1231 list<pair<CBitcoinAddress, int64> > listReceived;
1232 list<pair<CBitcoinAddress, int64> > listSent;
1233 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1234 mapAccountBalances[strSentAccount] -= nFee;
1235 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1236 mapAccountBalances[strSentAccount] -= s.second;
1237 if (wtx.GetDepthInMainChain() >= nMinDepth)
1239 mapAccountBalances[""] += nGeneratedMature;
1240 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1241 if (pwalletMain->mapAddressBook.count(r.first))
1242 mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second;
1244 mapAccountBalances[""] += r.second;
1248 list<CAccountingEntry> acentries;
1249 CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
1250 BOOST_FOREACH(const CAccountingEntry& entry, acentries)
1251 mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
1254 BOOST_FOREACH(const PAIRTYPE(string, int64)& accountBalance, mapAccountBalances) {
1255 ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
1260 Value listsinceblock(const Array& params, bool fHelp)
1263 throw runtime_error(
1264 "listsinceblock [blockid] [target-confirmations]\n"
1265 "Get all transactions in blocks since block [blockid], or all transactions if omitted");
1267 CBlockIndex *pindex = NULL;
1268 int target_confirms = 1;
1270 if (params.size() > 0)
1272 uint256 blockId = 0;
1274 blockId.SetHex(params[0].get_str());
1275 pindex = CBlockLocator(blockId).GetBlockIndex();
1278 if (params.size() > 1)
1280 target_confirms = params[1].get_int();
1282 if (target_confirms < 1)
1283 throw JSONRPCError(-8, "Invalid parameter");
1286 int depth = pindex ? (1 + nBestHeight - pindex->nHeight) : -1;
1290 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++)
1292 CWalletTx tx = (*it).second;
1294 if (depth == -1 || tx.GetDepthInMainChain() < depth)
1295 ListTransactions(tx, "*", 0, true, transactions);
1300 if (target_confirms == 1)
1303 lastblock = hashBestChain;
1307 int target_height = pindexBest->nHeight + 1 - target_confirms;
1310 for (block = pindexBest;
1311 block && block->nHeight > target_height;
1312 block = block->pprev);
1314 lastblock = block ? block->GetBlockHash() : 0;
1318 ret.push_back(Pair("transactions", transactions));
1319 ret.push_back(Pair("lastblock", lastblock.GetHex()));
1324 Value gettransaction(const Array& params, bool fHelp)
1326 if (fHelp || params.size() != 1)
1327 throw runtime_error(
1328 "gettransaction <txid>\n"
1329 "Get detailed information about <txid>");
1332 hash.SetHex(params[0].get_str());
1336 if (!pwalletMain->mapWallet.count(hash))
1337 throw JSONRPCError(-5, "Invalid or non-wallet transaction id");
1338 const CWalletTx& wtx = pwalletMain->mapWallet[hash];
1340 int64 nCredit = wtx.GetCredit();
1341 int64 nDebit = wtx.GetDebit();
1342 int64 nNet = nCredit - nDebit;
1343 int64 nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0);
1345 entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
1347 entry.push_back(Pair("fee", ValueFromAmount(nFee)));
1349 WalletTxToJSON(pwalletMain->mapWallet[hash], entry);
1352 ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details);
1353 entry.push_back(Pair("details", details));
1359 Value backupwallet(const Array& params, bool fHelp)
1361 if (fHelp || params.size() != 1)
1362 throw runtime_error(
1363 "backupwallet <destination>\n"
1364 "Safely copies wallet.dat to destination, which can be a directory or a path with filename.");
1366 string strDest = params[0].get_str();
1367 BackupWallet(*pwalletMain, strDest);
1373 Value keypoolrefill(const Array& params, bool fHelp)
1375 if (pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1376 throw runtime_error(
1378 "Fills the keypool, requires wallet passphrase to be set.");
1379 if (!pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1380 throw runtime_error(
1382 "Fills the keypool.");
1384 if (pwalletMain->IsLocked())
1385 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
1387 pwalletMain->TopUpKeyPool();
1389 if (pwalletMain->GetKeyPoolSize() < GetArg("-keypool", 100))
1390 throw JSONRPCError(-4, "Error refreshing keypool.");
1396 void ThreadTopUpKeyPool(void* parg)
1398 pwalletMain->TopUpKeyPool();
1401 void ThreadCleanWalletPassphrase(void* parg)
1403 int64 nMyWakeTime = GetTime() + *((int*)parg);
1405 if (nWalletUnlockTime == 0)
1407 CRITICAL_BLOCK(cs_nWalletUnlockTime)
1409 nWalletUnlockTime = nMyWakeTime;
1412 while (GetTime() < nWalletUnlockTime)
1413 Sleep(GetTime() - nWalletUnlockTime);
1415 CRITICAL_BLOCK(cs_nWalletUnlockTime)
1417 nWalletUnlockTime = 0;
1422 CRITICAL_BLOCK(cs_nWalletUnlockTime)
1424 if (nWalletUnlockTime < nMyWakeTime)
1425 nWalletUnlockTime = nMyWakeTime;
1431 pwalletMain->Lock();
1436 Value walletpassphrase(const Array& params, bool fHelp)
1438 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1439 throw runtime_error(
1440 "walletpassphrase <passphrase> <timeout>\n"
1441 "Stores the wallet decryption key in memory for <timeout> seconds.");
1444 if (!pwalletMain->IsCrypted())
1445 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
1447 if (!pwalletMain->IsLocked())
1448 throw JSONRPCError(-17, "Error: Wallet is already unlocked.");
1450 // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
1451 string strWalletPass;
1452 strWalletPass.reserve(100);
1453 mlock(&strWalletPass[0], strWalletPass.capacity());
1454 strWalletPass = params[0].get_str();
1456 if (strWalletPass.length() > 0)
1458 if (!pwalletMain->Unlock(strWalletPass))
1460 fill(strWalletPass.begin(), strWalletPass.end(), '\0');
1461 munlock(&strWalletPass[0], strWalletPass.capacity());
1462 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1464 fill(strWalletPass.begin(), strWalletPass.end(), '\0');
1465 munlock(&strWalletPass[0], strWalletPass.capacity());
1468 throw runtime_error(
1469 "walletpassphrase <passphrase> <timeout>\n"
1470 "Stores the wallet decryption key in memory for <timeout> seconds.");
1472 CreateThread(ThreadTopUpKeyPool, NULL);
1473 int* pnSleepTime = new int(params[1].get_int());
1474 CreateThread(ThreadCleanWalletPassphrase, pnSleepTime);
1480 Value walletpassphrasechange(const Array& params, bool fHelp)
1482 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1483 throw runtime_error(
1484 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1485 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1488 if (!pwalletMain->IsCrypted())
1489 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
1491 string strOldWalletPass;
1492 strOldWalletPass.reserve(100);
1493 mlock(&strOldWalletPass[0], strOldWalletPass.capacity());
1494 strOldWalletPass = params[0].get_str();
1496 string strNewWalletPass;
1497 strNewWalletPass.reserve(100);
1498 mlock(&strNewWalletPass[0], strNewWalletPass.capacity());
1499 strNewWalletPass = params[1].get_str();
1501 if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
1502 throw runtime_error(
1503 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1504 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1506 if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
1508 fill(strOldWalletPass.begin(), strOldWalletPass.end(), '\0');
1509 fill(strNewWalletPass.begin(), strNewWalletPass.end(), '\0');
1510 munlock(&strOldWalletPass[0], strOldWalletPass.capacity());
1511 munlock(&strNewWalletPass[0], strNewWalletPass.capacity());
1512 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1514 fill(strNewWalletPass.begin(), strNewWalletPass.end(), '\0');
1515 fill(strOldWalletPass.begin(), strOldWalletPass.end(), '\0');
1516 munlock(&strOldWalletPass[0], strOldWalletPass.capacity());
1517 munlock(&strNewWalletPass[0], strNewWalletPass.capacity());
1523 Value walletlock(const Array& params, bool fHelp)
1525 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
1526 throw runtime_error(
1528 "Removes the wallet encryption key from memory, locking the wallet.\n"
1529 "After calling this method, you will need to call walletpassphrase again\n"
1530 "before being able to call any methods which require the wallet to be unlocked.");
1533 if (!pwalletMain->IsCrypted())
1534 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletlock was called.");
1536 pwalletMain->Lock();
1537 CRITICAL_BLOCK(cs_nWalletUnlockTime)
1539 nWalletUnlockTime = 0;
1546 Value encryptwallet(const Array& params, bool fHelp)
1548 if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
1549 throw runtime_error(
1550 "encryptwallet <passphrase>\n"
1551 "Encrypts the wallet with <passphrase>.");
1554 if (pwalletMain->IsCrypted())
1555 throw JSONRPCError(-15, "Error: running with an encrypted wallet, but encryptwallet was called.");
1557 string strWalletPass;
1558 strWalletPass.reserve(100);
1559 mlock(&strWalletPass[0], strWalletPass.capacity());
1560 strWalletPass = params[0].get_str();
1562 if (strWalletPass.length() < 1)
1563 throw runtime_error(
1564 "encryptwallet <passphrase>\n"
1565 "Encrypts the wallet with <passphrase>.");
1567 if (!pwalletMain->EncryptWallet(strWalletPass))
1569 fill(strWalletPass.begin(), strWalletPass.end(), '\0');
1570 munlock(&strWalletPass[0], strWalletPass.capacity());
1571 throw JSONRPCError(-16, "Error: Failed to encrypt the wallet.");
1573 fill(strWalletPass.begin(), strWalletPass.end(), '\0');
1574 munlock(&strWalletPass[0], strWalletPass.capacity());
1580 Value validateaddress(const Array& params, bool fHelp)
1582 if (fHelp || params.size() != 1)
1583 throw runtime_error(
1584 "validateaddress <bitcoinaddress>\n"
1585 "Return information about <bitcoinaddress>.");
1587 CBitcoinAddress address(params[0].get_str());
1588 bool isValid = address.IsValid();
1591 ret.push_back(Pair("isvalid", isValid));
1594 // Call Hash160ToAddress() so we always return current ADDRESSVERSION
1595 // version of the address:
1596 string currentAddress = address.ToString();
1597 ret.push_back(Pair("address", currentAddress));
1598 ret.push_back(Pair("ismine", (pwalletMain->HaveKey(address) > 0)));
1599 if (pwalletMain->mapAddressBook.count(address))
1600 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));
1776 result.push_back(Pair("bits", (int64_t)pblock->nBits));
1782 CDataStream ssBlock(ParseHex(params[0].get_str()));
1786 return ProcessBlock(NULL, &pblock);
1804 pair<string, rpcfn_type> pCallTable[] =
1806 make_pair("help", &help),
1807 make_pair("stop", &stop),
1808 make_pair("getblockcount", &getblockcount),
1809 make_pair("getblocknumber", &getblocknumber),
1810 make_pair("getconnectioncount", &getconnectioncount),
1811 make_pair("getdifficulty", &getdifficulty),
1812 make_pair("getgenerate", &getgenerate),
1813 make_pair("setgenerate", &setgenerate),
1814 make_pair("gethashespersec", &gethashespersec),
1815 make_pair("getinfo", &getinfo),
1816 make_pair("getnewaddress", &getnewaddress),
1817 make_pair("getaccountaddress", &getaccountaddress),
1818 make_pair("setaccount", &setaccount),
1819 make_pair("getaccount", &getaccount),
1820 make_pair("getaddressesbyaccount", &getaddressesbyaccount),
1821 make_pair("sendtoaddress", &sendtoaddress),
1822 make_pair("getreceivedbyaddress", &getreceivedbyaddress),
1823 make_pair("getreceivedbyaccount", &getreceivedbyaccount),
1824 make_pair("listreceivedbyaddress", &listreceivedbyaddress),
1825 make_pair("listreceivedbyaccount", &listreceivedbyaccount),
1826 make_pair("backupwallet", &backupwallet),
1827 make_pair("keypoolrefill", &keypoolrefill),
1828 make_pair("walletpassphrase", &walletpassphrase),
1829 make_pair("walletpassphrasechange", &walletpassphrasechange),
1830 make_pair("walletlock", &walletlock),
1831 make_pair("encryptwallet", &encryptwallet),
1832 make_pair("validateaddress", &validateaddress),
1833 make_pair("getbalance", &getbalance),
1834 make_pair("move", &movecmd),
1835 make_pair("sendfrom", &sendfrom),
1836 make_pair("sendmany", &sendmany),
1837 make_pair("gettransaction", &gettransaction),
1838 make_pair("listtransactions", &listtransactions),
1839 make_pair("signmessage", &signmessage),
1840 make_pair("verifymessage", &verifymessage),
1841 make_pair("getwork", &getwork),
1842 make_pair("listaccounts", &listaccounts),
1843 make_pair("settxfee", &settxfee),
1844 make_pair("getmemorypool", &getmemorypool),
1845 make_pair("listsinceblock", &listsinceblock),
1847 map<string, rpcfn_type> mapCallTable(pCallTable, pCallTable + sizeof(pCallTable)/sizeof(pCallTable[0]));
1849 string pAllowInSafeMode[] =
1855 "getconnectioncount",
1862 "getaccountaddress",
1864 "getaddressesbyaccount",
1873 set<string> setAllowInSafeMode(pAllowInSafeMode, pAllowInSafeMode + sizeof(pAllowInSafeMode)/sizeof(pAllowInSafeMode[0]));
1881 // This ain't Apache. We're just using HTTP header for the length field
1882 // and to be compatible with other JSON-RPC implementations.
1885 string HTTPPost(const string& strMsg, const map<string,string>& mapRequestHeaders)
1888 s << "POST / HTTP/1.1\r\n"
1889 << "User-Agent: bitcoin-json-rpc/" << FormatFullVersion() << "\r\n"
1890 << "Host: 127.0.0.1\r\n"
1891 << "Content-Type: application/json\r\n"
1892 << "Content-Length: " << strMsg.size() << "\r\n"
1893 << "Connection: close\r\n"
1894 << "Accept: application/json\r\n";
1895 BOOST_FOREACH(const PAIRTYPE(string, string)& item, mapRequestHeaders)
1896 s << item.first << ": " << item.second << "\r\n";
1897 s << "\r\n" << strMsg;
1902 string rfc1123Time()
1907 struct tm* now_gmt = gmtime(&now);
1908 string locale(setlocale(LC_TIME, NULL));
1909 setlocale(LC_TIME, "C"); // we want posix (aka "C") weekday/month strings
1910 strftime(buffer, sizeof(buffer), "%a, %d %b %Y %H:%M:%S +0000", now_gmt);
1911 setlocale(LC_TIME, locale.c_str());
1912 return string(buffer);
1915 static string HTTPReply(int nStatus, const string& strMsg)
1918 return strprintf("HTTP/1.0 401 Authorization Required\r\n"
1920 "Server: bitcoin-json-rpc/%s\r\n"
1921 "WWW-Authenticate: Basic realm=\"jsonrpc\"\r\n"
1922 "Content-Type: text/html\r\n"
1923 "Content-Length: 296\r\n"
1925 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\r\n"
1926 "\"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd\">\r\n"
1929 "<TITLE>Error</TITLE>\r\n"
1930 "<META HTTP-EQUIV='Content-Type' CONTENT='text/html; charset=ISO-8859-1'>\r\n"
1932 "<BODY><H1>401 Unauthorized.</H1></BODY>\r\n"
1933 "</HTML>\r\n", rfc1123Time().c_str(), FormatFullVersion().c_str());
1934 const char *cStatus;
1935 if (nStatus == 200) cStatus = "OK";
1936 else if (nStatus == 400) cStatus = "Bad Request";
1937 else if (nStatus == 403) cStatus = "Forbidden";
1938 else if (nStatus == 404) cStatus = "Not Found";
1939 else if (nStatus == 500) cStatus = "Internal Server Error";
1942 "HTTP/1.1 %d %s\r\n"
1944 "Connection: close\r\n"
1945 "Content-Length: %d\r\n"
1946 "Content-Type: application/json\r\n"
1947 "Server: bitcoin-json-rpc/%s\r\n"
1952 rfc1123Time().c_str(),
1954 FormatFullVersion().c_str(),
1958 int ReadHTTPStatus(std::basic_istream<char>& stream)
1961 getline(stream, str);
1962 vector<string> vWords;
1963 boost::split(vWords, str, boost::is_any_of(" "));
1964 if (vWords.size() < 2)
1966 return atoi(vWords[1].c_str());
1969 int ReadHTTPHeader(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet)
1975 std::getline(stream, str);
1976 if (str.empty() || str == "\r")
1978 string::size_type nColon = str.find(":");
1979 if (nColon != string::npos)
1981 string strHeader = str.substr(0, nColon);
1982 boost::trim(strHeader);
1983 boost::to_lower(strHeader);
1984 string strValue = str.substr(nColon+1);
1985 boost::trim(strValue);
1986 mapHeadersRet[strHeader] = strValue;
1987 if (strHeader == "content-length")
1988 nLen = atoi(strValue.c_str());
1994 int ReadHTTP(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet, string& strMessageRet)
1996 mapHeadersRet.clear();
2000 int nStatus = ReadHTTPStatus(stream);
2003 int nLen = ReadHTTPHeader(stream, mapHeadersRet);
2004 if (nLen < 0 || nLen > MAX_SIZE)
2010 vector<char> vch(nLen);
2011 stream.read(&vch[0], nLen);
2012 strMessageRet = string(vch.begin(), vch.end());
2018 bool HTTPAuthorized(map<string, string>& mapHeaders)
2020 string strAuth = mapHeaders["authorization"];
2021 if (strAuth.substr(0,6) != "Basic ")
2023 string strUserPass64 = strAuth.substr(6); boost::trim(strUserPass64);
2024 string strUserPass = DecodeBase64(strUserPass64);
2025 string::size_type nColon = strUserPass.find(":");
2026 if (nColon == string::npos)
2028 string strUser = strUserPass.substr(0, nColon);
2029 string strPassword = strUserPass.substr(nColon+1);
2030 return (strUser == mapArgs["-rpcuser"] && strPassword == mapArgs["-rpcpassword"]);
2034 // JSON-RPC protocol. Bitcoin speaks version 1.0 for maximum compatibility,
2035 // but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
2036 // unspecified (HTTP errors and contents of 'error').
2038 // 1.0 spec: http://json-rpc.org/wiki/specification
2039 // 1.2 spec: http://groups.google.com/group/json-rpc/web/json-rpc-over-http
2040 // http://www.codeproject.com/KB/recipes/JSON_Spirit.aspx
2043 string JSONRPCRequest(const string& strMethod, const Array& params, const Value& id)
2046 request.push_back(Pair("method", strMethod));
2047 request.push_back(Pair("params", params));
2048 request.push_back(Pair("id", id));
2049 return write_string(Value(request), false) + "\n";
2052 string JSONRPCReply(const Value& result, const Value& error, const Value& id)
2055 if (error.type() != null_type)
2056 reply.push_back(Pair("result", Value::null));
2058 reply.push_back(Pair("result", result));
2059 reply.push_back(Pair("error", error));
2060 reply.push_back(Pair("id", id));
2061 return write_string(Value(reply), false) + "\n";
2064 void ErrorReply(std::ostream& stream, const Object& objError, const Value& id)
2066 // Send error reply from json-rpc error object
2068 int code = find_value(objError, "code").get_int();
2069 if (code == -32600) nStatus = 400;
2070 else if (code == -32601) nStatus = 404;
2071 string strReply = JSONRPCReply(Value::null, objError, id);
2072 stream << HTTPReply(nStatus, strReply) << std::flush;
2075 bool ClientAllowed(const string& strAddress)
2077 if (strAddress == asio::ip::address_v4::loopback().to_string())
2079 const vector<string>& vAllow = mapMultiArgs["-rpcallowip"];
2080 BOOST_FOREACH(string strAllow, vAllow)
2081 if (WildcardMatch(strAddress, strAllow))
2088 // IOStream device that speaks SSL but can also speak non-SSL
2090 class SSLIOStreamDevice : public iostreams::device<iostreams::bidirectional> {
2092 SSLIOStreamDevice(SSLStream &streamIn, bool fUseSSLIn) : stream(streamIn)
2094 fUseSSL = fUseSSLIn;
2095 fNeedHandshake = fUseSSLIn;
2098 void handshake(ssl::stream_base::handshake_type role)
2100 if (!fNeedHandshake) return;
2101 fNeedHandshake = false;
2102 stream.handshake(role);
2104 std::streamsize read(char* s, std::streamsize n)
2106 handshake(ssl::stream_base::server); // HTTPS servers read first
2107 if (fUseSSL) return stream.read_some(asio::buffer(s, n));
2108 return stream.next_layer().read_some(asio::buffer(s, n));
2110 std::streamsize write(const char* s, std::streamsize n)
2112 handshake(ssl::stream_base::client); // HTTPS clients write first
2113 if (fUseSSL) return asio::write(stream, asio::buffer(s, n));
2114 return asio::write(stream.next_layer(), asio::buffer(s, n));
2116 bool connect(const std::string& server, const std::string& port)
2118 ip::tcp::resolver resolver(stream.get_io_service());
2119 ip::tcp::resolver::query query(server.c_str(), port.c_str());
2120 ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
2121 ip::tcp::resolver::iterator end;
2122 boost::system::error_code error = asio::error::host_not_found;
2123 while (error && endpoint_iterator != end)
2125 stream.lowest_layer().close();
2126 stream.lowest_layer().connect(*endpoint_iterator++, error);
2134 bool fNeedHandshake;
2140 void ThreadRPCServer(void* parg)
2142 IMPLEMENT_RANDOMIZE_STACK(ThreadRPCServer(parg));
2145 vnThreadsRunning[4]++;
2146 ThreadRPCServer2(parg);
2147 vnThreadsRunning[4]--;
2149 catch (std::exception& e) {
2150 vnThreadsRunning[4]--;
2151 PrintException(&e, "ThreadRPCServer()");
2153 vnThreadsRunning[4]--;
2154 PrintException(NULL, "ThreadRPCServer()");
2156 printf("ThreadRPCServer exiting\n");
2159 void ThreadRPCServer2(void* parg)
2161 printf("ThreadRPCServer started\n");
2163 if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
2165 string strWhatAmI = "To use bitcoind";
2166 if (mapArgs.count("-server"))
2167 strWhatAmI = strprintf(_("To use the %s option"), "\"-server\"");
2168 else if (mapArgs.count("-daemon"))
2169 strWhatAmI = strprintf(_("To use the %s option"), "\"-daemon\"");
2171 _("Warning: %s, you must set rpcpassword=<password>\nin the configuration file: %s\n"
2172 "If the file does not exist, create it with owner-readable-only file permissions.\n"),
2174 GetConfigFile().c_str());
2175 CreateThread(Shutdown, NULL);
2179 bool fUseSSL = GetBoolArg("-rpcssl");
2180 asio::ip::address bindAddress = mapArgs.count("-rpcallowip") ? asio::ip::address_v4::any() : asio::ip::address_v4::loopback();
2182 asio::io_service io_service;
2183 ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", 8332));
2184 ip::tcp::acceptor acceptor(io_service, endpoint);
2186 acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
2189 ssl::context context(io_service, ssl::context::sslv23);
2192 context.set_options(ssl::context::no_sslv2);
2193 filesystem::path certfile = GetArg("-rpcsslcertificatechainfile", "server.cert");
2194 if (!certfile.is_complete()) certfile = filesystem::path(GetDataDir()) / certfile;
2195 if (filesystem::exists(certfile)) context.use_certificate_chain_file(certfile.string().c_str());
2196 else printf("ThreadRPCServer ERROR: missing server certificate file %s\n", certfile.string().c_str());
2197 filesystem::path pkfile = GetArg("-rpcsslprivatekeyfile", "server.pem");
2198 if (!pkfile.is_complete()) pkfile = filesystem::path(GetDataDir()) / pkfile;
2199 if (filesystem::exists(pkfile)) context.use_private_key_file(pkfile.string().c_str(), ssl::context::pem);
2200 else printf("ThreadRPCServer ERROR: missing server private key file %s\n", pkfile.string().c_str());
2202 string ciphers = GetArg("-rpcsslciphers",
2203 "TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH");
2204 SSL_CTX_set_cipher_list(context.impl(), ciphers.c_str());
2208 throw runtime_error("-rpcssl=1, but bitcoin compiled without full openssl libraries.");
2213 // Accept connection
2215 SSLStream sslStream(io_service, context);
2216 SSLIOStreamDevice d(sslStream, fUseSSL);
2217 iostreams::stream<SSLIOStreamDevice> stream(d);
2219 ip::tcp::iostream stream;
2222 ip::tcp::endpoint peer;
2223 vnThreadsRunning[4]--;
2225 acceptor.accept(sslStream.lowest_layer(), peer);
2227 acceptor.accept(*stream.rdbuf(), peer);
2229 vnThreadsRunning[4]++;
2233 // Restrict callers by IP
2234 if (!ClientAllowed(peer.address().to_string()))
2236 // Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake.
2238 stream << HTTPReply(403, "") << std::flush;
2242 map<string, string> mapHeaders;
2245 boost::thread api_caller(ReadHTTP, boost::ref(stream), boost::ref(mapHeaders), boost::ref(strRequest));
2246 if (!api_caller.timed_join(boost::posix_time::seconds(GetArg("-rpctimeout", 30))))
2249 printf("ThreadRPCServer ReadHTTP timeout\n");
2253 // Check authorization
2254 if (mapHeaders.count("authorization") == 0)
2256 stream << HTTPReply(401, "") << std::flush;
2259 if (!HTTPAuthorized(mapHeaders))
2261 // Deter brute-forcing short passwords
2262 if (mapArgs["-rpcpassword"].size() < 15)
2265 stream << HTTPReply(401, "") << std::flush;
2266 printf("ThreadRPCServer incorrect password attempt\n");
2270 Value id = Value::null;
2275 if (!read_string(strRequest, valRequest) || valRequest.type() != obj_type)
2276 throw JSONRPCError(-32700, "Parse error");
2277 const Object& request = valRequest.get_obj();
2279 // Parse id now so errors from here on will have the id
2280 id = find_value(request, "id");
2283 Value valMethod = find_value(request, "method");
2284 if (valMethod.type() == null_type)
2285 throw JSONRPCError(-32600, "Missing method");
2286 if (valMethod.type() != str_type)
2287 throw JSONRPCError(-32600, "Method must be a string");
2288 string strMethod = valMethod.get_str();
2289 if (strMethod != "getwork" && strMethod != "getmemorypool")
2290 printf("ThreadRPCServer method=%s\n", strMethod.c_str());
2293 Value valParams = find_value(request, "params");
2295 if (valParams.type() == array_type)
2296 params = valParams.get_array();
2297 else if (valParams.type() == null_type)
2300 throw JSONRPCError(-32600, "Params must be an array");
2303 map<string, rpcfn_type>::iterator mi = mapCallTable.find(strMethod);
2304 if (mi == mapCallTable.end())
2305 throw JSONRPCError(-32601, "Method not found");
2307 // Observe safe mode
2308 string strWarning = GetWarnings("rpc");
2309 if (strWarning != "" && !GetBoolArg("-disablesafemode") && !setAllowInSafeMode.count(strMethod))
2310 throw JSONRPCError(-2, string("Safe mode: ") + strWarning);
2316 CRITICAL_BLOCK(cs_main)
2317 CRITICAL_BLOCK(pwalletMain->cs_wallet)
2318 result = (*(*mi).second)(params, false);
2321 string strReply = JSONRPCReply(result, Value::null, id);
2322 stream << HTTPReply(200, strReply) << std::flush;
2324 catch (std::exception& e)
2326 ErrorReply(stream, JSONRPCError(-1, e.what()), id);
2329 catch (Object& objError)
2331 ErrorReply(stream, objError, id);
2333 catch (std::exception& e)
2335 ErrorReply(stream, JSONRPCError(-32700, e.what()), id);
2343 Object CallRPC(const string& strMethod, const Array& params)
2345 if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
2346 throw runtime_error(strprintf(
2347 _("You must set rpcpassword=<password> in the configuration file:\n%s\n"
2348 "If the file does not exist, create it with owner-readable-only file permissions."),
2349 GetConfigFile().c_str()));
2351 // Connect to localhost
2352 bool fUseSSL = GetBoolArg("-rpcssl");
2354 asio::io_service io_service;
2355 ssl::context context(io_service, ssl::context::sslv23);
2356 context.set_options(ssl::context::no_sslv2);
2357 SSLStream sslStream(io_service, context);
2358 SSLIOStreamDevice d(sslStream, fUseSSL);
2359 iostreams::stream<SSLIOStreamDevice> stream(d);
2360 if (!d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332")))
2361 throw runtime_error("couldn't connect to server");
2364 throw runtime_error("-rpcssl=1, but bitcoin compiled without full openssl libraries.");
2366 ip::tcp::iostream stream(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332"));
2368 throw runtime_error("couldn't connect to server");
2372 // HTTP basic authentication
2373 string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
2374 map<string, string> mapRequestHeaders;
2375 mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64;
2378 string strRequest = JSONRPCRequest(strMethod, params, 1);
2379 string strPost = HTTPPost(strRequest, mapRequestHeaders);
2380 stream << strPost << std::flush;
2383 map<string, string> mapHeaders;
2385 int nStatus = ReadHTTP(stream, mapHeaders, strReply);
2387 throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
2388 else if (nStatus >= 400 && nStatus != 400 && nStatus != 404 && nStatus != 500)
2389 throw runtime_error(strprintf("server returned HTTP error %d", nStatus));
2390 else if (strReply.empty())
2391 throw runtime_error("no response from server");
2395 if (!read_string(strReply, valReply))
2396 throw runtime_error("couldn't parse reply from server");
2397 const Object& reply = valReply.get_obj();
2399 throw runtime_error("expected reply to have result, error and id properties");
2407 template<typename T>
2408 void ConvertTo(Value& value)
2410 if (value.type() == str_type)
2412 // reinterpret string as unquoted json value
2414 if (!read_string(value.get_str(), value2))
2415 throw runtime_error("type mismatch");
2416 value = value2.get_value<T>();
2420 value = value.get_value<T>();
2424 int CommandLineRPC(int argc, char *argv[])
2431 while (argc > 1 && IsSwitchChar(argv[1][0]))
2439 throw runtime_error("too few parameters");
2440 string strMethod = argv[1];
2442 // Parameters default to strings
2444 for (int i = 2; i < argc; i++)
2445 params.push_back(argv[i]);
2446 int n = params.size();
2449 // Special case non-string parameter types
2451 if (strMethod == "setgenerate" && n > 0) ConvertTo<bool>(params[0]);
2452 if (strMethod == "setgenerate" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2453 if (strMethod == "sendtoaddress" && n > 1) ConvertTo<double>(params[1]);
2454 if (strMethod == "settxfee" && n > 0) ConvertTo<double>(params[0]);
2455 if (strMethod == "getreceivedbyaddress" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2456 if (strMethod == "getreceivedbyaccount" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2457 if (strMethod == "listreceivedbyaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2458 if (strMethod == "listreceivedbyaddress" && n > 1) ConvertTo<bool>(params[1]);
2459 if (strMethod == "listreceivedbyaccount" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2460 if (strMethod == "listreceivedbyaccount" && n > 1) ConvertTo<bool>(params[1]);
2461 if (strMethod == "getbalance" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2462 if (strMethod == "move" && n > 2) ConvertTo<double>(params[2]);
2463 if (strMethod == "move" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2464 if (strMethod == "sendfrom" && n > 2) ConvertTo<double>(params[2]);
2465 if (strMethod == "sendfrom" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2466 if (strMethod == "listtransactions" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2467 if (strMethod == "listtransactions" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2468 if (strMethod == "listaccounts" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2469 if (strMethod == "walletpassphrase" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2470 if (strMethod == "listsinceblock" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2471 if (strMethod == "sendmany" && n > 1)
2473 string s = params[1].get_str();
2475 if (!read_string(s, v) || v.type() != obj_type)
2476 throw runtime_error("type mismatch");
2477 params[1] = v.get_obj();
2479 if (strMethod == "sendmany" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2482 Object reply = CallRPC(strMethod, params);
2485 const Value& result = find_value(reply, "result");
2486 const Value& error = find_value(reply, "error");
2488 if (error.type() != null_type)
2491 strPrint = "error: " + write_string(error, false);
2492 int code = find_value(error.get_obj(), "code").get_int();
2498 if (result.type() == null_type)
2500 else if (result.type() == str_type)
2501 strPrint = result.get_str();
2503 strPrint = write_string(result, true);
2506 catch (std::exception& e)
2508 strPrint = string("error: ") + e.what();
2513 PrintException(NULL, "CommandLineRPC()");
2518 fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
2527 int main(int argc, char *argv[])
2530 // Turn off microsoft heap dump noise
2531 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
2532 _CrtSetReportFile(_CRT_WARN, CreateFile("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0));
2534 setbuf(stdin, NULL);
2535 setbuf(stdout, NULL);
2536 setbuf(stderr, NULL);
2540 if (argc >= 2 && string(argv[1]) == "-server")
2542 printf("server ready\n");
2543 ThreadRPCServer(NULL);
2547 return CommandLineRPC(argc, argv);
2550 catch (std::exception& e) {
2551 PrintException(&e, "main()");
2553 PrintException(NULL, "main()");