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 == "getblocknumber" || // deprecated
130 (strMethod.find("label") != string::npos))
132 if (strCommand != "" && strMethod != strCommand)
137 rpcfn_type pfn = (*mi).second;
138 if (setDone.insert(pfn).second)
139 (*pfn)(params, true);
141 catch (std::exception& e)
143 // Help text is returned in an exception
144 string strHelp = string(e.what());
145 if (strCommand == "")
146 if (strHelp.find('\n') != -1)
147 strHelp = strHelp.substr(0, strHelp.find('\n'));
148 strRet += strHelp + "\n";
152 strRet = strprintf("help: unknown command: %s\n", strCommand.c_str());
153 strRet = strRet.substr(0,strRet.size()-1);
158 Value stop(const Array& params, bool fHelp)
160 if (fHelp || params.size() != 0)
163 "Stop bitcoin server.");
165 // Shutdown will take long enough that the response should get back
166 CreateThread(Shutdown, NULL);
167 return "bitcoin server stopping";
171 Value getblockcount(const Array& params, bool fHelp)
173 if (fHelp || params.size() != 0)
176 "Returns the number of blocks in the longest block chain.");
183 Value getblocknumber(const Array& params, bool fHelp)
185 if (fHelp || params.size() != 0)
188 "Deprecated. Use getblockcount.");
194 Value getconnectioncount(const Array& params, bool fHelp)
196 if (fHelp || params.size() != 0)
198 "getconnectioncount\n"
199 "Returns the number of connections to other nodes.");
201 return (int)vNodes.size();
205 double GetDifficulty()
207 // Floating point number that is a multiple of the minimum difficulty,
208 // minimum difficulty = 1.0.
210 if (pindexBest == NULL)
212 int nShift = (pindexBest->nBits >> 24) & 0xff;
215 (double)0x0000ffff / (double)(pindexBest->nBits & 0x00ffffff);
231 Value getdifficulty(const Array& params, bool fHelp)
233 if (fHelp || params.size() != 0)
236 "Returns the proof-of-work difficulty as a multiple of the minimum difficulty.");
238 return GetDifficulty();
242 Value getgenerate(const Array& params, bool fHelp)
244 if (fHelp || params.size() != 0)
247 "Returns true or false.");
249 return (bool)fGenerateBitcoins;
253 Value setgenerate(const Array& params, bool fHelp)
255 if (fHelp || params.size() < 1 || params.size() > 2)
257 "setgenerate <generate> [genproclimit]\n"
258 "<generate> is true or false to turn generation on or off.\n"
259 "Generation is limited to [genproclimit] processors, -1 is unlimited.");
261 bool fGenerate = true;
262 if (params.size() > 0)
263 fGenerate = params[0].get_bool();
265 if (params.size() > 1)
267 int nGenProcLimit = params[1].get_int();
268 fLimitProcessors = (nGenProcLimit != -1);
269 WriteSetting("fLimitProcessors", fLimitProcessors);
270 if (nGenProcLimit != -1)
271 WriteSetting("nLimitProcessors", nLimitProcessors = nGenProcLimit);
272 if (nGenProcLimit == 0)
276 GenerateBitcoins(fGenerate, pwalletMain);
281 Value gethashespersec(const Array& params, bool fHelp)
283 if (fHelp || params.size() != 0)
286 "Returns a recent hashes per second performance measurement while generating.");
288 if (GetTimeMillis() - nHPSTimerStart > 8000)
289 return (boost::int64_t)0;
290 return (boost::int64_t)dHashesPerSec;
294 Value getinfo(const Array& params, bool fHelp)
296 if (fHelp || params.size() != 0)
299 "Returns an object containing various state info.");
302 obj.push_back(Pair("version", (int)VERSION));
303 obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance())));
304 obj.push_back(Pair("blocks", (int)nBestHeight));
305 obj.push_back(Pair("connections", (int)vNodes.size()));
306 obj.push_back(Pair("proxy", (fUseProxy ? addrProxy.ToStringIPPort() : string())));
307 obj.push_back(Pair("generate", (bool)fGenerateBitcoins));
308 obj.push_back(Pair("genproclimit", (int)(fLimitProcessors ? nLimitProcessors : -1)));
309 obj.push_back(Pair("difficulty", (double)GetDifficulty()));
310 obj.push_back(Pair("hashespersec", gethashespersec(params, false)));
311 obj.push_back(Pair("testnet", fTestNet));
312 obj.push_back(Pair("keypoololdest", (boost::int64_t)pwalletMain->GetOldestKeyPoolTime()));
313 obj.push_back(Pair("keypoolsize", pwalletMain->GetKeyPoolSize()));
314 obj.push_back(Pair("paytxfee", ValueFromAmount(nTransactionFee)));
315 if (pwalletMain->IsCrypted())
316 obj.push_back(Pair("unlocked_until", (boost::int64_t)nWalletUnlockTime));
317 obj.push_back(Pair("errors", GetWarnings("statusbar")));
322 Value getnewaddress(const Array& params, bool fHelp)
324 if (fHelp || params.size() > 1)
326 "getnewaddress [account]\n"
327 "Returns a new bitcoin address for receiving payments. "
328 "If [account] is specified (recommended), it is added to the address book "
329 "so payments received with the address will be credited to [account].");
331 // Parse the account first so we don't generate a key if there's an error
333 if (params.size() > 0)
334 strAccount = AccountFromValue(params[0]);
336 if (!pwalletMain->IsLocked())
337 pwalletMain->TopUpKeyPool();
339 // Generate a new key that is added to wallet
340 std::vector<unsigned char> newKey;
341 if (!pwalletMain->GetKeyFromPool(newKey, false))
342 throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
343 CBitcoinAddress address(newKey);
345 pwalletMain->SetAddressBookName(address, strAccount);
347 return address.ToString();
351 CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false)
353 CWalletDB walletdb(pwalletMain->strWalletFile);
356 walletdb.ReadAccount(strAccount, account);
358 bool bKeyUsed = false;
360 // Check if the current key has been used
361 if (!account.vchPubKey.empty())
363 CScript scriptPubKey;
364 scriptPubKey.SetBitcoinAddress(account.vchPubKey);
365 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
366 it != pwalletMain->mapWallet.end() && !account.vchPubKey.empty();
369 const CWalletTx& wtx = (*it).second;
370 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
371 if (txout.scriptPubKey == scriptPubKey)
376 // Generate a new key
377 if (account.vchPubKey.empty() || bForceNew || bKeyUsed)
379 if (!pwalletMain->GetKeyFromPool(account.vchPubKey, false))
380 throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
382 pwalletMain->SetAddressBookName(CBitcoinAddress(account.vchPubKey), strAccount);
383 walletdb.WriteAccount(strAccount, account);
386 return CBitcoinAddress(account.vchPubKey);
389 Value getaccountaddress(const Array& params, bool fHelp)
391 if (fHelp || params.size() != 1)
393 "getaccountaddress <account>\n"
394 "Returns the current bitcoin address for receiving payments to this account.");
396 // Parse the account first so we don't generate a key if there's an error
397 string strAccount = AccountFromValue(params[0]);
401 ret = GetAccountAddress(strAccount).ToString();
408 Value setaccount(const Array& params, bool fHelp)
410 if (fHelp || params.size() < 1 || params.size() > 2)
412 "setaccount <bitcoinaddress> <account>\n"
413 "Sets the account associated with the given address.");
415 CBitcoinAddress address(params[0].get_str());
416 if (!address.IsValid())
417 throw JSONRPCError(-5, "Invalid bitcoin address");
421 if (params.size() > 1)
422 strAccount = AccountFromValue(params[1]);
424 // Detect when changing the account of an address that is the 'unused current key' of another account:
425 if (pwalletMain->mapAddressBook.count(address))
427 string strOldAccount = pwalletMain->mapAddressBook[address];
428 if (address == GetAccountAddress(strOldAccount))
429 GetAccountAddress(strOldAccount, true);
432 pwalletMain->SetAddressBookName(address, strAccount);
438 Value getaccount(const Array& params, bool fHelp)
440 if (fHelp || params.size() != 1)
442 "getaccount <bitcoinaddress>\n"
443 "Returns the account associated with the given address.");
445 CBitcoinAddress address(params[0].get_str());
446 if (!address.IsValid())
447 throw JSONRPCError(-5, "Invalid bitcoin address");
450 map<CBitcoinAddress, string>::iterator mi = pwalletMain->mapAddressBook.find(address);
451 if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.empty())
452 strAccount = (*mi).second;
457 Value getaddressesbyaccount(const Array& params, bool fHelp)
459 if (fHelp || params.size() != 1)
461 "getaddressesbyaccount <account>\n"
462 "Returns the list of addresses for the given account.");
464 string strAccount = AccountFromValue(params[0]);
466 // Find all addresses that have the given account
468 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
470 const CBitcoinAddress& address = item.first;
471 const string& strName = item.second;
472 if (strName == strAccount)
473 ret.push_back(address.ToString());
478 Value settxfee(const Array& params, bool fHelp)
480 if (fHelp || params.size() < 1 || params.size() > 1)
482 "settxfee <amount>\n"
483 "<amount> is a real and is rounded to the nearest 0.00000001");
487 if (params[0].get_real() != 0.0)
488 nAmount = AmountFromValue(params[0]); // rejects 0.0 amounts
490 nTransactionFee = nAmount;
494 Value sendtoaddress(const Array& params, bool fHelp)
496 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
498 "sendtoaddress <bitcoinaddress> <amount> [comment] [comment-to]\n"
499 "<amount> is a real and is rounded to the nearest 0.00000001\n"
500 "requires wallet passphrase to be set with walletpassphrase first");
501 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
503 "sendtoaddress <bitcoinaddress> <amount> [comment] [comment-to]\n"
504 "<amount> is a real and is rounded to the nearest 0.00000001");
506 CBitcoinAddress address(params[0].get_str());
507 if (!address.IsValid())
508 throw JSONRPCError(-5, "Invalid bitcoin address");
511 int64 nAmount = AmountFromValue(params[1]);
515 if (params.size() > 2 && params[2].type() != null_type && !params[2].get_str().empty())
516 wtx.mapValue["comment"] = params[2].get_str();
517 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
518 wtx.mapValue["to"] = params[3].get_str();
520 if (pwalletMain->IsLocked())
521 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
523 string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
525 throw JSONRPCError(-4, strError);
527 return wtx.GetHash().GetHex();
530 static const string strMessageMagic = "Bitcoin Signed Message:\n";
532 Value signmessage(const Array& params, bool fHelp)
534 if (fHelp || params.size() != 2)
536 "signmessage <bitcoinaddress> <message>\n"
537 "Sign a message with the private key of an address");
539 if (pwalletMain->IsLocked())
540 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
542 string strAddress = params[0].get_str();
543 string strMessage = params[1].get_str();
545 CBitcoinAddress addr(strAddress);
547 throw JSONRPCError(-3, "Invalid address");
550 if (!pwalletMain->GetKey(addr, key))
551 throw JSONRPCError(-4, "Private key not available");
553 CDataStream ss(SER_GETHASH);
554 ss << strMessageMagic;
557 vector<unsigned char> vchSig;
558 if (!key.SignCompact(Hash(ss.begin(), ss.end()), vchSig))
559 throw JSONRPCError(-5, "Sign failed");
561 return EncodeBase64(&vchSig[0], vchSig.size());
564 Value verifymessage(const Array& params, bool fHelp)
566 if (fHelp || params.size() != 3)
568 "verifymessage <bitcoinaddress> <signature> <message>\n"
569 "Verify a signed message");
571 string strAddress = params[0].get_str();
572 string strSign = params[1].get_str();
573 string strMessage = params[2].get_str();
575 CBitcoinAddress addr(strAddress);
577 throw JSONRPCError(-3, "Invalid address");
579 bool fInvalid = false;
580 vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid);
583 throw JSONRPCError(-5, "Malformed base64 encoding");
585 CDataStream ss(SER_GETHASH);
586 ss << strMessageMagic;
590 if (!key.SetCompactSignature(Hash(ss.begin(), ss.end()), vchSig))
593 return (key.GetAddress() == addr);
597 Value getreceivedbyaddress(const Array& params, bool fHelp)
599 if (fHelp || params.size() < 1 || params.size() > 2)
601 "getreceivedbyaddress <bitcoinaddress> [minconf=1]\n"
602 "Returns the total amount received by <bitcoinaddress> in transactions with at least [minconf] confirmations.");
605 CBitcoinAddress address = CBitcoinAddress(params[0].get_str());
606 CScript scriptPubKey;
607 if (!address.IsValid())
608 throw JSONRPCError(-5, "Invalid bitcoin address");
609 scriptPubKey.SetBitcoinAddress(address);
610 if (!IsMine(*pwalletMain,scriptPubKey))
613 // Minimum confirmations
615 if (params.size() > 1)
616 nMinDepth = params[1].get_int();
620 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
622 const CWalletTx& wtx = (*it).second;
623 if (wtx.IsCoinBase() || !wtx.IsFinal())
626 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
627 if (txout.scriptPubKey == scriptPubKey)
628 if (wtx.GetDepthInMainChain() >= nMinDepth)
629 nAmount += txout.nValue;
632 return ValueFromAmount(nAmount);
636 void GetAccountAddresses(string strAccount, set<CBitcoinAddress>& setAddress)
638 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
640 const CBitcoinAddress& address = item.first;
641 const string& strName = item.second;
642 if (strName == strAccount)
643 setAddress.insert(address);
648 Value getreceivedbyaccount(const Array& params, bool fHelp)
650 if (fHelp || params.size() < 1 || params.size() > 2)
652 "getreceivedbyaccount <account> [minconf=1]\n"
653 "Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.");
655 // Minimum confirmations
657 if (params.size() > 1)
658 nMinDepth = params[1].get_int();
660 // Get the set of pub keys that have the label
661 string strAccount = AccountFromValue(params[0]);
662 set<CBitcoinAddress> setAddress;
663 GetAccountAddresses(strAccount, setAddress);
667 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
669 const CWalletTx& wtx = (*it).second;
670 if (wtx.IsCoinBase() || !wtx.IsFinal())
673 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
675 CBitcoinAddress address;
676 if (ExtractAddress(txout.scriptPubKey, pwalletMain, address) && setAddress.count(address))
677 if (wtx.GetDepthInMainChain() >= nMinDepth)
678 nAmount += txout.nValue;
682 return (double)nAmount / (double)COIN;
686 int64 GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth)
690 // Tally wallet transactions
691 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
693 const CWalletTx& wtx = (*it).second;
697 int64 nGenerated, nReceived, nSent, nFee;
698 wtx.GetAccountAmounts(strAccount, nGenerated, nReceived, nSent, nFee);
700 if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
701 nBalance += nReceived;
702 nBalance += nGenerated - nSent - nFee;
705 // Tally internal accounting entries
706 nBalance += walletdb.GetAccountCreditDebit(strAccount);
711 int64 GetAccountBalance(const string& strAccount, int nMinDepth)
713 CWalletDB walletdb(pwalletMain->strWalletFile);
714 return GetAccountBalance(walletdb, strAccount, nMinDepth);
718 Value getbalance(const Array& params, bool fHelp)
720 if (fHelp || params.size() > 2)
722 "getbalance [account] [minconf=1]\n"
723 "If [account] is not specified, returns the server's total available balance.\n"
724 "If [account] is specified, returns the balance in the account.");
726 if (params.size() == 0)
727 return ValueFromAmount(pwalletMain->GetBalance());
730 if (params.size() > 1)
731 nMinDepth = params[1].get_int();
733 if (params[0].get_str() == "*") {
734 // Calculate total balance a different way from GetBalance()
735 // (GetBalance() sums up all unspent TxOuts)
736 // getbalance and getbalance '*' should always return the same number.
738 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
740 const CWalletTx& wtx = (*it).second;
744 int64 allGeneratedImmature, allGeneratedMature, allFee;
745 allGeneratedImmature = allGeneratedMature = allFee = 0;
746 string strSentAccount;
747 list<pair<CBitcoinAddress, int64> > listReceived;
748 list<pair<CBitcoinAddress, int64> > listSent;
749 wtx.GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount);
750 if (wtx.GetDepthInMainChain() >= nMinDepth)
751 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listReceived)
752 nBalance += r.second;
753 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listSent)
754 nBalance -= r.second;
756 nBalance += allGeneratedMature;
758 return ValueFromAmount(nBalance);
761 string strAccount = AccountFromValue(params[0]);
763 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
765 return ValueFromAmount(nBalance);
769 Value movecmd(const Array& params, bool fHelp)
771 if (fHelp || params.size() < 3 || params.size() > 5)
773 "move <fromaccount> <toaccount> <amount> [minconf=1] [comment]\n"
774 "Move from one account in your wallet to another.");
776 string strFrom = AccountFromValue(params[0]);
777 string strTo = AccountFromValue(params[1]);
778 int64 nAmount = AmountFromValue(params[2]);
779 if (params.size() > 3)
780 // unused parameter, used to be nMinDepth, keep type-checking it though
781 (void)params[3].get_int();
783 if (params.size() > 4)
784 strComment = params[4].get_str();
786 CWalletDB walletdb(pwalletMain->strWalletFile);
789 int64 nNow = GetAdjustedTime();
792 CAccountingEntry debit;
793 debit.strAccount = strFrom;
794 debit.nCreditDebit = -nAmount;
796 debit.strOtherAccount = strTo;
797 debit.strComment = strComment;
798 walletdb.WriteAccountingEntry(debit);
801 CAccountingEntry credit;
802 credit.strAccount = strTo;
803 credit.nCreditDebit = nAmount;
805 credit.strOtherAccount = strFrom;
806 credit.strComment = strComment;
807 walletdb.WriteAccountingEntry(credit);
809 walletdb.TxnCommit();
815 Value sendfrom(const Array& params, bool fHelp)
817 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
819 "sendfrom <fromaccount> <tobitcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
820 "<amount> is a real and is rounded to the nearest 0.00000001\n"
821 "requires wallet passphrase to be set with walletpassphrase first");
822 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
824 "sendfrom <fromaccount> <tobitcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
825 "<amount> is a real and is rounded to the nearest 0.00000001");
827 string strAccount = AccountFromValue(params[0]);
828 CBitcoinAddress address(params[1].get_str());
829 if (!address.IsValid())
830 throw JSONRPCError(-5, "Invalid bitcoin address");
831 int64 nAmount = AmountFromValue(params[2]);
833 if (params.size() > 3)
834 nMinDepth = params[3].get_int();
837 wtx.strFromAccount = strAccount;
838 if (params.size() > 4 && params[4].type() != null_type && !params[4].get_str().empty())
839 wtx.mapValue["comment"] = params[4].get_str();
840 if (params.size() > 5 && params[5].type() != null_type && !params[5].get_str().empty())
841 wtx.mapValue["to"] = params[5].get_str();
843 if (pwalletMain->IsLocked())
844 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
847 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
848 if (nAmount > nBalance)
849 throw JSONRPCError(-6, "Account has insufficient funds");
852 string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
854 throw JSONRPCError(-4, strError);
856 return wtx.GetHash().GetHex();
860 Value sendmany(const Array& params, bool fHelp)
862 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
864 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
865 "amounts are double-precision floating point numbers\n"
866 "requires wallet passphrase to be set with walletpassphrase first");
867 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
869 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
870 "amounts are double-precision floating point numbers");
872 string strAccount = AccountFromValue(params[0]);
873 Object sendTo = params[1].get_obj();
875 if (params.size() > 2)
876 nMinDepth = params[2].get_int();
879 wtx.strFromAccount = strAccount;
880 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
881 wtx.mapValue["comment"] = params[3].get_str();
883 set<CBitcoinAddress> setAddress;
884 vector<pair<CScript, int64> > vecSend;
886 int64 totalAmount = 0;
887 BOOST_FOREACH(const Pair& s, sendTo)
889 CBitcoinAddress address(s.name_);
890 if (!address.IsValid())
891 throw JSONRPCError(-5, string("Invalid bitcoin address:")+s.name_);
893 if (setAddress.count(address))
894 throw JSONRPCError(-8, string("Invalid parameter, duplicated address: ")+s.name_);
895 setAddress.insert(address);
897 CScript scriptPubKey;
898 scriptPubKey.SetBitcoinAddress(address);
899 int64 nAmount = AmountFromValue(s.value_);
900 totalAmount += nAmount;
902 vecSend.push_back(make_pair(scriptPubKey, nAmount));
905 if (pwalletMain->IsLocked())
906 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
909 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
910 if (totalAmount > nBalance)
911 throw JSONRPCError(-6, "Account has insufficient funds");
914 CReserveKey keyChange(pwalletMain);
915 int64 nFeeRequired = 0;
916 bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired);
919 if (totalAmount + nFeeRequired > pwalletMain->GetBalance())
920 throw JSONRPCError(-6, "Insufficient funds");
921 throw JSONRPCError(-4, "Transaction creation failed");
923 if (!pwalletMain->CommitTransaction(wtx, keyChange))
924 throw JSONRPCError(-4, "Transaction commit failed");
926 return wtx.GetHash().GetHex();
941 Value ListReceived(const Array& params, bool fByAccounts)
943 // Minimum confirmations
945 if (params.size() > 0)
946 nMinDepth = params[0].get_int();
948 // Whether to include empty accounts
949 bool fIncludeEmpty = false;
950 if (params.size() > 1)
951 fIncludeEmpty = params[1].get_bool();
954 map<CBitcoinAddress, tallyitem> mapTally;
955 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
957 const CWalletTx& wtx = (*it).second;
958 if (wtx.IsCoinBase() || !wtx.IsFinal())
961 int nDepth = wtx.GetDepthInMainChain();
962 if (nDepth < nMinDepth)
965 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
967 CBitcoinAddress address;
968 if (!ExtractAddress(txout.scriptPubKey, pwalletMain, address) || !address.IsValid())
971 tallyitem& item = mapTally[address];
972 item.nAmount += txout.nValue;
973 item.nConf = min(item.nConf, nDepth);
979 map<string, tallyitem> mapAccountTally;
980 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
982 const CBitcoinAddress& address = item.first;
983 const string& strAccount = item.second;
984 map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
985 if (it == mapTally.end() && !fIncludeEmpty)
990 if (it != mapTally.end())
992 nAmount = (*it).second.nAmount;
993 nConf = (*it).second.nConf;
998 tallyitem& item = mapAccountTally[strAccount];
999 item.nAmount += nAmount;
1000 item.nConf = min(item.nConf, nConf);
1005 obj.push_back(Pair("address", address.ToString()));
1006 obj.push_back(Pair("account", strAccount));
1007 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1008 obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf)));
1015 for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
1017 int64 nAmount = (*it).second.nAmount;
1018 int nConf = (*it).second.nConf;
1020 obj.push_back(Pair("account", (*it).first));
1021 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1022 obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf)));
1030 Value listreceivedbyaddress(const Array& params, bool fHelp)
1032 if (fHelp || params.size() > 2)
1033 throw runtime_error(
1034 "listreceivedbyaddress [minconf=1] [includeempty=false]\n"
1035 "[minconf] is the minimum number of confirmations before payments are included.\n"
1036 "[includeempty] whether to include addresses that haven't received any payments.\n"
1037 "Returns an array of objects containing:\n"
1038 " \"address\" : receiving address\n"
1039 " \"account\" : the account of the receiving address\n"
1040 " \"amount\" : total amount received by the address\n"
1041 " \"confirmations\" : number of confirmations of the most recent transaction included");
1043 return ListReceived(params, false);
1046 Value listreceivedbyaccount(const Array& params, bool fHelp)
1048 if (fHelp || params.size() > 2)
1049 throw runtime_error(
1050 "listreceivedbyaccount [minconf=1] [includeempty=false]\n"
1051 "[minconf] is the minimum number of confirmations before payments are included.\n"
1052 "[includeempty] whether to include accounts that haven't received any payments.\n"
1053 "Returns an array of objects containing:\n"
1054 " \"account\" : the account of the receiving addresses\n"
1055 " \"amount\" : total amount received by addresses with this account\n"
1056 " \"confirmations\" : number of confirmations of the most recent transaction included");
1058 return ListReceived(params, true);
1061 void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret)
1063 int64 nGeneratedImmature, nGeneratedMature, nFee;
1064 string strSentAccount;
1065 list<pair<CBitcoinAddress, int64> > listReceived;
1066 list<pair<CBitcoinAddress, int64> > listSent;
1067 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1069 bool fAllAccounts = (strAccount == string("*"));
1071 // Generated blocks assigned to account ""
1072 if ((nGeneratedMature+nGeneratedImmature) != 0 && (fAllAccounts || strAccount == ""))
1075 entry.push_back(Pair("account", string("")));
1076 if (nGeneratedImmature)
1078 entry.push_back(Pair("category", wtx.GetDepthInMainChain() ? "immature" : "orphan"));
1079 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedImmature)));
1083 entry.push_back(Pair("category", "generate"));
1084 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedMature)));
1087 WalletTxToJSON(wtx, entry);
1088 ret.push_back(entry);
1092 if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
1094 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1097 entry.push_back(Pair("account", strSentAccount));
1098 entry.push_back(Pair("address", s.first.ToString()));
1099 entry.push_back(Pair("category", "send"));
1100 entry.push_back(Pair("amount", ValueFromAmount(-s.second)));
1101 entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
1103 WalletTxToJSON(wtx, entry);
1104 ret.push_back(entry);
1109 if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
1110 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1113 if (pwalletMain->mapAddressBook.count(r.first))
1114 account = pwalletMain->mapAddressBook[r.first];
1115 if (fAllAccounts || (account == strAccount))
1118 entry.push_back(Pair("account", account));
1119 entry.push_back(Pair("address", r.first.ToString()));
1120 entry.push_back(Pair("category", "receive"));
1121 entry.push_back(Pair("amount", ValueFromAmount(r.second)));
1123 WalletTxToJSON(wtx, entry);
1124 ret.push_back(entry);
1129 void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret)
1131 bool fAllAccounts = (strAccount == string("*"));
1133 if (fAllAccounts || acentry.strAccount == strAccount)
1136 entry.push_back(Pair("account", acentry.strAccount));
1137 entry.push_back(Pair("category", "move"));
1138 entry.push_back(Pair("time", (boost::int64_t)acentry.nTime));
1139 entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
1140 entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
1141 entry.push_back(Pair("comment", acentry.strComment));
1142 ret.push_back(entry);
1146 Value listtransactions(const Array& params, bool fHelp)
1148 if (fHelp || params.size() > 3)
1149 throw runtime_error(
1150 "listtransactions [account] [count=10] [from=0]\n"
1151 "Returns up to [count] most recent transactions skipping the first [from] transactions for account [account].");
1153 string strAccount = "*";
1154 if (params.size() > 0)
1155 strAccount = params[0].get_str();
1157 if (params.size() > 1)
1158 nCount = params[1].get_int();
1160 if (params.size() > 2)
1161 nFrom = params[2].get_int();
1164 CWalletDB walletdb(pwalletMain->strWalletFile);
1166 // Firs: get all CWalletTx and CAccountingEntry into a sorted-by-time multimap:
1167 typedef pair<CWalletTx*, CAccountingEntry*> TxPair;
1168 typedef multimap<int64, TxPair > TxItems;
1171 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1173 CWalletTx* wtx = &((*it).second);
1174 txByTime.insert(make_pair(wtx->GetTxTime(), TxPair(wtx, (CAccountingEntry*)0)));
1176 list<CAccountingEntry> acentries;
1177 walletdb.ListAccountCreditDebit(strAccount, acentries);
1178 BOOST_FOREACH(CAccountingEntry& entry, acentries)
1180 txByTime.insert(make_pair(entry.nTime, TxPair((CWalletTx*)0, &entry)));
1183 // Now: iterate backwards until we have nCount items to return:
1184 TxItems::reverse_iterator it = txByTime.rbegin();
1185 if (txByTime.size() > nFrom) std::advance(it, nFrom);
1186 for (; it != txByTime.rend(); ++it)
1188 CWalletTx *const pwtx = (*it).second.first;
1190 ListTransactions(*pwtx, strAccount, 0, true, ret);
1191 CAccountingEntry *const pacentry = (*it).second.second;
1193 AcentryToJSON(*pacentry, strAccount, ret);
1195 if (ret.size() >= nCount) break;
1197 // ret is now newest to oldest
1199 // Make sure we return only last nCount items (sends-to-self might give us an extra):
1200 if (ret.size() > nCount)
1202 Array::iterator last = ret.begin();
1203 std::advance(last, nCount);
1204 ret.erase(last, ret.end());
1206 std::reverse(ret.begin(), ret.end()); // oldest to newest
1211 Value listaccounts(const Array& params, bool fHelp)
1213 if (fHelp || params.size() > 1)
1214 throw runtime_error(
1215 "listaccounts [minconf=1]\n"
1216 "Returns Object that has account names as keys, account balances as values.");
1219 if (params.size() > 0)
1220 nMinDepth = params[0].get_int();
1222 map<string, int64> mapAccountBalances;
1223 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& entry, pwalletMain->mapAddressBook) {
1224 if (pwalletMain->HaveKey(entry.first)) // This address belongs to me
1225 mapAccountBalances[entry.second] = 0;
1228 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1230 const CWalletTx& wtx = (*it).second;
1231 int64 nGeneratedImmature, nGeneratedMature, nFee;
1232 string strSentAccount;
1233 list<pair<CBitcoinAddress, int64> > listReceived;
1234 list<pair<CBitcoinAddress, int64> > listSent;
1235 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1236 mapAccountBalances[strSentAccount] -= nFee;
1237 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1238 mapAccountBalances[strSentAccount] -= s.second;
1239 if (wtx.GetDepthInMainChain() >= nMinDepth)
1241 mapAccountBalances[""] += nGeneratedMature;
1242 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1243 if (pwalletMain->mapAddressBook.count(r.first))
1244 mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second;
1246 mapAccountBalances[""] += r.second;
1250 list<CAccountingEntry> acentries;
1251 CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
1252 BOOST_FOREACH(const CAccountingEntry& entry, acentries)
1253 mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
1256 BOOST_FOREACH(const PAIRTYPE(string, int64)& accountBalance, mapAccountBalances) {
1257 ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
1262 Value listsinceblock(const Array& params, bool fHelp)
1265 throw runtime_error(
1266 "listsinceblock [blockid] [target-confirmations]\n"
1267 "Get all transactions in blocks since block [blockid], or all transactions if omitted");
1269 CBlockIndex *pindex = NULL;
1270 int target_confirms = 1;
1272 if (params.size() > 0)
1274 uint256 blockId = 0;
1276 blockId.SetHex(params[0].get_str());
1277 pindex = CBlockLocator(blockId).GetBlockIndex();
1280 if (params.size() > 1)
1282 target_confirms = params[1].get_int();
1284 if (target_confirms < 1)
1285 throw JSONRPCError(-8, "Invalid parameter");
1288 int depth = pindex ? (1 + nBestHeight - pindex->nHeight) : -1;
1292 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++)
1294 CWalletTx tx = (*it).second;
1296 if (depth == -1 || tx.GetDepthInMainChain() < depth)
1297 ListTransactions(tx, "*", 0, true, transactions);
1302 if (target_confirms == 1)
1305 lastblock = hashBestChain;
1309 int target_height = pindexBest->nHeight + 1 - target_confirms;
1312 for (block = pindexBest;
1313 block && block->nHeight > target_height;
1314 block = block->pprev);
1316 lastblock = block ? block->GetBlockHash() : 0;
1320 ret.push_back(Pair("transactions", transactions));
1321 ret.push_back(Pair("lastblock", lastblock.GetHex()));
1326 Value gettransaction(const Array& params, bool fHelp)
1328 if (fHelp || params.size() != 1)
1329 throw runtime_error(
1330 "gettransaction <txid>\n"
1331 "Get detailed information about <txid>");
1334 hash.SetHex(params[0].get_str());
1338 if (!pwalletMain->mapWallet.count(hash))
1339 throw JSONRPCError(-5, "Invalid or non-wallet transaction id");
1340 const CWalletTx& wtx = pwalletMain->mapWallet[hash];
1342 int64 nCredit = wtx.GetCredit();
1343 int64 nDebit = wtx.GetDebit();
1344 int64 nNet = nCredit - nDebit;
1345 int64 nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0);
1347 entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
1349 entry.push_back(Pair("fee", ValueFromAmount(nFee)));
1351 WalletTxToJSON(pwalletMain->mapWallet[hash], entry);
1354 ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details);
1355 entry.push_back(Pair("details", details));
1361 Value backupwallet(const Array& params, bool fHelp)
1363 if (fHelp || params.size() != 1)
1364 throw runtime_error(
1365 "backupwallet <destination>\n"
1366 "Safely copies wallet.dat to destination, which can be a directory or a path with filename.");
1368 string strDest = params[0].get_str();
1369 BackupWallet(*pwalletMain, strDest);
1375 Value keypoolrefill(const Array& params, bool fHelp)
1377 if (pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1378 throw runtime_error(
1380 "Fills the keypool, requires wallet passphrase to be set.");
1381 if (!pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1382 throw runtime_error(
1384 "Fills the keypool.");
1386 if (pwalletMain->IsLocked())
1387 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
1389 pwalletMain->TopUpKeyPool();
1391 if (pwalletMain->GetKeyPoolSize() < GetArg("-keypool", 100))
1392 throw JSONRPCError(-4, "Error refreshing keypool.");
1398 void ThreadTopUpKeyPool(void* parg)
1400 pwalletMain->TopUpKeyPool();
1403 void ThreadCleanWalletPassphrase(void* parg)
1405 int64 nMyWakeTime = GetTime() + *((int*)parg);
1407 if (nWalletUnlockTime == 0)
1409 CRITICAL_BLOCK(cs_nWalletUnlockTime)
1411 nWalletUnlockTime = nMyWakeTime;
1414 while (GetTime() < nWalletUnlockTime)
1415 Sleep(GetTime() - nWalletUnlockTime);
1417 CRITICAL_BLOCK(cs_nWalletUnlockTime)
1419 nWalletUnlockTime = 0;
1424 CRITICAL_BLOCK(cs_nWalletUnlockTime)
1426 if (nWalletUnlockTime < nMyWakeTime)
1427 nWalletUnlockTime = nMyWakeTime;
1433 pwalletMain->Lock();
1438 Value walletpassphrase(const Array& params, bool fHelp)
1440 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1441 throw runtime_error(
1442 "walletpassphrase <passphrase> <timeout>\n"
1443 "Stores the wallet decryption key in memory for <timeout> seconds.");
1446 if (!pwalletMain->IsCrypted())
1447 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
1449 if (!pwalletMain->IsLocked())
1450 throw JSONRPCError(-17, "Error: Wallet is already unlocked.");
1452 // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
1453 string strWalletPass;
1454 strWalletPass.reserve(100);
1455 mlock(&strWalletPass[0], strWalletPass.capacity());
1456 strWalletPass = params[0].get_str();
1458 if (strWalletPass.length() > 0)
1460 if (!pwalletMain->Unlock(strWalletPass))
1462 fill(strWalletPass.begin(), strWalletPass.end(), '\0');
1463 munlock(&strWalletPass[0], strWalletPass.capacity());
1464 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1466 fill(strWalletPass.begin(), strWalletPass.end(), '\0');
1467 munlock(&strWalletPass[0], strWalletPass.capacity());
1470 throw runtime_error(
1471 "walletpassphrase <passphrase> <timeout>\n"
1472 "Stores the wallet decryption key in memory for <timeout> seconds.");
1474 CreateThread(ThreadTopUpKeyPool, NULL);
1475 int* pnSleepTime = new int(params[1].get_int());
1476 CreateThread(ThreadCleanWalletPassphrase, pnSleepTime);
1482 Value walletpassphrasechange(const Array& params, bool fHelp)
1484 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1485 throw runtime_error(
1486 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1487 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1490 if (!pwalletMain->IsCrypted())
1491 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
1493 string strOldWalletPass;
1494 strOldWalletPass.reserve(100);
1495 mlock(&strOldWalletPass[0], strOldWalletPass.capacity());
1496 strOldWalletPass = params[0].get_str();
1498 string strNewWalletPass;
1499 strNewWalletPass.reserve(100);
1500 mlock(&strNewWalletPass[0], strNewWalletPass.capacity());
1501 strNewWalletPass = params[1].get_str();
1503 if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
1504 throw runtime_error(
1505 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1506 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1508 if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
1510 fill(strOldWalletPass.begin(), strOldWalletPass.end(), '\0');
1511 fill(strNewWalletPass.begin(), strNewWalletPass.end(), '\0');
1512 munlock(&strOldWalletPass[0], strOldWalletPass.capacity());
1513 munlock(&strNewWalletPass[0], strNewWalletPass.capacity());
1514 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1516 fill(strNewWalletPass.begin(), strNewWalletPass.end(), '\0');
1517 fill(strOldWalletPass.begin(), strOldWalletPass.end(), '\0');
1518 munlock(&strOldWalletPass[0], strOldWalletPass.capacity());
1519 munlock(&strNewWalletPass[0], strNewWalletPass.capacity());
1525 Value walletlock(const Array& params, bool fHelp)
1527 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
1528 throw runtime_error(
1530 "Removes the wallet encryption key from memory, locking the wallet.\n"
1531 "After calling this method, you will need to call walletpassphrase again\n"
1532 "before being able to call any methods which require the wallet to be unlocked.");
1535 if (!pwalletMain->IsCrypted())
1536 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletlock was called.");
1538 pwalletMain->Lock();
1539 CRITICAL_BLOCK(cs_nWalletUnlockTime)
1541 nWalletUnlockTime = 0;
1548 Value encryptwallet(const Array& params, bool fHelp)
1550 if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
1551 throw runtime_error(
1552 "encryptwallet <passphrase>\n"
1553 "Encrypts the wallet with <passphrase>.");
1556 if (pwalletMain->IsCrypted())
1557 throw JSONRPCError(-15, "Error: running with an encrypted wallet, but encryptwallet was called.");
1559 string strWalletPass;
1560 strWalletPass.reserve(100);
1561 mlock(&strWalletPass[0], strWalletPass.capacity());
1562 strWalletPass = params[0].get_str();
1564 if (strWalletPass.length() < 1)
1565 throw runtime_error(
1566 "encryptwallet <passphrase>\n"
1567 "Encrypts the wallet with <passphrase>.");
1569 if (!pwalletMain->EncryptWallet(strWalletPass))
1571 fill(strWalletPass.begin(), strWalletPass.end(), '\0');
1572 munlock(&strWalletPass[0], strWalletPass.capacity());
1573 throw JSONRPCError(-16, "Error: Failed to encrypt the wallet.");
1575 fill(strWalletPass.begin(), strWalletPass.end(), '\0');
1576 munlock(&strWalletPass[0], strWalletPass.capacity());
1582 Value validateaddress(const Array& params, bool fHelp)
1584 if (fHelp || params.size() != 1)
1585 throw runtime_error(
1586 "validateaddress <bitcoinaddress>\n"
1587 "Return information about <bitcoinaddress>.");
1589 CBitcoinAddress address(params[0].get_str());
1590 bool isValid = address.IsValid();
1593 ret.push_back(Pair("isvalid", isValid));
1596 // Call Hash160ToAddress() so we always return current ADDRESSVERSION
1597 // version of the address:
1598 string currentAddress = address.ToString();
1599 ret.push_back(Pair("address", currentAddress));
1600 ret.push_back(Pair("ismine", (pwalletMain->HaveKey(address) > 0)));
1601 if (pwalletMain->mapAddressBook.count(address))
1602 ret.push_back(Pair("account", pwalletMain->mapAddressBook[address]));
1608 Value getwork(const Array& params, bool fHelp)
1610 if (fHelp || params.size() > 1)
1611 throw runtime_error(
1613 "If [data] is not specified, returns formatted hash data to work on:\n"
1614 " \"midstate\" : precomputed hash state after hashing the first half of the data (DEPRECATED)\n" // deprecated
1615 " \"data\" : block data\n"
1616 " \"hash1\" : formatted hash buffer for second hash (DEPRECATED)\n" // deprecated
1617 " \"target\" : little endian hash target\n"
1618 "If [data] is specified, tries to solve the block and returns true if it was successful.");
1621 throw JSONRPCError(-9, "Bitcoin is not connected!");
1623 if (IsInitialBlockDownload())
1624 throw JSONRPCError(-10, "Bitcoin is downloading blocks...");
1626 typedef map<uint256, pair<CBlock*, CScript> > mapNewBlock_t;
1627 static mapNewBlock_t mapNewBlock;
1628 static vector<CBlock*> vNewBlock;
1629 static CReserveKey reservekey(pwalletMain);
1631 if (params.size() == 0)
1634 static unsigned int nTransactionsUpdatedLast;
1635 static CBlockIndex* pindexPrev;
1636 static int64 nStart;
1637 static CBlock* pblock;
1638 if (pindexPrev != pindexBest ||
1639 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60))
1641 if (pindexPrev != pindexBest)
1643 // Deallocate old blocks since they're obsolete now
1644 mapNewBlock.clear();
1645 BOOST_FOREACH(CBlock* pblock, vNewBlock)
1649 nTransactionsUpdatedLast = nTransactionsUpdated;
1650 pindexPrev = pindexBest;
1654 pblock = CreateNewBlock(reservekey);
1656 throw JSONRPCError(-7, "Out of memory");
1657 vNewBlock.push_back(pblock);
1661 pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
1664 // Update nExtraNonce
1665 static unsigned int nExtraNonce = 0;
1666 IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
1669 mapNewBlock[pblock->hashMerkleRoot] = make_pair(pblock, pblock->vtx[0].vin[0].scriptSig);
1671 // Prebuild hash buffers
1675 FormatHashBuffers(pblock, pmidstate, pdata, phash1);
1677 uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
1680 result.push_back(Pair("midstate", HexStr(BEGIN(pmidstate), END(pmidstate)))); // deprecated
1681 result.push_back(Pair("data", HexStr(BEGIN(pdata), END(pdata))));
1682 result.push_back(Pair("hash1", HexStr(BEGIN(phash1), END(phash1)))); // deprecated
1683 result.push_back(Pair("target", HexStr(BEGIN(hashTarget), END(hashTarget))));
1689 vector<unsigned char> vchData = ParseHex(params[0].get_str());
1690 if (vchData.size() != 128)
1691 throw JSONRPCError(-8, "Invalid parameter");
1692 CBlock* pdata = (CBlock*)&vchData[0];
1695 for (int i = 0; i < 128/4; i++)
1696 ((unsigned int*)pdata)[i] = ByteReverse(((unsigned int*)pdata)[i]);
1699 if (!mapNewBlock.count(pdata->hashMerkleRoot))
1701 CBlock* pblock = mapNewBlock[pdata->hashMerkleRoot].first;
1703 pblock->nTime = pdata->nTime;
1704 pblock->nNonce = pdata->nNonce;
1705 pblock->vtx[0].vin[0].scriptSig = mapNewBlock[pdata->hashMerkleRoot].second;
1706 pblock->hashMerkleRoot = pblock->BuildMerkleTree();
1708 return CheckWork(pblock, *pwalletMain, reservekey);
1713 Value getmemorypool(const Array& params, bool fHelp)
1715 if (fHelp || params.size() > 1)
1716 throw runtime_error(
1717 "getmemorypool [data]\n"
1718 "If [data] is not specified, returns data needed to construct a block to work on:\n"
1719 " \"version\" : block version\n"
1720 " \"previousblockhash\" : hash of current highest block\n"
1721 " \"transactions\" : contents of non-coinbase transactions that should be included in the next block\n"
1722 " \"coinbasevalue\" : maximum allowable input to coinbase transaction, including the generation award and transaction fees\n"
1723 " \"time\" : timestamp appropriate for next block\n"
1724 " \"bits\" : compressed target of next block\n"
1725 "If [data] is specified, tries to solve the block and returns true if it was successful.");
1727 if (params.size() == 0)
1730 throw JSONRPCError(-9, "Bitcoin is not connected!");
1732 if (IsInitialBlockDownload())
1733 throw JSONRPCError(-10, "Bitcoin is downloading blocks...");
1735 static CReserveKey reservekey(pwalletMain);
1738 static unsigned int nTransactionsUpdatedLast;
1739 static CBlockIndex* pindexPrev;
1740 static int64 nStart;
1741 static CBlock* pblock;
1742 if (pindexPrev != pindexBest ||
1743 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 5))
1745 nTransactionsUpdatedLast = nTransactionsUpdated;
1746 pindexPrev = pindexBest;
1752 pblock = CreateNewBlock(reservekey);
1754 throw JSONRPCError(-7, "Out of memory");
1758 pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
1762 BOOST_FOREACH(CTransaction tx, pblock->vtx) {
1769 transactions.push_back(HexStr(ssTx.begin(), ssTx.end()));
1773 result.push_back(Pair("version", pblock->nVersion));
1774 result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex()));
1775 result.push_back(Pair("transactions", transactions));
1776 result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue));
1777 result.push_back(Pair("time", (int64_t)pblock->nTime));
1783 uBits.nBits = htonl((int32_t)pblock->nBits);
1784 result.push_back(Pair("bits", HexStr(BEGIN(uBits.cBits), END(uBits.cBits))));
1791 CDataStream ssBlock(ParseHex(params[0].get_str()));
1795 return ProcessBlock(NULL, &pblock);
1813 pair<string, rpcfn_type> pCallTable[] =
1815 make_pair("help", &help),
1816 make_pair("stop", &stop),
1817 make_pair("getblockcount", &getblockcount),
1818 make_pair("getblocknumber", &getblocknumber),
1819 make_pair("getconnectioncount", &getconnectioncount),
1820 make_pair("getdifficulty", &getdifficulty),
1821 make_pair("getgenerate", &getgenerate),
1822 make_pair("setgenerate", &setgenerate),
1823 make_pair("gethashespersec", &gethashespersec),
1824 make_pair("getinfo", &getinfo),
1825 make_pair("getnewaddress", &getnewaddress),
1826 make_pair("getaccountaddress", &getaccountaddress),
1827 make_pair("setaccount", &setaccount),
1828 make_pair("getaccount", &getaccount),
1829 make_pair("getaddressesbyaccount", &getaddressesbyaccount),
1830 make_pair("sendtoaddress", &sendtoaddress),
1831 make_pair("getreceivedbyaddress", &getreceivedbyaddress),
1832 make_pair("getreceivedbyaccount", &getreceivedbyaccount),
1833 make_pair("listreceivedbyaddress", &listreceivedbyaddress),
1834 make_pair("listreceivedbyaccount", &listreceivedbyaccount),
1835 make_pair("backupwallet", &backupwallet),
1836 make_pair("keypoolrefill", &keypoolrefill),
1837 make_pair("walletpassphrase", &walletpassphrase),
1838 make_pair("walletpassphrasechange", &walletpassphrasechange),
1839 make_pair("walletlock", &walletlock),
1840 make_pair("encryptwallet", &encryptwallet),
1841 make_pair("validateaddress", &validateaddress),
1842 make_pair("getbalance", &getbalance),
1843 make_pair("move", &movecmd),
1844 make_pair("sendfrom", &sendfrom),
1845 make_pair("sendmany", &sendmany),
1846 make_pair("gettransaction", &gettransaction),
1847 make_pair("listtransactions", &listtransactions),
1848 make_pair("signmessage", &signmessage),
1849 make_pair("verifymessage", &verifymessage),
1850 make_pair("getwork", &getwork),
1851 make_pair("listaccounts", &listaccounts),
1852 make_pair("settxfee", &settxfee),
1853 make_pair("getmemorypool", &getmemorypool),
1854 make_pair("listsinceblock", &listsinceblock),
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 string::size_type nColon = strUserPass.find(":");
2035 if (nColon == string::npos)
2037 string strUser = strUserPass.substr(0, nColon);
2038 string strPassword = strUserPass.substr(nColon+1);
2039 return (strUser == mapArgs["-rpcuser"] && strPassword == mapArgs["-rpcpassword"]);
2043 // JSON-RPC protocol. Bitcoin speaks version 1.0 for maximum compatibility,
2044 // but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
2045 // unspecified (HTTP errors and contents of 'error').
2047 // 1.0 spec: http://json-rpc.org/wiki/specification
2048 // 1.2 spec: http://groups.google.com/group/json-rpc/web/json-rpc-over-http
2049 // http://www.codeproject.com/KB/recipes/JSON_Spirit.aspx
2052 string JSONRPCRequest(const string& strMethod, const Array& params, const Value& id)
2055 request.push_back(Pair("method", strMethod));
2056 request.push_back(Pair("params", params));
2057 request.push_back(Pair("id", id));
2058 return write_string(Value(request), false) + "\n";
2061 string JSONRPCReply(const Value& result, const Value& error, const Value& id)
2064 if (error.type() != null_type)
2065 reply.push_back(Pair("result", Value::null));
2067 reply.push_back(Pair("result", result));
2068 reply.push_back(Pair("error", error));
2069 reply.push_back(Pair("id", id));
2070 return write_string(Value(reply), false) + "\n";
2073 void ErrorReply(std::ostream& stream, const Object& objError, const Value& id)
2075 // Send error reply from json-rpc error object
2077 int code = find_value(objError, "code").get_int();
2078 if (code == -32600) nStatus = 400;
2079 else if (code == -32601) nStatus = 404;
2080 string strReply = JSONRPCReply(Value::null, objError, id);
2081 stream << HTTPReply(nStatus, strReply) << std::flush;
2084 bool ClientAllowed(const string& strAddress)
2086 if (strAddress == asio::ip::address_v4::loopback().to_string())
2088 const vector<string>& vAllow = mapMultiArgs["-rpcallowip"];
2089 BOOST_FOREACH(string strAllow, vAllow)
2090 if (WildcardMatch(strAddress, strAllow))
2097 // IOStream device that speaks SSL but can also speak non-SSL
2099 class SSLIOStreamDevice : public iostreams::device<iostreams::bidirectional> {
2101 SSLIOStreamDevice(SSLStream &streamIn, bool fUseSSLIn) : stream(streamIn)
2103 fUseSSL = fUseSSLIn;
2104 fNeedHandshake = fUseSSLIn;
2107 void handshake(ssl::stream_base::handshake_type role)
2109 if (!fNeedHandshake) return;
2110 fNeedHandshake = false;
2111 stream.handshake(role);
2113 std::streamsize read(char* s, std::streamsize n)
2115 handshake(ssl::stream_base::server); // HTTPS servers read first
2116 if (fUseSSL) return stream.read_some(asio::buffer(s, n));
2117 return stream.next_layer().read_some(asio::buffer(s, n));
2119 std::streamsize write(const char* s, std::streamsize n)
2121 handshake(ssl::stream_base::client); // HTTPS clients write first
2122 if (fUseSSL) return asio::write(stream, asio::buffer(s, n));
2123 return asio::write(stream.next_layer(), asio::buffer(s, n));
2125 bool connect(const std::string& server, const std::string& port)
2127 ip::tcp::resolver resolver(stream.get_io_service());
2128 ip::tcp::resolver::query query(server.c_str(), port.c_str());
2129 ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
2130 ip::tcp::resolver::iterator end;
2131 boost::system::error_code error = asio::error::host_not_found;
2132 while (error && endpoint_iterator != end)
2134 stream.lowest_layer().close();
2135 stream.lowest_layer().connect(*endpoint_iterator++, error);
2143 bool fNeedHandshake;
2149 void ThreadRPCServer(void* parg)
2151 IMPLEMENT_RANDOMIZE_STACK(ThreadRPCServer(parg));
2154 vnThreadsRunning[4]++;
2155 ThreadRPCServer2(parg);
2156 vnThreadsRunning[4]--;
2158 catch (std::exception& e) {
2159 vnThreadsRunning[4]--;
2160 PrintException(&e, "ThreadRPCServer()");
2162 vnThreadsRunning[4]--;
2163 PrintException(NULL, "ThreadRPCServer()");
2165 printf("ThreadRPCServer exiting\n");
2168 void ThreadRPCServer2(void* parg)
2170 printf("ThreadRPCServer started\n");
2172 if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
2174 string strWhatAmI = "To use bitcoind";
2175 if (mapArgs.count("-server"))
2176 strWhatAmI = strprintf(_("To use the %s option"), "\"-server\"");
2177 else if (mapArgs.count("-daemon"))
2178 strWhatAmI = strprintf(_("To use the %s option"), "\"-daemon\"");
2180 _("Warning: %s, you must set rpcpassword=<password>\nin the configuration file: %s\n"
2181 "If the file does not exist, create it with owner-readable-only file permissions.\n"),
2183 GetConfigFile().c_str());
2184 CreateThread(Shutdown, NULL);
2188 bool fUseSSL = GetBoolArg("-rpcssl");
2189 asio::ip::address bindAddress = mapArgs.count("-rpcallowip") ? asio::ip::address_v4::any() : asio::ip::address_v4::loopback();
2191 asio::io_service io_service;
2192 ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", 8332));
2193 ip::tcp::acceptor acceptor(io_service, endpoint);
2195 acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
2198 ssl::context context(io_service, ssl::context::sslv23);
2201 context.set_options(ssl::context::no_sslv2);
2202 filesystem::path certfile = GetArg("-rpcsslcertificatechainfile", "server.cert");
2203 if (!certfile.is_complete()) certfile = filesystem::path(GetDataDir()) / certfile;
2204 if (filesystem::exists(certfile)) context.use_certificate_chain_file(certfile.string().c_str());
2205 else printf("ThreadRPCServer ERROR: missing server certificate file %s\n", certfile.string().c_str());
2206 filesystem::path pkfile = GetArg("-rpcsslprivatekeyfile", "server.pem");
2207 if (!pkfile.is_complete()) pkfile = filesystem::path(GetDataDir()) / pkfile;
2208 if (filesystem::exists(pkfile)) context.use_private_key_file(pkfile.string().c_str(), ssl::context::pem);
2209 else printf("ThreadRPCServer ERROR: missing server private key file %s\n", pkfile.string().c_str());
2211 string ciphers = GetArg("-rpcsslciphers",
2212 "TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH");
2213 SSL_CTX_set_cipher_list(context.impl(), ciphers.c_str());
2217 throw runtime_error("-rpcssl=1, but bitcoin compiled without full openssl libraries.");
2222 // Accept connection
2224 SSLStream sslStream(io_service, context);
2225 SSLIOStreamDevice d(sslStream, fUseSSL);
2226 iostreams::stream<SSLIOStreamDevice> stream(d);
2228 ip::tcp::iostream stream;
2231 ip::tcp::endpoint peer;
2232 vnThreadsRunning[4]--;
2234 acceptor.accept(sslStream.lowest_layer(), peer);
2236 acceptor.accept(*stream.rdbuf(), peer);
2238 vnThreadsRunning[4]++;
2242 // Restrict callers by IP
2243 if (!ClientAllowed(peer.address().to_string()))
2245 // Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake.
2247 stream << HTTPReply(403, "") << std::flush;
2251 map<string, string> mapHeaders;
2254 boost::thread api_caller(ReadHTTP, boost::ref(stream), boost::ref(mapHeaders), boost::ref(strRequest));
2255 if (!api_caller.timed_join(boost::posix_time::seconds(GetArg("-rpctimeout", 30))))
2258 printf("ThreadRPCServer ReadHTTP timeout\n");
2262 // Check authorization
2263 if (mapHeaders.count("authorization") == 0)
2265 stream << HTTPReply(401, "") << std::flush;
2268 if (!HTTPAuthorized(mapHeaders))
2270 // Deter brute-forcing short passwords
2271 if (mapArgs["-rpcpassword"].size() < 15)
2274 stream << HTTPReply(401, "") << std::flush;
2275 printf("ThreadRPCServer incorrect password attempt\n");
2279 Value id = Value::null;
2284 if (!read_string(strRequest, valRequest) || valRequest.type() != obj_type)
2285 throw JSONRPCError(-32700, "Parse error");
2286 const Object& request = valRequest.get_obj();
2288 // Parse id now so errors from here on will have the id
2289 id = find_value(request, "id");
2292 Value valMethod = find_value(request, "method");
2293 if (valMethod.type() == null_type)
2294 throw JSONRPCError(-32600, "Missing method");
2295 if (valMethod.type() != str_type)
2296 throw JSONRPCError(-32600, "Method must be a string");
2297 string strMethod = valMethod.get_str();
2298 if (strMethod != "getwork" && strMethod != "getmemorypool")
2299 printf("ThreadRPCServer method=%s\n", strMethod.c_str());
2302 Value valParams = find_value(request, "params");
2304 if (valParams.type() == array_type)
2305 params = valParams.get_array();
2306 else if (valParams.type() == null_type)
2309 throw JSONRPCError(-32600, "Params must be an array");
2312 map<string, rpcfn_type>::iterator mi = mapCallTable.find(strMethod);
2313 if (mi == mapCallTable.end())
2314 throw JSONRPCError(-32601, "Method not found");
2316 // Observe safe mode
2317 string strWarning = GetWarnings("rpc");
2318 if (strWarning != "" && !GetBoolArg("-disablesafemode") && !setAllowInSafeMode.count(strMethod))
2319 throw JSONRPCError(-2, string("Safe mode: ") + strWarning);
2325 CRITICAL_BLOCK(cs_main)
2326 CRITICAL_BLOCK(pwalletMain->cs_wallet)
2327 result = (*(*mi).second)(params, false);
2330 string strReply = JSONRPCReply(result, Value::null, id);
2331 stream << HTTPReply(200, strReply) << std::flush;
2333 catch (std::exception& e)
2335 ErrorReply(stream, JSONRPCError(-1, e.what()), id);
2338 catch (Object& objError)
2340 ErrorReply(stream, objError, id);
2342 catch (std::exception& e)
2344 ErrorReply(stream, JSONRPCError(-32700, e.what()), id);
2352 Object CallRPC(const string& strMethod, const Array& params)
2354 if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
2355 throw runtime_error(strprintf(
2356 _("You must set rpcpassword=<password> in the configuration file:\n%s\n"
2357 "If the file does not exist, create it with owner-readable-only file permissions."),
2358 GetConfigFile().c_str()));
2360 // Connect to localhost
2361 bool fUseSSL = GetBoolArg("-rpcssl");
2363 asio::io_service io_service;
2364 ssl::context context(io_service, ssl::context::sslv23);
2365 context.set_options(ssl::context::no_sslv2);
2366 SSLStream sslStream(io_service, context);
2367 SSLIOStreamDevice d(sslStream, fUseSSL);
2368 iostreams::stream<SSLIOStreamDevice> stream(d);
2369 if (!d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332")))
2370 throw runtime_error("couldn't connect to server");
2373 throw runtime_error("-rpcssl=1, but bitcoin compiled without full openssl libraries.");
2375 ip::tcp::iostream stream(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332"));
2377 throw runtime_error("couldn't connect to server");
2381 // HTTP basic authentication
2382 string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
2383 map<string, string> mapRequestHeaders;
2384 mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64;
2387 string strRequest = JSONRPCRequest(strMethod, params, 1);
2388 string strPost = HTTPPost(strRequest, mapRequestHeaders);
2389 stream << strPost << std::flush;
2392 map<string, string> mapHeaders;
2394 int nStatus = ReadHTTP(stream, mapHeaders, strReply);
2396 throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
2397 else if (nStatus >= 400 && nStatus != 400 && nStatus != 404 && nStatus != 500)
2398 throw runtime_error(strprintf("server returned HTTP error %d", nStatus));
2399 else if (strReply.empty())
2400 throw runtime_error("no response from server");
2404 if (!read_string(strReply, valReply))
2405 throw runtime_error("couldn't parse reply from server");
2406 const Object& reply = valReply.get_obj();
2408 throw runtime_error("expected reply to have result, error and id properties");
2416 template<typename T>
2417 void ConvertTo(Value& value)
2419 if (value.type() == str_type)
2421 // reinterpret string as unquoted json value
2423 if (!read_string(value.get_str(), value2))
2424 throw runtime_error("type mismatch");
2425 value = value2.get_value<T>();
2429 value = value.get_value<T>();
2433 int CommandLineRPC(int argc, char *argv[])
2440 while (argc > 1 && IsSwitchChar(argv[1][0]))
2448 throw runtime_error("too few parameters");
2449 string strMethod = argv[1];
2451 // Parameters default to strings
2453 for (int i = 2; i < argc; i++)
2454 params.push_back(argv[i]);
2455 int n = params.size();
2458 // Special case non-string parameter types
2460 if (strMethod == "setgenerate" && n > 0) ConvertTo<bool>(params[0]);
2461 if (strMethod == "setgenerate" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2462 if (strMethod == "sendtoaddress" && n > 1) ConvertTo<double>(params[1]);
2463 if (strMethod == "settxfee" && n > 0) ConvertTo<double>(params[0]);
2464 if (strMethod == "getreceivedbyaddress" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2465 if (strMethod == "getreceivedbyaccount" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2466 if (strMethod == "listreceivedbyaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2467 if (strMethod == "listreceivedbyaddress" && n > 1) ConvertTo<bool>(params[1]);
2468 if (strMethod == "listreceivedbyaccount" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2469 if (strMethod == "listreceivedbyaccount" && n > 1) ConvertTo<bool>(params[1]);
2470 if (strMethod == "getbalance" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2471 if (strMethod == "move" && n > 2) ConvertTo<double>(params[2]);
2472 if (strMethod == "move" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2473 if (strMethod == "sendfrom" && n > 2) ConvertTo<double>(params[2]);
2474 if (strMethod == "sendfrom" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2475 if (strMethod == "listtransactions" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2476 if (strMethod == "listtransactions" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2477 if (strMethod == "listaccounts" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2478 if (strMethod == "walletpassphrase" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2479 if (strMethod == "listsinceblock" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2480 if (strMethod == "sendmany" && n > 1)
2482 string s = params[1].get_str();
2484 if (!read_string(s, v) || v.type() != obj_type)
2485 throw runtime_error("type mismatch");
2486 params[1] = v.get_obj();
2488 if (strMethod == "sendmany" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2491 Object reply = CallRPC(strMethod, params);
2494 const Value& result = find_value(reply, "result");
2495 const Value& error = find_value(reply, "error");
2497 if (error.type() != null_type)
2500 strPrint = "error: " + write_string(error, false);
2501 int code = find_value(error.get_obj(), "code").get_int();
2507 if (result.type() == null_type)
2509 else if (result.type() == str_type)
2510 strPrint = result.get_str();
2512 strPrint = write_string(result, true);
2515 catch (std::exception& e)
2517 strPrint = string("error: ") + e.what();
2522 PrintException(NULL, "CommandLineRPC()");
2527 fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
2536 int main(int argc, char *argv[])
2539 // Turn off microsoft heap dump noise
2540 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
2541 _CrtSetReportFile(_CRT_WARN, CreateFile("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0));
2543 setbuf(stdin, NULL);
2544 setbuf(stdout, NULL);
2545 setbuf(stderr, NULL);
2549 if (argc >= 2 && string(argv[1]) == "-server")
2551 printf("server ready\n");
2552 ThreadRPCServer(NULL);
2556 return CommandLineRPC(argc, argv);
2559 catch (std::exception& e) {
2560 PrintException(&e, "main()");
2562 PrintException(NULL, "main()");