1 // Copyright (c) 2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2012 The Bitcoin developers
3 // Distributed under the MIT/X11 software license, see the accompanying
4 // file COPYING 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 std::string strRPCUserColonPass;
41 static int64 nWalletUnlockTime;
42 static CCriticalSection cs_nWalletUnlockTime;
45 Object JSONRPCError(int code, const string& message)
48 error.push_back(Pair("code", code));
49 error.push_back(Pair("message", message));
54 void PrintConsole(const std::string &format, ...)
57 int limit = sizeof(buffer);
59 va_start(arg_ptr, format);
60 int ret = _vsnprintf(buffer, limit, format.c_str(), arg_ptr);
62 if (ret < 0 || ret >= limit)
68 fprintf(stdout, "%s", buffer);
72 int64 AmountFromValue(const Value& value)
74 double dAmount = value.get_real();
75 if (dAmount <= 0.0 || dAmount > 21000000.0)
76 throw JSONRPCError(-3, "Invalid amount");
77 int64 nAmount = roundint64(dAmount * COIN);
78 if (!MoneyRange(nAmount))
79 throw JSONRPCError(-3, "Invalid amount");
83 Value ValueFromAmount(int64 amount)
85 return (double)amount / (double)COIN;
88 void WalletTxToJSON(const CWalletTx& wtx, Object& entry)
90 entry.push_back(Pair("confirmations", wtx.GetDepthInMainChain()));
91 entry.push_back(Pair("txid", wtx.GetHash().GetHex()));
92 entry.push_back(Pair("time", (boost::int64_t)wtx.GetTxTime()));
93 BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue)
94 entry.push_back(Pair(item.first, item.second));
97 string AccountFromValue(const Value& value)
99 string strAccount = value.get_str();
100 if (strAccount == "*")
101 throw JSONRPCError(-11, "Invalid account name");
108 /// Note: This interface may still be subject to change.
112 Value help(const Array& params, bool fHelp)
114 if (fHelp || params.size() > 1)
117 "List commands, or get help for a command.");
120 if (params.size() > 0)
121 strCommand = params[0].get_str();
124 set<rpcfn_type> setDone;
125 for (map<string, rpcfn_type>::iterator mi = mapCallTable.begin(); mi != mapCallTable.end(); ++mi)
127 string strMethod = (*mi).first;
128 // We already filter duplicates, but these deprecated screw up the sort order
129 if (strMethod == "getamountreceived" ||
130 strMethod == "getallreceived" ||
131 strMethod == "getblocknumber" || // deprecated
132 (strMethod.find("label") != string::npos))
134 if (strCommand != "" && strMethod != strCommand)
139 rpcfn_type pfn = (*mi).second;
140 if (setDone.insert(pfn).second)
141 (*pfn)(params, true);
143 catch (std::exception& e)
145 // Help text is returned in an exception
146 string strHelp = string(e.what());
147 if (strCommand == "")
148 if (strHelp.find('\n') != string::npos)
149 strHelp = strHelp.substr(0, strHelp.find('\n'));
150 strRet += strHelp + "\n";
154 strRet = strprintf("help: unknown command: %s\n", strCommand.c_str());
155 strRet = strRet.substr(0,strRet.size()-1);
160 Value stop(const Array& params, bool fHelp)
162 if (fHelp || params.size() != 0)
165 "Stop bitcoin server.");
167 // Shutdown will take long enough that the response should get back
168 // NOTE: This should actually work with Bitcoin-Qt too now, but 0.5.0 didn't allow it
170 return "bitcoin server stopping";
172 throw runtime_error("NYI: cannot shut down GUI with RPC command");
177 Value getblockcount(const Array& params, bool fHelp)
179 if (fHelp || params.size() != 0)
182 "Returns the number of blocks in the longest block chain.");
189 Value getblocknumber(const Array& params, bool fHelp)
191 if (fHelp || params.size() != 0)
194 "Deprecated. Use getblockcount.");
200 Value getconnectioncount(const Array& params, bool fHelp)
202 if (fHelp || params.size() != 0)
204 "getconnectioncount\n"
205 "Returns the number of connections to other nodes.");
207 return (int)vNodes.size();
211 double GetDifficulty()
213 // Floating point number that is a multiple of the minimum difficulty,
214 // minimum difficulty = 1.0.
216 if (pindexBest == NULL)
218 int nShift = (pindexBest->nBits >> 24) & 0xff;
221 (double)0x0000ffff / (double)(pindexBest->nBits & 0x00ffffff);
237 Value getdifficulty(const Array& params, bool fHelp)
239 if (fHelp || params.size() != 0)
242 "Returns the proof-of-work difficulty as a multiple of the minimum difficulty.");
244 return GetDifficulty();
248 Value getgenerate(const Array& params, bool fHelp)
250 if (fHelp || params.size() != 0)
253 "Returns true or false.");
255 return (bool)fGenerateBitcoins;
259 Value setgenerate(const Array& params, bool fHelp)
261 if (fHelp || params.size() < 1 || params.size() > 2)
263 "setgenerate <generate> [genproclimit]\n"
264 "<generate> is true or false to turn generation on or off.\n"
265 "Generation is limited to [genproclimit] processors, -1 is unlimited.");
267 bool fGenerate = true;
268 if (params.size() > 0)
269 fGenerate = params[0].get_bool();
271 if (params.size() > 1)
273 int nGenProcLimit = params[1].get_int();
274 fLimitProcessors = (nGenProcLimit != -1);
275 WriteSetting("fLimitProcessors", fLimitProcessors);
276 if (nGenProcLimit != -1)
277 WriteSetting("nLimitProcessors", nLimitProcessors = nGenProcLimit);
278 if (nGenProcLimit == 0)
282 GenerateBitcoins(fGenerate, pwalletMain);
287 Value gethashespersec(const Array& params, bool fHelp)
289 if (fHelp || params.size() != 0)
292 "Returns a recent hashes per second performance measurement while generating.");
294 if (GetTimeMillis() - nHPSTimerStart > 8000)
295 return (boost::int64_t)0;
296 return (boost::int64_t)dHashesPerSec;
300 Value getinfo(const Array& params, bool fHelp)
302 if (fHelp || params.size() != 0)
305 "Returns an object containing various state info.");
308 obj.push_back(Pair("version", (int)VERSION));
309 obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance())));
310 obj.push_back(Pair("blocks", (int)nBestHeight));
311 obj.push_back(Pair("connections", (int)vNodes.size()));
312 obj.push_back(Pair("proxy", (fUseProxy ? addrProxy.ToStringIPPort() : string())));
313 obj.push_back(Pair("generate", (bool)fGenerateBitcoins));
314 obj.push_back(Pair("genproclimit", (int)(fLimitProcessors ? nLimitProcessors : -1)));
315 obj.push_back(Pair("difficulty", (double)GetDifficulty()));
316 obj.push_back(Pair("hashespersec", gethashespersec(params, false)));
317 obj.push_back(Pair("testnet", fTestNet));
318 obj.push_back(Pair("keypoololdest", (boost::int64_t)pwalletMain->GetOldestKeyPoolTime()));
319 obj.push_back(Pair("keypoolsize", pwalletMain->GetKeyPoolSize()));
320 obj.push_back(Pair("paytxfee", ValueFromAmount(nTransactionFee)));
321 if (pwalletMain->IsCrypted())
322 obj.push_back(Pair("unlocked_until", (boost::int64_t)nWalletUnlockTime / 1000));
323 obj.push_back(Pair("errors", GetWarnings("statusbar")));
328 Value getnewaddress(const Array& params, bool fHelp)
330 if (fHelp || params.size() > 1)
332 "getnewaddress [account]\n"
333 "Returns a new bitcoin address for receiving payments. "
334 "If [account] is specified (recommended), it is added to the address book "
335 "so payments received with the address will be credited to [account].");
337 // Parse the account first so we don't generate a key if there's an error
339 if (params.size() > 0)
340 strAccount = AccountFromValue(params[0]);
342 if (!pwalletMain->IsLocked())
343 pwalletMain->TopUpKeyPool();
345 // Generate a new key that is added to wallet
346 std::vector<unsigned char> newKey;
347 if (!pwalletMain->GetKeyFromPool(newKey, false))
348 throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
349 CBitcoinAddress address(newKey);
351 pwalletMain->SetAddressBookName(address, strAccount);
353 return address.ToString();
357 CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false)
359 CWalletDB walletdb(pwalletMain->strWalletFile);
362 walletdb.ReadAccount(strAccount, account);
364 bool bKeyUsed = false;
366 // Check if the current key has been used
367 if (!account.vchPubKey.empty())
369 CScript scriptPubKey;
370 scriptPubKey.SetBitcoinAddress(account.vchPubKey);
371 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
372 it != pwalletMain->mapWallet.end() && !account.vchPubKey.empty();
375 const CWalletTx& wtx = (*it).second;
376 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
377 if (txout.scriptPubKey == scriptPubKey)
382 // Generate a new key
383 if (account.vchPubKey.empty() || bForceNew || bKeyUsed)
385 if (!pwalletMain->GetKeyFromPool(account.vchPubKey, false))
386 throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
388 pwalletMain->SetAddressBookName(CBitcoinAddress(account.vchPubKey), strAccount);
389 walletdb.WriteAccount(strAccount, account);
392 return CBitcoinAddress(account.vchPubKey);
395 Value getaccountaddress(const Array& params, bool fHelp)
397 if (fHelp || params.size() != 1)
399 "getaccountaddress <account>\n"
400 "Returns the current bitcoin address for receiving payments to this account.");
402 // Parse the account first so we don't generate a key if there's an error
403 string strAccount = AccountFromValue(params[0]);
407 ret = GetAccountAddress(strAccount).ToString();
414 Value setaccount(const Array& params, bool fHelp)
416 if (fHelp || params.size() < 1 || params.size() > 2)
418 "setaccount <bitcoinaddress> <account>\n"
419 "Sets the account associated with the given address.");
421 CBitcoinAddress address(params[0].get_str());
422 if (!address.IsValid())
423 throw JSONRPCError(-5, "Invalid bitcoin address");
427 if (params.size() > 1)
428 strAccount = AccountFromValue(params[1]);
430 // Detect when changing the account of an address that is the 'unused current key' of another account:
431 if (pwalletMain->mapAddressBook.count(address))
433 string strOldAccount = pwalletMain->mapAddressBook[address];
434 if (address == GetAccountAddress(strOldAccount))
435 GetAccountAddress(strOldAccount, true);
438 pwalletMain->SetAddressBookName(address, strAccount);
444 Value getaccount(const Array& params, bool fHelp)
446 if (fHelp || params.size() != 1)
448 "getaccount <bitcoinaddress>\n"
449 "Returns the account associated with the given address.");
451 CBitcoinAddress address(params[0].get_str());
452 if (!address.IsValid())
453 throw JSONRPCError(-5, "Invalid bitcoin address");
456 map<CBitcoinAddress, string>::iterator mi = pwalletMain->mapAddressBook.find(address);
457 if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.empty())
458 strAccount = (*mi).second;
463 Value getaddressesbyaccount(const Array& params, bool fHelp)
465 if (fHelp || params.size() != 1)
467 "getaddressesbyaccount <account>\n"
468 "Returns the list of addresses for the given account.");
470 string strAccount = AccountFromValue(params[0]);
472 // Find all addresses that have the given account
474 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
476 const CBitcoinAddress& address = item.first;
477 const string& strName = item.second;
478 if (strName == strAccount)
479 ret.push_back(address.ToString());
484 Value settxfee(const Array& params, bool fHelp)
486 if (fHelp || params.size() < 1 || params.size() > 1)
488 "settxfee <amount>\n"
489 "<amount> is a real and is rounded to the nearest 0.00000001");
493 if (params[0].get_real() != 0.0)
494 nAmount = AmountFromValue(params[0]); // rejects 0.0 amounts
496 nTransactionFee = nAmount;
500 Value sendtoaddress(const Array& params, bool fHelp)
502 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
504 "sendtoaddress <bitcoinaddress> <amount> [comment] [comment-to]\n"
505 "<amount> is a real and is rounded to the nearest 0.00000001\n"
506 "requires wallet passphrase to be set with walletpassphrase first");
507 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
509 "sendtoaddress <bitcoinaddress> <amount> [comment] [comment-to]\n"
510 "<amount> is a real and is rounded to the nearest 0.00000001");
512 CBitcoinAddress address(params[0].get_str());
513 if (!address.IsValid())
514 throw JSONRPCError(-5, "Invalid bitcoin address");
517 int64 nAmount = AmountFromValue(params[1]);
521 if (params.size() > 2 && params[2].type() != null_type && !params[2].get_str().empty())
522 wtx.mapValue["comment"] = params[2].get_str();
523 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
524 wtx.mapValue["to"] = params[3].get_str();
526 if (pwalletMain->IsLocked())
527 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
529 string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
531 throw JSONRPCError(-4, strError);
533 return wtx.GetHash().GetHex();
536 static const string strMessageMagic = "Bitcoin Signed Message:\n";
538 Value signmessage(const Array& params, bool fHelp)
540 if (fHelp || params.size() != 2)
542 "signmessage <bitcoinaddress> <message>\n"
543 "Sign a message with the private key of an address");
545 if (pwalletMain->IsLocked())
546 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
548 string strAddress = params[0].get_str();
549 string strMessage = params[1].get_str();
551 CBitcoinAddress addr(strAddress);
553 throw JSONRPCError(-3, "Invalid address");
556 if (!pwalletMain->GetKey(addr, key))
557 throw JSONRPCError(-4, "Private key not available");
559 CDataStream ss(SER_GETHASH);
560 ss << strMessageMagic;
563 vector<unsigned char> vchSig;
564 if (!key.SignCompact(Hash(ss.begin(), ss.end()), vchSig))
565 throw JSONRPCError(-5, "Sign failed");
567 return EncodeBase64(&vchSig[0], vchSig.size());
570 Value verifymessage(const Array& params, bool fHelp)
572 if (fHelp || params.size() != 3)
574 "verifymessage <bitcoinaddress> <signature> <message>\n"
575 "Verify a signed message");
577 string strAddress = params[0].get_str();
578 string strSign = params[1].get_str();
579 string strMessage = params[2].get_str();
581 CBitcoinAddress addr(strAddress);
583 throw JSONRPCError(-3, "Invalid address");
585 bool fInvalid = false;
586 vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid);
589 throw JSONRPCError(-5, "Malformed base64 encoding");
591 CDataStream ss(SER_GETHASH);
592 ss << strMessageMagic;
596 if (!key.SetCompactSignature(Hash(ss.begin(), ss.end()), vchSig))
599 return (key.GetAddress() == addr);
603 Value getreceivedbyaddress(const Array& params, bool fHelp)
605 if (fHelp || params.size() < 1 || params.size() > 2)
607 "getreceivedbyaddress <bitcoinaddress> [minconf=1]\n"
608 "Returns the total amount received by <bitcoinaddress> in transactions with at least [minconf] confirmations.");
611 CBitcoinAddress address = CBitcoinAddress(params[0].get_str());
612 CScript scriptPubKey;
613 if (!address.IsValid())
614 throw JSONRPCError(-5, "Invalid bitcoin address");
615 scriptPubKey.SetBitcoinAddress(address);
616 if (!IsMine(*pwalletMain,scriptPubKey))
619 // Minimum confirmations
621 if (params.size() > 1)
622 nMinDepth = params[1].get_int();
626 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
628 const CWalletTx& wtx = (*it).second;
629 if (wtx.IsCoinBase() || !wtx.IsFinal())
632 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
633 if (txout.scriptPubKey == scriptPubKey)
634 if (wtx.GetDepthInMainChain() >= nMinDepth)
635 nAmount += txout.nValue;
638 return ValueFromAmount(nAmount);
642 void GetAccountAddresses(string strAccount, set<CBitcoinAddress>& setAddress)
644 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
646 const CBitcoinAddress& address = item.first;
647 const string& strName = item.second;
648 if (strName == strAccount)
649 setAddress.insert(address);
654 Value getreceivedbyaccount(const Array& params, bool fHelp)
656 if (fHelp || params.size() < 1 || params.size() > 2)
658 "getreceivedbyaccount <account> [minconf=1]\n"
659 "Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.");
661 // Minimum confirmations
663 if (params.size() > 1)
664 nMinDepth = params[1].get_int();
666 // Get the set of pub keys that have the label
667 string strAccount = AccountFromValue(params[0]);
668 set<CBitcoinAddress> setAddress;
669 GetAccountAddresses(strAccount, setAddress);
673 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
675 const CWalletTx& wtx = (*it).second;
676 if (wtx.IsCoinBase() || !wtx.IsFinal())
679 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
681 CBitcoinAddress address;
682 if (ExtractAddress(txout.scriptPubKey, pwalletMain, address) && setAddress.count(address))
683 if (wtx.GetDepthInMainChain() >= nMinDepth)
684 nAmount += txout.nValue;
688 return (double)nAmount / (double)COIN;
692 int64 GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth)
696 // Tally wallet transactions
697 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
699 const CWalletTx& wtx = (*it).second;
703 int64 nGenerated, nReceived, nSent, nFee;
704 wtx.GetAccountAmounts(strAccount, nGenerated, nReceived, nSent, nFee);
706 if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
707 nBalance += nReceived;
708 nBalance += nGenerated - nSent - nFee;
711 // Tally internal accounting entries
712 nBalance += walletdb.GetAccountCreditDebit(strAccount);
717 int64 GetAccountBalance(const string& strAccount, int nMinDepth)
719 CWalletDB walletdb(pwalletMain->strWalletFile);
720 return GetAccountBalance(walletdb, strAccount, nMinDepth);
724 Value getbalance(const Array& params, bool fHelp)
726 if (fHelp || params.size() > 2)
728 "getbalance [account] [minconf=1]\n"
729 "If [account] is not specified, returns the server's total available balance.\n"
730 "If [account] is specified, returns the balance in the account.");
732 if (params.size() == 0)
733 return ValueFromAmount(pwalletMain->GetBalance());
736 if (params.size() > 1)
737 nMinDepth = params[1].get_int();
739 if (params[0].get_str() == "*") {
740 // Calculate total balance a different way from GetBalance()
741 // (GetBalance() sums up all unspent TxOuts)
742 // getbalance and getbalance '*' should always return the same number.
744 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
746 const CWalletTx& wtx = (*it).second;
750 int64 allGeneratedImmature, allGeneratedMature, allFee;
751 allGeneratedImmature = allGeneratedMature = allFee = 0;
752 string strSentAccount;
753 list<pair<CBitcoinAddress, int64> > listReceived;
754 list<pair<CBitcoinAddress, int64> > listSent;
755 wtx.GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount);
756 if (wtx.GetDepthInMainChain() >= nMinDepth)
758 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listReceived)
759 nBalance += r.second;
761 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listSent)
762 nBalance -= r.second;
764 nBalance += allGeneratedMature;
766 return ValueFromAmount(nBalance);
769 string strAccount = AccountFromValue(params[0]);
771 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
773 return ValueFromAmount(nBalance);
777 Value movecmd(const Array& params, bool fHelp)
779 if (fHelp || params.size() < 3 || params.size() > 5)
781 "move <fromaccount> <toaccount> <amount> [minconf=1] [comment]\n"
782 "Move from one account in your wallet to another.");
784 string strFrom = AccountFromValue(params[0]);
785 string strTo = AccountFromValue(params[1]);
786 int64 nAmount = AmountFromValue(params[2]);
787 if (params.size() > 3)
788 // unused parameter, used to be nMinDepth, keep type-checking it though
789 (void)params[3].get_int();
791 if (params.size() > 4)
792 strComment = params[4].get_str();
794 CWalletDB walletdb(pwalletMain->strWalletFile);
795 if (!walletdb.TxnBegin())
796 throw JSONRPCError(-20, "database error");
798 int64 nNow = GetAdjustedTime();
801 CAccountingEntry debit;
802 debit.strAccount = strFrom;
803 debit.nCreditDebit = -nAmount;
805 debit.strOtherAccount = strTo;
806 debit.strComment = strComment;
807 walletdb.WriteAccountingEntry(debit);
810 CAccountingEntry credit;
811 credit.strAccount = strTo;
812 credit.nCreditDebit = nAmount;
814 credit.strOtherAccount = strFrom;
815 credit.strComment = strComment;
816 walletdb.WriteAccountingEntry(credit);
818 if (!walletdb.TxnCommit())
819 throw JSONRPCError(-20, "database error");
825 Value sendfrom(const Array& params, bool fHelp)
827 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
829 "sendfrom <fromaccount> <tobitcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
830 "<amount> is a real and is rounded to the nearest 0.00000001\n"
831 "requires wallet passphrase to be set with walletpassphrase first");
832 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
834 "sendfrom <fromaccount> <tobitcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
835 "<amount> is a real and is rounded to the nearest 0.00000001");
837 string strAccount = AccountFromValue(params[0]);
838 CBitcoinAddress address(params[1].get_str());
839 if (!address.IsValid())
840 throw JSONRPCError(-5, "Invalid bitcoin address");
841 int64 nAmount = AmountFromValue(params[2]);
843 if (params.size() > 3)
844 nMinDepth = params[3].get_int();
847 wtx.strFromAccount = strAccount;
848 if (params.size() > 4 && params[4].type() != null_type && !params[4].get_str().empty())
849 wtx.mapValue["comment"] = params[4].get_str();
850 if (params.size() > 5 && params[5].type() != null_type && !params[5].get_str().empty())
851 wtx.mapValue["to"] = params[5].get_str();
853 if (pwalletMain->IsLocked())
854 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
857 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
858 if (nAmount > nBalance)
859 throw JSONRPCError(-6, "Account has insufficient funds");
862 string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
864 throw JSONRPCError(-4, strError);
866 return wtx.GetHash().GetHex();
870 Value sendmany(const Array& params, bool fHelp)
872 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
874 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
875 "amounts are double-precision floating point numbers\n"
876 "requires wallet passphrase to be set with walletpassphrase first");
877 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
879 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
880 "amounts are double-precision floating point numbers");
882 string strAccount = AccountFromValue(params[0]);
883 Object sendTo = params[1].get_obj();
885 if (params.size() > 2)
886 nMinDepth = params[2].get_int();
889 wtx.strFromAccount = strAccount;
890 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
891 wtx.mapValue["comment"] = params[3].get_str();
893 set<CBitcoinAddress> setAddress;
894 vector<pair<CScript, int64> > vecSend;
896 int64 totalAmount = 0;
897 BOOST_FOREACH(const Pair& s, sendTo)
899 CBitcoinAddress address(s.name_);
900 if (!address.IsValid())
901 throw JSONRPCError(-5, string("Invalid bitcoin address:")+s.name_);
903 if (setAddress.count(address))
904 throw JSONRPCError(-8, string("Invalid parameter, duplicated address: ")+s.name_);
905 setAddress.insert(address);
907 CScript scriptPubKey;
908 scriptPubKey.SetBitcoinAddress(address);
909 int64 nAmount = AmountFromValue(s.value_);
910 totalAmount += nAmount;
912 vecSend.push_back(make_pair(scriptPubKey, nAmount));
915 if (pwalletMain->IsLocked())
916 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
919 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
920 if (totalAmount > nBalance)
921 throw JSONRPCError(-6, "Account has insufficient funds");
924 CReserveKey keyChange(pwalletMain);
925 int64 nFeeRequired = 0;
926 bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired);
929 if (totalAmount + nFeeRequired > pwalletMain->GetBalance())
930 throw JSONRPCError(-6, "Insufficient funds");
931 throw JSONRPCError(-4, "Transaction creation failed");
933 if (!pwalletMain->CommitTransaction(wtx, keyChange))
934 throw JSONRPCError(-4, "Transaction commit failed");
936 return wtx.GetHash().GetHex();
951 Value ListReceived(const Array& params, bool fByAccounts)
953 // Minimum confirmations
955 if (params.size() > 0)
956 nMinDepth = params[0].get_int();
958 // Whether to include empty accounts
959 bool fIncludeEmpty = false;
960 if (params.size() > 1)
961 fIncludeEmpty = params[1].get_bool();
964 map<CBitcoinAddress, tallyitem> mapTally;
965 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
967 const CWalletTx& wtx = (*it).second;
968 if (wtx.IsCoinBase() || !wtx.IsFinal())
971 int nDepth = wtx.GetDepthInMainChain();
972 if (nDepth < nMinDepth)
975 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
977 CBitcoinAddress address;
978 if (!ExtractAddress(txout.scriptPubKey, pwalletMain, address) || !address.IsValid())
981 tallyitem& item = mapTally[address];
982 item.nAmount += txout.nValue;
983 item.nConf = min(item.nConf, nDepth);
989 map<string, tallyitem> mapAccountTally;
990 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
992 const CBitcoinAddress& address = item.first;
993 const string& strAccount = item.second;
994 map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
995 if (it == mapTally.end() && !fIncludeEmpty)
1000 if (it != mapTally.end())
1002 nAmount = (*it).second.nAmount;
1003 nConf = (*it).second.nConf;
1008 tallyitem& item = mapAccountTally[strAccount];
1009 item.nAmount += nAmount;
1010 item.nConf = min(item.nConf, nConf);
1015 obj.push_back(Pair("address", address.ToString()));
1016 obj.push_back(Pair("account", strAccount));
1017 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1018 obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf)));
1025 for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
1027 int64 nAmount = (*it).second.nAmount;
1028 int nConf = (*it).second.nConf;
1030 obj.push_back(Pair("account", (*it).first));
1031 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1032 obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf)));
1040 Value listreceivedbyaddress(const Array& params, bool fHelp)
1042 if (fHelp || params.size() > 2)
1043 throw runtime_error(
1044 "listreceivedbyaddress [minconf=1] [includeempty=false]\n"
1045 "[minconf] is the minimum number of confirmations before payments are included.\n"
1046 "[includeempty] whether to include addresses that haven't received any payments.\n"
1047 "Returns an array of objects containing:\n"
1048 " \"address\" : receiving address\n"
1049 " \"account\" : the account of the receiving address\n"
1050 " \"amount\" : total amount received by the address\n"
1051 " \"confirmations\" : number of confirmations of the most recent transaction included");
1053 return ListReceived(params, false);
1056 Value listreceivedbyaccount(const Array& params, bool fHelp)
1058 if (fHelp || params.size() > 2)
1059 throw runtime_error(
1060 "listreceivedbyaccount [minconf=1] [includeempty=false]\n"
1061 "[minconf] is the minimum number of confirmations before payments are included.\n"
1062 "[includeempty] whether to include accounts that haven't received any payments.\n"
1063 "Returns an array of objects containing:\n"
1064 " \"account\" : the account of the receiving addresses\n"
1065 " \"amount\" : total amount received by addresses with this account\n"
1066 " \"confirmations\" : number of confirmations of the most recent transaction included");
1068 return ListReceived(params, true);
1071 void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret)
1073 int64 nGeneratedImmature, nGeneratedMature, nFee;
1074 string strSentAccount;
1075 list<pair<CBitcoinAddress, int64> > listReceived;
1076 list<pair<CBitcoinAddress, int64> > listSent;
1077 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1079 bool fAllAccounts = (strAccount == string("*"));
1081 // Generated blocks assigned to account ""
1082 if ((nGeneratedMature+nGeneratedImmature) != 0 && (fAllAccounts || strAccount == ""))
1085 entry.push_back(Pair("account", string("")));
1086 if (nGeneratedImmature)
1088 entry.push_back(Pair("category", wtx.GetDepthInMainChain() ? "immature" : "orphan"));
1089 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedImmature)));
1093 entry.push_back(Pair("category", "generate"));
1094 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedMature)));
1097 WalletTxToJSON(wtx, entry);
1098 ret.push_back(entry);
1102 if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
1104 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1107 entry.push_back(Pair("account", strSentAccount));
1108 entry.push_back(Pair("address", s.first.ToString()));
1109 entry.push_back(Pair("category", "send"));
1110 entry.push_back(Pair("amount", ValueFromAmount(-s.second)));
1111 entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
1113 WalletTxToJSON(wtx, entry);
1114 ret.push_back(entry);
1119 if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
1121 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1124 if (pwalletMain->mapAddressBook.count(r.first))
1125 account = pwalletMain->mapAddressBook[r.first];
1126 if (fAllAccounts || (account == strAccount))
1129 entry.push_back(Pair("account", account));
1130 entry.push_back(Pair("address", r.first.ToString()));
1131 entry.push_back(Pair("category", "receive"));
1132 entry.push_back(Pair("amount", ValueFromAmount(r.second)));
1134 WalletTxToJSON(wtx, entry);
1135 ret.push_back(entry);
1141 void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret)
1143 bool fAllAccounts = (strAccount == string("*"));
1145 if (fAllAccounts || acentry.strAccount == strAccount)
1148 entry.push_back(Pair("account", acentry.strAccount));
1149 entry.push_back(Pair("category", "move"));
1150 entry.push_back(Pair("time", (boost::int64_t)acentry.nTime));
1151 entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
1152 entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
1153 entry.push_back(Pair("comment", acentry.strComment));
1154 ret.push_back(entry);
1158 Value listtransactions(const Array& params, bool fHelp)
1160 if (fHelp || params.size() > 3)
1161 throw runtime_error(
1162 "listtransactions [account] [count=10] [from=0]\n"
1163 "Returns up to [count] most recent transactions skipping the first [from] transactions for account [account].");
1165 string strAccount = "*";
1166 if (params.size() > 0)
1167 strAccount = params[0].get_str();
1169 if (params.size() > 1)
1170 nCount = params[1].get_int();
1172 if (params.size() > 2)
1173 nFrom = params[2].get_int();
1176 throw JSONRPCError(-8, "Negative count");
1178 throw JSONRPCError(-8, "Negative from");
1181 CWalletDB walletdb(pwalletMain->strWalletFile);
1183 // First: get all CWalletTx and CAccountingEntry into a sorted-by-time multimap.
1184 typedef pair<CWalletTx*, CAccountingEntry*> TxPair;
1185 typedef multimap<int64, TxPair > TxItems;
1188 // Note: maintaining indices in the database of (account,time) --> txid and (account, time) --> acentry
1189 // would make this much faster for applications that do this a lot.
1190 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1192 CWalletTx* wtx = &((*it).second);
1193 txByTime.insert(make_pair(wtx->GetTxTime(), TxPair(wtx, (CAccountingEntry*)0)));
1195 list<CAccountingEntry> acentries;
1196 walletdb.ListAccountCreditDebit(strAccount, acentries);
1197 BOOST_FOREACH(CAccountingEntry& entry, acentries)
1199 txByTime.insert(make_pair(entry.nTime, TxPair((CWalletTx*)0, &entry)));
1202 // iterate backwards until we have nCount items to return:
1203 for (TxItems::reverse_iterator it = txByTime.rbegin(); it != txByTime.rend(); ++it)
1205 CWalletTx *const pwtx = (*it).second.first;
1207 ListTransactions(*pwtx, strAccount, 0, true, ret);
1208 CAccountingEntry *const pacentry = (*it).second.second;
1210 AcentryToJSON(*pacentry, strAccount, ret);
1212 if (ret.size() >= (nCount+nFrom)) break;
1214 // ret is newest to oldest
1216 if (nFrom > ret.size()) nFrom = ret.size();
1217 if (nFrom+nCount > ret.size()) nCount = ret.size()-nFrom;
1218 Array::iterator first = ret.begin();
1219 std::advance(first, nFrom);
1220 Array::iterator last = ret.begin();
1221 std::advance(last, nFrom+nCount);
1223 if (last != ret.end()) ret.erase(last, ret.end());
1224 if (first != ret.begin()) ret.erase(ret.begin(), first);
1226 std::reverse(ret.begin(), ret.end()); // Return oldest to newest
1231 Value listaccounts(const Array& params, bool fHelp)
1233 if (fHelp || params.size() > 1)
1234 throw runtime_error(
1235 "listaccounts [minconf=1]\n"
1236 "Returns Object that has account names as keys, account balances as values.");
1239 if (params.size() > 0)
1240 nMinDepth = params[0].get_int();
1242 map<string, int64> mapAccountBalances;
1243 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& entry, pwalletMain->mapAddressBook) {
1244 if (pwalletMain->HaveKey(entry.first)) // This address belongs to me
1245 mapAccountBalances[entry.second] = 0;
1248 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1250 const CWalletTx& wtx = (*it).second;
1251 int64 nGeneratedImmature, nGeneratedMature, nFee;
1252 string strSentAccount;
1253 list<pair<CBitcoinAddress, int64> > listReceived;
1254 list<pair<CBitcoinAddress, int64> > listSent;
1255 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1256 mapAccountBalances[strSentAccount] -= nFee;
1257 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1258 mapAccountBalances[strSentAccount] -= s.second;
1259 if (wtx.GetDepthInMainChain() >= nMinDepth)
1261 mapAccountBalances[""] += nGeneratedMature;
1262 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1263 if (pwalletMain->mapAddressBook.count(r.first))
1264 mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second;
1266 mapAccountBalances[""] += r.second;
1270 list<CAccountingEntry> acentries;
1271 CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
1272 BOOST_FOREACH(const CAccountingEntry& entry, acentries)
1273 mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
1276 BOOST_FOREACH(const PAIRTYPE(string, int64)& accountBalance, mapAccountBalances) {
1277 ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
1282 Value listsinceblock(const Array& params, bool fHelp)
1285 throw runtime_error(
1286 "listsinceblock [blockhash] [target-confirmations]\n"
1287 "Get all transactions in blocks since block [blockhash], or all transactions if omitted");
1289 CBlockIndex *pindex = NULL;
1290 int target_confirms = 1;
1292 if (params.size() > 0)
1294 uint256 blockId = 0;
1296 blockId.SetHex(params[0].get_str());
1297 pindex = CBlockLocator(blockId).GetBlockIndex();
1300 if (params.size() > 1)
1302 target_confirms = params[1].get_int();
1304 if (target_confirms < 1)
1305 throw JSONRPCError(-8, "Invalid parameter");
1308 int depth = pindex ? (1 + nBestHeight - pindex->nHeight) : -1;
1312 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++)
1314 CWalletTx tx = (*it).second;
1316 if (depth == -1 || tx.GetDepthInMainChain() < depth)
1317 ListTransactions(tx, "*", 0, true, transactions);
1322 if (target_confirms == 1)
1324 lastblock = hashBestChain;
1328 int target_height = pindexBest->nHeight + 1 - target_confirms;
1331 for (block = pindexBest;
1332 block && block->nHeight > target_height;
1333 block = block->pprev) { }
1335 lastblock = block ? block->GetBlockHash() : 0;
1339 ret.push_back(Pair("transactions", transactions));
1340 ret.push_back(Pair("lastblock", lastblock.GetHex()));
1345 Value gettransaction(const Array& params, bool fHelp)
1347 if (fHelp || params.size() != 1)
1348 throw runtime_error(
1349 "gettransaction <txid>\n"
1350 "Get detailed information about <txid>");
1353 hash.SetHex(params[0].get_str());
1357 if (!pwalletMain->mapWallet.count(hash))
1358 throw JSONRPCError(-5, "Invalid or non-wallet transaction id");
1359 const CWalletTx& wtx = pwalletMain->mapWallet[hash];
1361 int64 nCredit = wtx.GetCredit();
1362 int64 nDebit = wtx.GetDebit();
1363 int64 nNet = nCredit - nDebit;
1364 int64 nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0);
1366 entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
1368 entry.push_back(Pair("fee", ValueFromAmount(nFee)));
1370 WalletTxToJSON(pwalletMain->mapWallet[hash], entry);
1373 ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details);
1374 entry.push_back(Pair("details", details));
1380 Value backupwallet(const Array& params, bool fHelp)
1382 if (fHelp || params.size() != 1)
1383 throw runtime_error(
1384 "backupwallet <destination>\n"
1385 "Safely copies wallet.dat to destination, which can be a directory or a path with filename.");
1387 string strDest = params[0].get_str();
1388 BackupWallet(*pwalletMain, strDest);
1394 Value keypoolrefill(const Array& params, bool fHelp)
1396 if (pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1397 throw runtime_error(
1399 "Fills the keypool, requires wallet passphrase to be set.");
1400 if (!pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1401 throw runtime_error(
1403 "Fills the keypool.");
1405 if (pwalletMain->IsLocked())
1406 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
1408 pwalletMain->TopUpKeyPool();
1410 if (pwalletMain->GetKeyPoolSize() < GetArg("-keypool", 100))
1411 throw JSONRPCError(-4, "Error refreshing keypool.");
1417 void ThreadTopUpKeyPool(void* parg)
1419 pwalletMain->TopUpKeyPool();
1422 void ThreadCleanWalletPassphrase(void* parg)
1424 int64 nMyWakeTime = GetTimeMillis() + *((int64*)parg) * 1000;
1426 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1428 if (nWalletUnlockTime == 0)
1430 nWalletUnlockTime = nMyWakeTime;
1434 if (nWalletUnlockTime==0)
1436 int64 nToSleep = nWalletUnlockTime - GetTimeMillis();
1440 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1442 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1446 if (nWalletUnlockTime)
1448 nWalletUnlockTime = 0;
1449 pwalletMain->Lock();
1454 if (nWalletUnlockTime < nMyWakeTime)
1455 nWalletUnlockTime = nMyWakeTime;
1458 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1460 delete (int64*)parg;
1463 Value walletpassphrase(const Array& params, bool fHelp)
1465 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1466 throw runtime_error(
1467 "walletpassphrase <passphrase> <timeout>\n"
1468 "Stores the wallet decryption key in memory for <timeout> seconds.");
1471 if (!pwalletMain->IsCrypted())
1472 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
1474 if (!pwalletMain->IsLocked())
1475 throw JSONRPCError(-17, "Error: Wallet is already unlocked.");
1477 // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
1478 SecureString strWalletPass;
1479 strWalletPass.reserve(100);
1480 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1481 // Alternately, find a way to make params[0] mlock()'d to begin with.
1482 strWalletPass = params[0].get_str().c_str();
1484 if (strWalletPass.length() > 0)
1486 if (!pwalletMain->Unlock(strWalletPass))
1487 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1490 throw runtime_error(
1491 "walletpassphrase <passphrase> <timeout>\n"
1492 "Stores the wallet decryption key in memory for <timeout> seconds.");
1494 CreateThread(ThreadTopUpKeyPool, NULL);
1495 int64* pnSleepTime = new int64(params[1].get_int64());
1496 CreateThread(ThreadCleanWalletPassphrase, pnSleepTime);
1502 Value walletpassphrasechange(const Array& params, bool fHelp)
1504 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1505 throw runtime_error(
1506 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1507 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1510 if (!pwalletMain->IsCrypted())
1511 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
1513 // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
1514 // Alternately, find a way to make params[0] mlock()'d to begin with.
1515 SecureString strOldWalletPass;
1516 strOldWalletPass.reserve(100);
1517 strOldWalletPass = params[0].get_str().c_str();
1519 SecureString strNewWalletPass;
1520 strNewWalletPass.reserve(100);
1521 strNewWalletPass = params[1].get_str().c_str();
1523 if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
1524 throw runtime_error(
1525 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1526 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1528 if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
1529 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1535 Value walletlock(const Array& params, bool fHelp)
1537 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
1538 throw runtime_error(
1540 "Removes the wallet encryption key from memory, locking the wallet.\n"
1541 "After calling this method, you will need to call walletpassphrase again\n"
1542 "before being able to call any methods which require the wallet to be unlocked.");
1545 if (!pwalletMain->IsCrypted())
1546 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletlock was called.");
1548 CRITICAL_BLOCK(cs_nWalletUnlockTime)
1550 pwalletMain->Lock();
1551 nWalletUnlockTime = 0;
1558 Value encryptwallet(const Array& params, bool fHelp)
1560 if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
1561 throw runtime_error(
1562 "encryptwallet <passphrase>\n"
1563 "Encrypts the wallet with <passphrase>.");
1566 if (pwalletMain->IsCrypted())
1567 throw JSONRPCError(-15, "Error: running with an encrypted wallet, but encryptwallet was called.");
1570 // shutting down via RPC while the GUI is running does not work (yet):
1571 throw runtime_error("Not Yet Implemented: use GUI to encrypt wallet, not RPC command");
1574 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1575 // Alternately, find a way to make params[0] mlock()'d to begin with.
1576 SecureString strWalletPass;
1577 strWalletPass.reserve(100);
1578 strWalletPass = params[0].get_str().c_str();
1580 if (strWalletPass.length() < 1)
1581 throw runtime_error(
1582 "encryptwallet <passphrase>\n"
1583 "Encrypts the wallet with <passphrase>.");
1585 if (!pwalletMain->EncryptWallet(strWalletPass))
1586 throw JSONRPCError(-16, "Error: Failed to encrypt the wallet.");
1588 // BDB seems to have a bad habit of writing old data into
1589 // slack space in .dat files; that is bad if the old data is
1590 // unencrypted private keys. So:
1592 return "wallet encrypted; bitcoin server stopping, restart to run with encrypted wallet";
1596 Value validateaddress(const Array& params, bool fHelp)
1598 if (fHelp || params.size() != 1)
1599 throw runtime_error(
1600 "validateaddress <bitcoinaddress>\n"
1601 "Return information about <bitcoinaddress>.");
1603 CBitcoinAddress address(params[0].get_str());
1604 bool isValid = address.IsValid();
1607 ret.push_back(Pair("isvalid", isValid));
1610 // Call Hash160ToAddress() so we always return current ADDRESSVERSION
1611 // version of the address:
1612 string currentAddress = address.ToString();
1613 ret.push_back(Pair("address", currentAddress));
1614 ret.push_back(Pair("ismine", (pwalletMain->HaveKey(address) > 0)));
1615 if (pwalletMain->mapAddressBook.count(address))
1616 ret.push_back(Pair("account", pwalletMain->mapAddressBook[address]));
1622 Value getwork(const Array& params, bool fHelp)
1624 if (fHelp || params.size() > 1)
1625 throw runtime_error(
1627 "If [data] is not specified, returns formatted hash data to work on:\n"
1628 " \"midstate\" : precomputed hash state after hashing the first half of the data (DEPRECATED)\n" // deprecated
1629 " \"data\" : block data\n"
1630 " \"hash1\" : formatted hash buffer for second hash (DEPRECATED)\n" // deprecated
1631 " \"target\" : little endian hash target\n"
1632 "If [data] is specified, tries to solve the block and returns true if it was successful.");
1635 throw JSONRPCError(-9, "Bitcoin is not connected!");
1637 if (IsInitialBlockDownload())
1638 throw JSONRPCError(-10, "Bitcoin is downloading blocks...");
1640 typedef map<uint256, pair<CBlock*, CScript> > mapNewBlock_t;
1641 static mapNewBlock_t mapNewBlock;
1642 static vector<CBlock*> vNewBlock;
1643 static CReserveKey reservekey(pwalletMain);
1645 if (params.size() == 0)
1648 static unsigned int nTransactionsUpdatedLast;
1649 static CBlockIndex* pindexPrev;
1650 static int64 nStart;
1651 static CBlock* pblock;
1652 if (pindexPrev != pindexBest ||
1653 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60))
1655 if (pindexPrev != pindexBest)
1657 // Deallocate old blocks since they're obsolete now
1658 mapNewBlock.clear();
1659 BOOST_FOREACH(CBlock* pblock, vNewBlock)
1663 nTransactionsUpdatedLast = nTransactionsUpdated;
1664 pindexPrev = pindexBest;
1668 pblock = CreateNewBlock(reservekey);
1670 throw JSONRPCError(-7, "Out of memory");
1671 vNewBlock.push_back(pblock);
1675 pblock->UpdateTime(pindexPrev);
1678 // Update nExtraNonce
1679 static unsigned int nExtraNonce = 0;
1680 IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
1683 mapNewBlock[pblock->hashMerkleRoot] = make_pair(pblock, pblock->vtx[0].vin[0].scriptSig);
1685 // Prebuild hash buffers
1689 FormatHashBuffers(pblock, pmidstate, pdata, phash1);
1691 uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
1694 result.push_back(Pair("midstate", HexStr(BEGIN(pmidstate), END(pmidstate)))); // deprecated
1695 result.push_back(Pair("data", HexStr(BEGIN(pdata), END(pdata))));
1696 result.push_back(Pair("hash1", HexStr(BEGIN(phash1), END(phash1)))); // deprecated
1697 result.push_back(Pair("target", HexStr(BEGIN(hashTarget), END(hashTarget))));
1703 vector<unsigned char> vchData = ParseHex(params[0].get_str());
1704 if (vchData.size() != 128)
1705 throw JSONRPCError(-8, "Invalid parameter");
1706 CBlock* pdata = (CBlock*)&vchData[0];
1709 for (int i = 0; i < 128/4; i++)
1710 ((unsigned int*)pdata)[i] = ByteReverse(((unsigned int*)pdata)[i]);
1713 if (!mapNewBlock.count(pdata->hashMerkleRoot))
1715 CBlock* pblock = mapNewBlock[pdata->hashMerkleRoot].first;
1717 pblock->nTime = pdata->nTime;
1718 pblock->nNonce = pdata->nNonce;
1719 pblock->vtx[0].vin[0].scriptSig = mapNewBlock[pdata->hashMerkleRoot].second;
1720 pblock->hashMerkleRoot = pblock->BuildMerkleTree();
1722 return CheckWork(pblock, *pwalletMain, reservekey);
1727 Value getmemorypool(const Array& params, bool fHelp)
1729 if (fHelp || params.size() > 1)
1730 throw runtime_error(
1731 "getmemorypool [data]\n"
1732 "If [data] is not specified, returns data needed to construct a block to work on:\n"
1733 " \"version\" : block version\n"
1734 " \"previousblockhash\" : hash of current highest block\n"
1735 " \"transactions\" : contents of non-coinbase transactions that should be included in the next block\n"
1736 " \"coinbasevalue\" : maximum allowable input to coinbase transaction, including the generation award and transaction fees\n"
1737 " \"time\" : timestamp appropriate for next block\n"
1738 " \"bits\" : compressed target of next block\n"
1739 "If [data] is specified, tries to solve the block and returns true if it was successful.");
1741 if (params.size() == 0)
1744 throw JSONRPCError(-9, "Bitcoin is not connected!");
1746 if (IsInitialBlockDownload())
1747 throw JSONRPCError(-10, "Bitcoin is downloading blocks...");
1749 static CReserveKey reservekey(pwalletMain);
1752 static unsigned int nTransactionsUpdatedLast;
1753 static CBlockIndex* pindexPrev;
1754 static int64 nStart;
1755 static CBlock* pblock;
1756 if (pindexPrev != pindexBest ||
1757 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 5))
1759 nTransactionsUpdatedLast = nTransactionsUpdated;
1760 pindexPrev = pindexBest;
1766 pblock = CreateNewBlock(reservekey);
1768 throw JSONRPCError(-7, "Out of memory");
1772 pblock->UpdateTime(pindexPrev);
1776 BOOST_FOREACH(CTransaction tx, pblock->vtx) {
1783 transactions.push_back(HexStr(ssTx.begin(), ssTx.end()));
1787 result.push_back(Pair("version", pblock->nVersion));
1788 result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex()));
1789 result.push_back(Pair("transactions", transactions));
1790 result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue));
1791 result.push_back(Pair("time", (int64_t)pblock->nTime));
1797 uBits.nBits = htonl((int32_t)pblock->nBits);
1798 result.push_back(Pair("bits", HexStr(BEGIN(uBits.cBits), END(uBits.cBits))));
1805 CDataStream ssBlock(ParseHex(params[0].get_str()));
1809 return ProcessBlock(NULL, &pblock);
1827 pair<string, rpcfn_type> pCallTable[] =
1829 make_pair("help", &help),
1830 make_pair("stop", &stop),
1831 make_pair("getblockcount", &getblockcount),
1832 make_pair("getblocknumber", &getblocknumber),
1833 make_pair("getconnectioncount", &getconnectioncount),
1834 make_pair("getdifficulty", &getdifficulty),
1835 make_pair("getgenerate", &getgenerate),
1836 make_pair("setgenerate", &setgenerate),
1837 make_pair("gethashespersec", &gethashespersec),
1838 make_pair("getinfo", &getinfo),
1839 make_pair("getnewaddress", &getnewaddress),
1840 make_pair("getaccountaddress", &getaccountaddress),
1841 make_pair("setaccount", &setaccount),
1842 make_pair("getaccount", &getaccount),
1843 make_pair("getaddressesbyaccount", &getaddressesbyaccount),
1844 make_pair("sendtoaddress", &sendtoaddress),
1845 make_pair("getreceivedbyaddress", &getreceivedbyaddress),
1846 make_pair("getreceivedbyaccount", &getreceivedbyaccount),
1847 make_pair("listreceivedbyaddress", &listreceivedbyaddress),
1848 make_pair("listreceivedbyaccount", &listreceivedbyaccount),
1849 make_pair("backupwallet", &backupwallet),
1850 make_pair("keypoolrefill", &keypoolrefill),
1851 make_pair("walletpassphrase", &walletpassphrase),
1852 make_pair("walletpassphrasechange", &walletpassphrasechange),
1853 make_pair("walletlock", &walletlock),
1854 make_pair("encryptwallet", &encryptwallet),
1855 make_pair("validateaddress", &validateaddress),
1856 make_pair("getbalance", &getbalance),
1857 make_pair("move", &movecmd),
1858 make_pair("sendfrom", &sendfrom),
1859 make_pair("sendmany", &sendmany),
1860 make_pair("gettransaction", &gettransaction),
1861 make_pair("listtransactions", &listtransactions),
1862 make_pair("signmessage", &signmessage),
1863 make_pair("verifymessage", &verifymessage),
1864 make_pair("getwork", &getwork),
1865 make_pair("listaccounts", &listaccounts),
1866 make_pair("settxfee", &settxfee),
1867 make_pair("getmemorypool", &getmemorypool),
1868 make_pair("listsinceblock", &listsinceblock),
1870 map<string, rpcfn_type> mapCallTable(pCallTable, pCallTable + sizeof(pCallTable)/sizeof(pCallTable[0]));
1872 string pAllowInSafeMode[] =
1877 "getblocknumber", // deprecated
1878 "getconnectioncount",
1885 "getaccountaddress",
1887 "getaddressesbyaccount",
1896 set<string> setAllowInSafeMode(pAllowInSafeMode, pAllowInSafeMode + sizeof(pAllowInSafeMode)/sizeof(pAllowInSafeMode[0]));
1904 // This ain't Apache. We're just using HTTP header for the length field
1905 // and to be compatible with other JSON-RPC implementations.
1908 string HTTPPost(const string& strMsg, const map<string,string>& mapRequestHeaders)
1911 s << "POST / HTTP/1.1\r\n"
1912 << "User-Agent: bitcoin-json-rpc/" << FormatFullVersion() << "\r\n"
1913 << "Host: 127.0.0.1\r\n"
1914 << "Content-Type: application/json\r\n"
1915 << "Content-Length: " << strMsg.size() << "\r\n"
1916 << "Connection: close\r\n"
1917 << "Accept: application/json\r\n";
1918 BOOST_FOREACH(const PAIRTYPE(string, string)& item, mapRequestHeaders)
1919 s << item.first << ": " << item.second << "\r\n";
1920 s << "\r\n" << strMsg;
1925 string rfc1123Time()
1930 struct tm* now_gmt = gmtime(&now);
1931 string locale(setlocale(LC_TIME, NULL));
1932 setlocale(LC_TIME, "C"); // we want posix (aka "C") weekday/month strings
1933 strftime(buffer, sizeof(buffer), "%a, %d %b %Y %H:%M:%S +0000", now_gmt);
1934 setlocale(LC_TIME, locale.c_str());
1935 return string(buffer);
1938 static string HTTPReply(int nStatus, const string& strMsg)
1941 return strprintf("HTTP/1.0 401 Authorization Required\r\n"
1943 "Server: bitcoin-json-rpc/%s\r\n"
1944 "WWW-Authenticate: Basic realm=\"jsonrpc\"\r\n"
1945 "Content-Type: text/html\r\n"
1946 "Content-Length: 296\r\n"
1948 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\r\n"
1949 "\"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd\">\r\n"
1952 "<TITLE>Error</TITLE>\r\n"
1953 "<META HTTP-EQUIV='Content-Type' CONTENT='text/html; charset=ISO-8859-1'>\r\n"
1955 "<BODY><H1>401 Unauthorized.</H1></BODY>\r\n"
1956 "</HTML>\r\n", rfc1123Time().c_str(), FormatFullVersion().c_str());
1957 const char *cStatus;
1958 if (nStatus == 200) cStatus = "OK";
1959 else if (nStatus == 400) cStatus = "Bad Request";
1960 else if (nStatus == 403) cStatus = "Forbidden";
1961 else if (nStatus == 404) cStatus = "Not Found";
1962 else if (nStatus == 500) cStatus = "Internal Server Error";
1965 "HTTP/1.1 %d %s\r\n"
1967 "Connection: close\r\n"
1968 "Content-Length: %d\r\n"
1969 "Content-Type: application/json\r\n"
1970 "Server: bitcoin-json-rpc/%s\r\n"
1975 rfc1123Time().c_str(),
1977 FormatFullVersion().c_str(),
1981 int ReadHTTPStatus(std::basic_istream<char>& stream)
1984 getline(stream, str);
1985 vector<string> vWords;
1986 boost::split(vWords, str, boost::is_any_of(" "));
1987 if (vWords.size() < 2)
1989 return atoi(vWords[1].c_str());
1992 int ReadHTTPHeader(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet)
1998 std::getline(stream, str);
1999 if (str.empty() || str == "\r")
2001 string::size_type nColon = str.find(":");
2002 if (nColon != string::npos)
2004 string strHeader = str.substr(0, nColon);
2005 boost::trim(strHeader);
2006 boost::to_lower(strHeader);
2007 string strValue = str.substr(nColon+1);
2008 boost::trim(strValue);
2009 mapHeadersRet[strHeader] = strValue;
2010 if (strHeader == "content-length")
2011 nLen = atoi(strValue.c_str());
2017 int ReadHTTP(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet, string& strMessageRet)
2019 mapHeadersRet.clear();
2023 int nStatus = ReadHTTPStatus(stream);
2026 int nLen = ReadHTTPHeader(stream, mapHeadersRet);
2027 if (nLen < 0 || nLen > MAX_SIZE)
2033 vector<char> vch(nLen);
2034 stream.read(&vch[0], nLen);
2035 strMessageRet = string(vch.begin(), vch.end());
2041 bool HTTPAuthorized(map<string, string>& mapHeaders)
2043 string strAuth = mapHeaders["authorization"];
2044 if (strAuth.substr(0,6) != "Basic ")
2046 string strUserPass64 = strAuth.substr(6); boost::trim(strUserPass64);
2047 string strUserPass = DecodeBase64(strUserPass64);
2048 return strUserPass == strRPCUserColonPass;
2052 // JSON-RPC protocol. Bitcoin speaks version 1.0 for maximum compatibility,
2053 // but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
2054 // unspecified (HTTP errors and contents of 'error').
2056 // 1.0 spec: http://json-rpc.org/wiki/specification
2057 // 1.2 spec: http://groups.google.com/group/json-rpc/web/json-rpc-over-http
2058 // http://www.codeproject.com/KB/recipes/JSON_Spirit.aspx
2061 string JSONRPCRequest(const string& strMethod, const Array& params, const Value& id)
2064 request.push_back(Pair("method", strMethod));
2065 request.push_back(Pair("params", params));
2066 request.push_back(Pair("id", id));
2067 return write_string(Value(request), false) + "\n";
2070 string JSONRPCReply(const Value& result, const Value& error, const Value& id)
2073 if (error.type() != null_type)
2074 reply.push_back(Pair("result", Value::null));
2076 reply.push_back(Pair("result", result));
2077 reply.push_back(Pair("error", error));
2078 reply.push_back(Pair("id", id));
2079 return write_string(Value(reply), false) + "\n";
2082 void ErrorReply(std::ostream& stream, const Object& objError, const Value& id)
2084 // Send error reply from json-rpc error object
2086 int code = find_value(objError, "code").get_int();
2087 if (code == -32600) nStatus = 400;
2088 else if (code == -32601) nStatus = 404;
2089 string strReply = JSONRPCReply(Value::null, objError, id);
2090 stream << HTTPReply(nStatus, strReply) << std::flush;
2093 bool ClientAllowed(const string& strAddress)
2095 if (strAddress == asio::ip::address_v4::loopback().to_string())
2097 const vector<string>& vAllow = mapMultiArgs["-rpcallowip"];
2098 BOOST_FOREACH(string strAllow, vAllow)
2099 if (WildcardMatch(strAddress, strAllow))
2106 // IOStream device that speaks SSL but can also speak non-SSL
2108 class SSLIOStreamDevice : public iostreams::device<iostreams::bidirectional> {
2110 SSLIOStreamDevice(SSLStream &streamIn, bool fUseSSLIn) : stream(streamIn)
2112 fUseSSL = fUseSSLIn;
2113 fNeedHandshake = fUseSSLIn;
2116 void handshake(ssl::stream_base::handshake_type role)
2118 if (!fNeedHandshake) return;
2119 fNeedHandshake = false;
2120 stream.handshake(role);
2122 std::streamsize read(char* s, std::streamsize n)
2124 handshake(ssl::stream_base::server); // HTTPS servers read first
2125 if (fUseSSL) return stream.read_some(asio::buffer(s, n));
2126 return stream.next_layer().read_some(asio::buffer(s, n));
2128 std::streamsize write(const char* s, std::streamsize n)
2130 handshake(ssl::stream_base::client); // HTTPS clients write first
2131 if (fUseSSL) return asio::write(stream, asio::buffer(s, n));
2132 return asio::write(stream.next_layer(), asio::buffer(s, n));
2134 bool connect(const std::string& server, const std::string& port)
2136 ip::tcp::resolver resolver(stream.get_io_service());
2137 ip::tcp::resolver::query query(server.c_str(), port.c_str());
2138 ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
2139 ip::tcp::resolver::iterator end;
2140 boost::system::error_code error = asio::error::host_not_found;
2141 while (error && endpoint_iterator != end)
2143 stream.lowest_layer().close();
2144 stream.lowest_layer().connect(*endpoint_iterator++, error);
2152 bool fNeedHandshake;
2158 void ThreadRPCServer(void* parg)
2160 IMPLEMENT_RANDOMIZE_STACK(ThreadRPCServer(parg));
2163 vnThreadsRunning[4]++;
2164 ThreadRPCServer2(parg);
2165 vnThreadsRunning[4]--;
2167 catch (std::exception& e) {
2168 vnThreadsRunning[4]--;
2169 PrintException(&e, "ThreadRPCServer()");
2171 vnThreadsRunning[4]--;
2172 PrintException(NULL, "ThreadRPCServer()");
2174 printf("ThreadRPCServer exiting\n");
2177 void ThreadRPCServer2(void* parg)
2179 printf("ThreadRPCServer started\n");
2181 strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"];
2182 if (strRPCUserColonPass == ":")
2184 unsigned char rand_pwd[32];
2185 RAND_bytes(rand_pwd, 32);
2186 string strWhatAmI = "To use bitcoind";
2187 if (mapArgs.count("-server"))
2188 strWhatAmI = strprintf(_("To use the %s option"), "\"-server\"");
2189 else if (mapArgs.count("-daemon"))
2190 strWhatAmI = strprintf(_("To use the %s option"), "\"-daemon\"");
2191 ThreadSafeMessageBox(strprintf(
2192 _("Error: %s, you must set a rpcpassword in the configuration file:\n %s\n"
2193 "It is recommended you use the following random password:\n"
2194 "rpcuser=bitcoinrpc\n"
2196 "(you do not need to remember this password)\n"
2197 "If the file does not exist, create it with owner-readable-only file permissions.\n"),
2199 GetConfigFile().c_str(),
2200 EncodeBase58(&rand_pwd[0],&rand_pwd[0]+32).c_str()),
2201 _("Error"), wxOK | wxMODAL);
2208 bool fUseSSL = GetBoolArg("-rpcssl");
2209 asio::ip::address bindAddress = mapArgs.count("-rpcallowip") ? asio::ip::address_v4::any() : asio::ip::address_v4::loopback();
2211 asio::io_service io_service;
2212 ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", 8332));
2214 ip::tcp::acceptor acceptor(io_service, endpoint);
2216 acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
2218 ip::tcp::acceptor acceptor(io_service);
2221 acceptor.open(endpoint.protocol());
2222 acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
2223 acceptor.bind(endpoint);
2224 acceptor.listen(socket_base::max_connections);
2226 catch(boost::system::system_error &e)
2228 ThreadSafeMessageBox(strprintf(_("An error occured while setting up the RPC port %i for listening: %s"), endpoint.port(), e.what()),
2229 _("Error"), wxOK | wxMODAL);
2236 ssl::context context(io_service, ssl::context::sslv23);
2239 context.set_options(ssl::context::no_sslv2);
2240 filesystem::path certfile = GetArg("-rpcsslcertificatechainfile", "server.cert");
2241 if (!certfile.is_complete()) certfile = filesystem::path(GetDataDir()) / certfile;
2242 if (filesystem::exists(certfile)) context.use_certificate_chain_file(certfile.string().c_str());
2243 else printf("ThreadRPCServer ERROR: missing server certificate file %s\n", certfile.string().c_str());
2244 filesystem::path pkfile = GetArg("-rpcsslprivatekeyfile", "server.pem");
2245 if (!pkfile.is_complete()) pkfile = filesystem::path(GetDataDir()) / pkfile;
2246 if (filesystem::exists(pkfile)) context.use_private_key_file(pkfile.string().c_str(), ssl::context::pem);
2247 else printf("ThreadRPCServer ERROR: missing server private key file %s\n", pkfile.string().c_str());
2249 string ciphers = GetArg("-rpcsslciphers",
2250 "TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH");
2251 SSL_CTX_set_cipher_list(context.impl(), ciphers.c_str());
2255 throw runtime_error("-rpcssl=1, but bitcoin compiled without full openssl libraries.");
2260 // Accept connection
2262 SSLStream sslStream(io_service, context);
2263 SSLIOStreamDevice d(sslStream, fUseSSL);
2264 iostreams::stream<SSLIOStreamDevice> stream(d);
2266 ip::tcp::iostream stream;
2269 ip::tcp::endpoint peer;
2270 vnThreadsRunning[4]--;
2272 acceptor.accept(sslStream.lowest_layer(), peer);
2274 acceptor.accept(*stream.rdbuf(), peer);
2276 vnThreadsRunning[4]++;
2280 // Restrict callers by IP
2281 if (!ClientAllowed(peer.address().to_string()))
2283 // Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake.
2285 stream << HTTPReply(403, "") << std::flush;
2289 map<string, string> mapHeaders;
2292 boost::thread api_caller(ReadHTTP, boost::ref(stream), boost::ref(mapHeaders), boost::ref(strRequest));
2293 if (!api_caller.timed_join(boost::posix_time::seconds(GetArg("-rpctimeout", 30))))
2296 printf("ThreadRPCServer ReadHTTP timeout\n");
2300 // Check authorization
2301 if (mapHeaders.count("authorization") == 0)
2303 stream << HTTPReply(401, "") << std::flush;
2306 if (!HTTPAuthorized(mapHeaders))
2308 printf("ThreadRPCServer incorrect password attempt from %s\n",peer.address().to_string().c_str());
2309 /* Deter brute-forcing short passwords.
2310 If this results in a DOS the user really
2311 shouldn't have their RPC port exposed.*/
2312 if (mapArgs["-rpcpassword"].size() < 20)
2315 stream << HTTPReply(401, "") << std::flush;
2319 Value id = Value::null;
2324 if (!read_string(strRequest, valRequest) || valRequest.type() != obj_type)
2325 throw JSONRPCError(-32700, "Parse error");
2326 const Object& request = valRequest.get_obj();
2328 // Parse id now so errors from here on will have the id
2329 id = find_value(request, "id");
2332 Value valMethod = find_value(request, "method");
2333 if (valMethod.type() == null_type)
2334 throw JSONRPCError(-32600, "Missing method");
2335 if (valMethod.type() != str_type)
2336 throw JSONRPCError(-32600, "Method must be a string");
2337 string strMethod = valMethod.get_str();
2338 if (strMethod != "getwork" && strMethod != "getmemorypool")
2339 printf("ThreadRPCServer method=%s\n", strMethod.c_str());
2342 Value valParams = find_value(request, "params");
2344 if (valParams.type() == array_type)
2345 params = valParams.get_array();
2346 else if (valParams.type() == null_type)
2349 throw JSONRPCError(-32600, "Params must be an array");
2352 map<string, rpcfn_type>::iterator mi = mapCallTable.find(strMethod);
2353 if (mi == mapCallTable.end())
2354 throw JSONRPCError(-32601, "Method not found");
2356 // Observe safe mode
2357 string strWarning = GetWarnings("rpc");
2358 if (strWarning != "" && !GetBoolArg("-disablesafemode") && !setAllowInSafeMode.count(strMethod))
2359 throw JSONRPCError(-2, string("Safe mode: ") + strWarning);
2365 CRITICAL_BLOCK(cs_main)
2366 CRITICAL_BLOCK(pwalletMain->cs_wallet)
2367 result = (*(*mi).second)(params, false);
2370 string strReply = JSONRPCReply(result, Value::null, id);
2371 stream << HTTPReply(200, strReply) << std::flush;
2373 catch (std::exception& e)
2375 ErrorReply(stream, JSONRPCError(-1, e.what()), id);
2378 catch (Object& objError)
2380 ErrorReply(stream, objError, id);
2382 catch (std::exception& e)
2384 ErrorReply(stream, JSONRPCError(-32700, e.what()), id);
2392 Object CallRPC(const string& strMethod, const Array& params)
2394 if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
2395 throw runtime_error(strprintf(
2396 _("You must set rpcpassword=<password> in the configuration file:\n%s\n"
2397 "If the file does not exist, create it with owner-readable-only file permissions."),
2398 GetConfigFile().c_str()));
2400 // Connect to localhost
2401 bool fUseSSL = GetBoolArg("-rpcssl");
2403 asio::io_service io_service;
2404 ssl::context context(io_service, ssl::context::sslv23);
2405 context.set_options(ssl::context::no_sslv2);
2406 SSLStream sslStream(io_service, context);
2407 SSLIOStreamDevice d(sslStream, fUseSSL);
2408 iostreams::stream<SSLIOStreamDevice> stream(d);
2409 if (!d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332")))
2410 throw runtime_error("couldn't connect to server");
2413 throw runtime_error("-rpcssl=1, but bitcoin compiled without full openssl libraries.");
2415 ip::tcp::iostream stream(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332"));
2417 throw runtime_error("couldn't connect to server");
2421 // HTTP basic authentication
2422 string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
2423 map<string, string> mapRequestHeaders;
2424 mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64;
2427 string strRequest = JSONRPCRequest(strMethod, params, 1);
2428 string strPost = HTTPPost(strRequest, mapRequestHeaders);
2429 stream << strPost << std::flush;
2432 map<string, string> mapHeaders;
2434 int nStatus = ReadHTTP(stream, mapHeaders, strReply);
2436 throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
2437 else if (nStatus >= 400 && nStatus != 400 && nStatus != 404 && nStatus != 500)
2438 throw runtime_error(strprintf("server returned HTTP error %d", nStatus));
2439 else if (strReply.empty())
2440 throw runtime_error("no response from server");
2444 if (!read_string(strReply, valReply))
2445 throw runtime_error("couldn't parse reply from server");
2446 const Object& reply = valReply.get_obj();
2448 throw runtime_error("expected reply to have result, error and id properties");
2456 template<typename T>
2457 void ConvertTo(Value& value)
2459 if (value.type() == str_type)
2461 // reinterpret string as unquoted json value
2463 if (!read_string(value.get_str(), value2))
2464 throw runtime_error("type mismatch");
2465 value = value2.get_value<T>();
2469 value = value.get_value<T>();
2473 int CommandLineRPC(int argc, char *argv[])
2480 while (argc > 1 && IsSwitchChar(argv[1][0]))
2488 throw runtime_error("too few parameters");
2489 string strMethod = argv[1];
2491 // Parameters default to strings
2493 for (int i = 2; i < argc; i++)
2494 params.push_back(argv[i]);
2495 int n = params.size();
2498 // Special case non-string parameter types
2500 if (strMethod == "setgenerate" && n > 0) ConvertTo<bool>(params[0]);
2501 if (strMethod == "setgenerate" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2502 if (strMethod == "sendtoaddress" && n > 1) ConvertTo<double>(params[1]);
2503 if (strMethod == "settxfee" && n > 0) ConvertTo<double>(params[0]);
2504 if (strMethod == "getreceivedbyaddress" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2505 if (strMethod == "getreceivedbyaccount" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2506 if (strMethod == "listreceivedbyaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2507 if (strMethod == "listreceivedbyaddress" && n > 1) ConvertTo<bool>(params[1]);
2508 if (strMethod == "listreceivedbyaccount" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2509 if (strMethod == "listreceivedbyaccount" && n > 1) ConvertTo<bool>(params[1]);
2510 if (strMethod == "getbalance" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2511 if (strMethod == "move" && n > 2) ConvertTo<double>(params[2]);
2512 if (strMethod == "move" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2513 if (strMethod == "sendfrom" && n > 2) ConvertTo<double>(params[2]);
2514 if (strMethod == "sendfrom" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2515 if (strMethod == "listtransactions" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2516 if (strMethod == "listtransactions" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2517 if (strMethod == "listaccounts" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2518 if (strMethod == "walletpassphrase" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2519 if (strMethod == "listsinceblock" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2520 if (strMethod == "sendmany" && n > 1)
2522 string s = params[1].get_str();
2524 if (!read_string(s, v) || v.type() != obj_type)
2525 throw runtime_error("type mismatch");
2526 params[1] = v.get_obj();
2528 if (strMethod == "sendmany" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2531 Object reply = CallRPC(strMethod, params);
2534 const Value& result = find_value(reply, "result");
2535 const Value& error = find_value(reply, "error");
2537 if (error.type() != null_type)
2540 strPrint = "error: " + write_string(error, false);
2541 int code = find_value(error.get_obj(), "code").get_int();
2547 if (result.type() == null_type)
2549 else if (result.type() == str_type)
2550 strPrint = result.get_str();
2552 strPrint = write_string(result, true);
2555 catch (std::exception& e)
2557 strPrint = string("error: ") + e.what();
2562 PrintException(NULL, "CommandLineRPC()");
2567 fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
2576 int main(int argc, char *argv[])
2579 // Turn off microsoft heap dump noise
2580 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
2581 _CrtSetReportFile(_CRT_WARN, CreateFile("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0));
2583 setbuf(stdin, NULL);
2584 setbuf(stdout, NULL);
2585 setbuf(stderr, NULL);
2589 if (argc >= 2 && string(argv[1]) == "-server")
2591 printf("server ready\n");
2592 ThreadRPCServer(NULL);
2596 return CommandLineRPC(argc, argv);
2599 catch (std::exception& e) {
2600 PrintException(&e, "main()");
2602 PrintException(NULL, "main()");