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 license.txt or http://www.opensource.org/licenses/mit-license.php.
7 #include "cryptopp/sha.h"
12 #include <boost/asio.hpp>
13 #include <boost/iostreams/concepts.hpp>
14 #include <boost/iostreams/stream.hpp>
15 #include <boost/algorithm/string.hpp>
17 #include <boost/asio/ssl.hpp>
18 #include <boost/filesystem.hpp>
19 #include <boost/filesystem/fstream.hpp>
20 typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> SSLStream;
22 #include "json/json_spirit_reader_template.h"
23 #include "json/json_spirit_writer_template.h"
24 #include "json/json_spirit_utils.h"
25 #define printf OutputDebugStringF
26 // MinGW 3.4.5 gets "fatal error: had to relocate PCH" if the json headers are
27 // precompiled in headers.h. The problem might be when the pch file goes over
28 // a certain size around 145MB. If we need access to json_spirit outside this
29 // file, we could use the compiled json_spirit option.
32 using namespace boost;
33 using namespace boost::asio;
34 using namespace json_spirit;
36 void ThreadRPCServer2(void* parg);
37 typedef Value(*rpcfn_type)(const Array& params, bool fHelp);
38 extern map<string, rpcfn_type> mapCallTable;
40 static int64 nWalletUnlockTime;
41 static CCriticalSection cs_nWalletUnlockTime;
44 Object JSONRPCError(int code, const string& message)
47 error.push_back(Pair("code", code));
48 error.push_back(Pair("message", message));
53 void PrintConsole(const char* format, ...)
56 int limit = sizeof(buffer);
58 va_start(arg_ptr, format);
59 int ret = _vsnprintf(buffer, limit, format, arg_ptr);
61 if (ret < 0 || ret >= limit)
67 #if defined(__WXMSW__) && defined(GUI)
68 MyMessageBox(buffer, "Bitcoin", wxOK | wxICON_EXCLAMATION);
70 fprintf(stdout, "%s", buffer);
75 int64 AmountFromValue(const Value& value)
77 double dAmount = value.get_real();
78 if (dAmount <= 0.0 || dAmount > 21000000.0)
79 throw JSONRPCError(-3, "Invalid amount");
80 int64 nAmount = roundint64(dAmount * COIN);
81 if (!MoneyRange(nAmount))
82 throw JSONRPCError(-3, "Invalid amount");
86 Value ValueFromAmount(int64 amount)
88 return (double)amount / (double)COIN;
91 void WalletTxToJSON(const CWalletTx& wtx, Object& entry)
93 entry.push_back(Pair("confirmations", wtx.GetDepthInMainChain()));
94 entry.push_back(Pair("txid", wtx.GetHash().GetHex()));
95 entry.push_back(Pair("time", (boost::int64_t)wtx.GetTxTime()));
96 BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue)
97 entry.push_back(Pair(item.first, item.second));
100 string AccountFromValue(const Value& value)
102 string strAccount = value.get_str();
103 if (strAccount == "*")
104 throw JSONRPCError(-11, "Invalid account name");
111 /// Note: This interface may still be subject to change.
115 Value help(const Array& params, bool fHelp)
117 if (fHelp || params.size() > 1)
120 "List commands, or get help for a command.");
123 if (params.size() > 0)
124 strCommand = params[0].get_str();
127 set<rpcfn_type> setDone;
128 for (map<string, rpcfn_type>::iterator mi = mapCallTable.begin(); mi != mapCallTable.end(); ++mi)
130 string strMethod = (*mi).first;
131 // We already filter duplicates, but these deprecated screw up the sort order
132 if (strMethod == "getamountreceived" ||
133 strMethod == "getallreceived" ||
134 (strMethod.find("label") != string::npos))
136 if (strCommand != "" && strMethod != strCommand)
141 rpcfn_type pfn = (*mi).second;
142 if (setDone.insert(pfn).second)
143 (*pfn)(params, true);
145 catch (std::exception& e)
147 // Help text is returned in an exception
148 string strHelp = string(e.what());
149 if (strCommand == "")
150 if (strHelp.find('\n') != string::npos)
151 strHelp = strHelp.substr(0, strHelp.find('\n'));
152 strRet += strHelp + "\n";
156 strRet = strprintf("help: unknown command: %s\n", strCommand.c_str());
157 strRet = strRet.substr(0,strRet.size()-1);
162 Value stop(const Array& params, bool fHelp)
164 if (fHelp || params.size() != 0)
167 "Stop bitcoin server.");
169 // Shutdown will take long enough that the response should get back
170 CreateThread(Shutdown, NULL);
171 return "bitcoin server stopping";
175 Value getblockcount(const Array& params, bool fHelp)
177 if (fHelp || params.size() != 0)
180 "Returns the number of blocks in the longest block chain.");
186 Value getblocknumber(const Array& params, bool fHelp)
188 if (fHelp || params.size() != 0)
191 "Returns the block number of the latest block in the longest block chain.");
197 Value getconnectioncount(const Array& params, bool fHelp)
199 if (fHelp || params.size() != 0)
201 "getconnectioncount\n"
202 "Returns the number of connections to other nodes.");
204 return (int)vNodes.size();
208 double GetDifficulty()
210 // Floating point number that is a multiple of the minimum difficulty,
211 // minimum difficulty = 1.0.
213 if (pindexBest == NULL)
215 int nShift = (pindexBest->nBits >> 24) & 0xff;
218 (double)0x0000ffff / (double)(pindexBest->nBits & 0x00ffffff);
234 Value getdifficulty(const Array& params, bool fHelp)
236 if (fHelp || params.size() != 0)
239 "Returns the proof-of-work difficulty as a multiple of the minimum difficulty.");
241 return GetDifficulty();
245 Value getgenerate(const Array& params, bool fHelp)
247 if (fHelp || params.size() != 0)
250 "Returns true or false.");
252 return (bool)fGenerateBitcoins;
256 Value setgenerate(const Array& params, bool fHelp)
258 if (fHelp || params.size() < 1 || params.size() > 2)
260 "setgenerate <generate> [genproclimit]\n"
261 "<generate> is true or false to turn generation on or off.\n"
262 "Generation is limited to [genproclimit] processors, -1 is unlimited.");
264 bool fGenerate = true;
265 if (params.size() > 0)
266 fGenerate = params[0].get_bool();
268 if (params.size() > 1)
270 int nGenProcLimit = params[1].get_int();
271 fLimitProcessors = (nGenProcLimit != -1);
272 WriteSetting("fLimitProcessors", fLimitProcessors);
273 if (nGenProcLimit != -1)
274 WriteSetting("nLimitProcessors", nLimitProcessors = nGenProcLimit);
275 if (nGenProcLimit == 0)
279 GenerateBitcoins(fGenerate, pwalletMain);
284 Value gethashespersec(const Array& params, bool fHelp)
286 if (fHelp || params.size() != 0)
289 "Returns a recent hashes per second performance measurement while generating.");
291 if (GetTimeMillis() - nHPSTimerStart > 8000)
292 return (boost::int64_t)0;
293 return (boost::int64_t)dHashesPerSec;
297 Value getinfo(const Array& params, bool fHelp)
299 if (fHelp || params.size() != 0)
302 "Returns an object containing various state info.");
305 obj.push_back(Pair("version", (int)VERSION));
306 obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance())));
307 obj.push_back(Pair("blocks", (int)nBestHeight));
308 obj.push_back(Pair("connections", (int)vNodes.size()));
309 obj.push_back(Pair("proxy", (fUseProxy ? addrProxy.ToStringIPPort() : string())));
310 obj.push_back(Pair("generate", (bool)fGenerateBitcoins));
311 obj.push_back(Pair("genproclimit", (int)(fLimitProcessors ? nLimitProcessors : -1)));
312 obj.push_back(Pair("difficulty", (double)GetDifficulty()));
313 obj.push_back(Pair("hashespersec", gethashespersec(params, false)));
314 obj.push_back(Pair("testnet", fTestNet));
315 obj.push_back(Pair("keypoololdest", (boost::int64_t)pwalletMain->GetOldestKeyPoolTime()));
316 obj.push_back(Pair("keypoolsize", pwalletMain->GetKeyPoolSize()));
317 obj.push_back(Pair("paytxfee", ValueFromAmount(nTransactionFee)));
318 if (pwalletMain->IsCrypted())
319 obj.push_back(Pair("unlocked_until", (boost::int64_t)nWalletUnlockTime / 1000));
320 obj.push_back(Pair("errors", GetWarnings("statusbar")));
325 Value getnewaddress(const Array& params, bool fHelp)
327 if (fHelp || params.size() > 1)
329 "getnewaddress [account]\n"
330 "Returns a new bitcoin address for receiving payments. "
331 "If [account] is specified (recommended), it is added to the address book "
332 "so payments received with the address will be credited to [account].");
334 // Parse the account first so we don't generate a key if there's an error
336 if (params.size() > 0)
337 strAccount = AccountFromValue(params[0]);
339 if (!pwalletMain->IsLocked())
340 pwalletMain->TopUpKeyPool();
342 // Generate a new key that is added to wallet
343 std::vector<unsigned char> newKey;
344 if (!pwalletMain->GetKeyFromPool(newKey, false))
345 throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
346 CBitcoinAddress address(newKey);
348 pwalletMain->SetAddressBookName(address, strAccount);
350 return address.ToString();
354 CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false)
356 CWalletDB walletdb(pwalletMain->strWalletFile);
359 walletdb.ReadAccount(strAccount, account);
361 bool bKeyUsed = false;
363 // Check if the current key has been used
364 if (!account.vchPubKey.empty())
366 CScript scriptPubKey;
367 scriptPubKey.SetBitcoinAddress(account.vchPubKey);
368 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
369 it != pwalletMain->mapWallet.end() && !account.vchPubKey.empty();
372 const CWalletTx& wtx = (*it).second;
373 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
374 if (txout.scriptPubKey == scriptPubKey)
379 // Generate a new key
380 if (account.vchPubKey.empty() || bForceNew || bKeyUsed)
382 if (!pwalletMain->GetKeyFromPool(account.vchPubKey, false))
383 throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
385 pwalletMain->SetAddressBookName(CBitcoinAddress(account.vchPubKey), strAccount);
386 walletdb.WriteAccount(strAccount, account);
389 return CBitcoinAddress(account.vchPubKey);
392 Value getaccountaddress(const Array& params, bool fHelp)
394 if (fHelp || params.size() != 1)
396 "getaccountaddress <account>\n"
397 "Returns the current bitcoin address for receiving payments to this account.");
399 // Parse the account first so we don't generate a key if there's an error
400 string strAccount = AccountFromValue(params[0]);
404 ret = GetAccountAddress(strAccount).ToString();
411 Value setaccount(const Array& params, bool fHelp)
413 if (fHelp || params.size() < 1 || params.size() > 2)
415 "setaccount <bitcoinaddress> <account>\n"
416 "Sets the account associated with the given address.");
418 CBitcoinAddress address(params[0].get_str());
419 if (!address.IsValid())
420 throw JSONRPCError(-5, "Invalid bitcoin address");
424 if (params.size() > 1)
425 strAccount = AccountFromValue(params[1]);
427 // Detect when changing the account of an address that is the 'unused current key' of another account:
428 if (pwalletMain->mapAddressBook.count(address))
430 string strOldAccount = pwalletMain->mapAddressBook[address];
431 if (address == GetAccountAddress(strOldAccount))
432 GetAccountAddress(strOldAccount, true);
435 pwalletMain->SetAddressBookName(address, strAccount);
441 Value getaccount(const Array& params, bool fHelp)
443 if (fHelp || params.size() != 1)
445 "getaccount <bitcoinaddress>\n"
446 "Returns the account associated with the given address.");
448 CBitcoinAddress address(params[0].get_str());
449 if (!address.IsValid())
450 throw JSONRPCError(-5, "Invalid bitcoin address");
453 map<CBitcoinAddress, string>::iterator mi = pwalletMain->mapAddressBook.find(address);
454 if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.empty())
455 strAccount = (*mi).second;
460 Value getaddressesbyaccount(const Array& params, bool fHelp)
462 if (fHelp || params.size() != 1)
464 "getaddressesbyaccount <account>\n"
465 "Returns the list of addresses for the given account.");
467 string strAccount = AccountFromValue(params[0]);
469 // Find all addresses that have the given account
471 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
473 const CBitcoinAddress& address = item.first;
474 const string& strName = item.second;
475 if (strName == strAccount)
476 ret.push_back(address.ToString());
481 Value settxfee(const Array& params, bool fHelp)
483 if (fHelp || params.size() < 1 || params.size() > 1)
485 "settxfee <amount>\n"
486 "<amount> is a real and is rounded to the nearest 0.00000001");
490 if (params[0].get_real() != 0.0)
491 nAmount = AmountFromValue(params[0]); // rejects 0.0 amounts
493 nTransactionFee = nAmount;
497 Value sendtoaddress(const Array& params, bool fHelp)
499 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
501 "sendtoaddress <bitcoinaddress> <amount> [comment] [comment-to]\n"
502 "<amount> is a real and is rounded to the nearest 0.00000001\n"
503 "requires wallet passphrase to be set with walletpassphrase first");
504 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
506 "sendtoaddress <bitcoinaddress> <amount> [comment] [comment-to]\n"
507 "<amount> is a real and is rounded to the nearest 0.00000001");
509 CBitcoinAddress address(params[0].get_str());
510 if (!address.IsValid())
511 throw JSONRPCError(-5, "Invalid bitcoin address");
514 int64 nAmount = AmountFromValue(params[1]);
518 if (params.size() > 2 && params[2].type() != null_type && !params[2].get_str().empty())
519 wtx.mapValue["comment"] = params[2].get_str();
520 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
521 wtx.mapValue["to"] = params[3].get_str();
523 if (pwalletMain->IsLocked())
524 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
526 string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
528 throw JSONRPCError(-4, strError);
530 return wtx.GetHash().GetHex();
534 Value getreceivedbyaddress(const Array& params, bool fHelp)
536 if (fHelp || params.size() < 1 || params.size() > 2)
538 "getreceivedbyaddress <bitcoinaddress> [minconf=1]\n"
539 "Returns the total amount received by <bitcoinaddress> in transactions with at least [minconf] confirmations.");
542 CBitcoinAddress address = CBitcoinAddress(params[0].get_str());
543 CScript scriptPubKey;
544 if (!address.IsValid())
545 throw JSONRPCError(-5, "Invalid bitcoin address");
546 scriptPubKey.SetBitcoinAddress(address);
547 if (!IsMine(*pwalletMain,scriptPubKey))
550 // Minimum confirmations
552 if (params.size() > 1)
553 nMinDepth = params[1].get_int();
557 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
559 const CWalletTx& wtx = (*it).second;
560 if (wtx.IsCoinBase() || !wtx.IsFinal())
563 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
564 if (txout.scriptPubKey == scriptPubKey)
565 if (wtx.GetDepthInMainChain() >= nMinDepth)
566 nAmount += txout.nValue;
569 return ValueFromAmount(nAmount);
573 void GetAccountAddresses(string strAccount, set<CBitcoinAddress>& setAddress)
575 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
577 const CBitcoinAddress& address = item.first;
578 const string& strName = item.second;
579 if (strName == strAccount)
580 setAddress.insert(address);
585 Value getreceivedbyaccount(const Array& params, bool fHelp)
587 if (fHelp || params.size() < 1 || params.size() > 2)
589 "getreceivedbyaccount <account> [minconf=1]\n"
590 "Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.");
592 // Minimum confirmations
594 if (params.size() > 1)
595 nMinDepth = params[1].get_int();
597 // Get the set of pub keys that have the label
598 string strAccount = AccountFromValue(params[0]);
599 set<CBitcoinAddress> setAddress;
600 GetAccountAddresses(strAccount, setAddress);
604 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
606 const CWalletTx& wtx = (*it).second;
607 if (wtx.IsCoinBase() || !wtx.IsFinal())
610 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
612 CBitcoinAddress address;
613 if (ExtractAddress(txout.scriptPubKey, pwalletMain, address) && setAddress.count(address))
614 if (wtx.GetDepthInMainChain() >= nMinDepth)
615 nAmount += txout.nValue;
619 return (double)nAmount / (double)COIN;
623 int64 GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth)
627 // Tally wallet transactions
628 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
630 const CWalletTx& wtx = (*it).second;
634 int64 nGenerated, nReceived, nSent, nFee;
635 wtx.GetAccountAmounts(strAccount, nGenerated, nReceived, nSent, nFee);
637 if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
638 nBalance += nReceived;
639 nBalance += nGenerated - nSent - nFee;
642 // Tally internal accounting entries
643 nBalance += walletdb.GetAccountCreditDebit(strAccount);
648 int64 GetAccountBalance(const string& strAccount, int nMinDepth)
650 CWalletDB walletdb(pwalletMain->strWalletFile);
651 return GetAccountBalance(walletdb, strAccount, nMinDepth);
655 Value getbalance(const Array& params, bool fHelp)
657 if (fHelp || params.size() > 2)
659 "getbalance [account] [minconf=1]\n"
660 "If [account] is not specified, returns the server's total available balance.\n"
661 "If [account] is specified, returns the balance in the account.");
663 if (params.size() == 0)
664 return ValueFromAmount(pwalletMain->GetBalance());
667 if (params.size() > 1)
668 nMinDepth = params[1].get_int();
670 if (params[0].get_str() == "*") {
671 // Calculate total balance a different way from GetBalance()
672 // (GetBalance() sums up all unspent TxOuts)
673 // getbalance and getbalance '*' should always return the same number.
675 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
677 const CWalletTx& wtx = (*it).second;
681 int64 allGeneratedImmature, allGeneratedMature, allFee;
682 allGeneratedImmature = allGeneratedMature = allFee = 0;
683 string strSentAccount;
684 list<pair<CBitcoinAddress, int64> > listReceived;
685 list<pair<CBitcoinAddress, int64> > listSent;
686 wtx.GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount);
687 if (wtx.GetDepthInMainChain() >= nMinDepth)
689 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listReceived)
690 nBalance += r.second;
692 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listSent)
693 nBalance -= r.second;
695 nBalance += allGeneratedMature;
697 return ValueFromAmount(nBalance);
700 string strAccount = AccountFromValue(params[0]);
702 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
704 return ValueFromAmount(nBalance);
708 Value movecmd(const Array& params, bool fHelp)
710 if (fHelp || params.size() < 3 || params.size() > 5)
712 "move <fromaccount> <toaccount> <amount> [minconf=1] [comment]\n"
713 "Move from one account in your wallet to another.");
715 string strFrom = AccountFromValue(params[0]);
716 string strTo = AccountFromValue(params[1]);
717 int64 nAmount = AmountFromValue(params[2]);
718 if (params.size() > 3)
719 // unused parameter, used to be nMinDepth, keep type-checking it though
720 (void)params[3].get_int();
722 if (params.size() > 4)
723 strComment = params[4].get_str();
725 CWalletDB walletdb(pwalletMain->strWalletFile);
726 if (!walletdb.TxnBegin())
727 throw JSONRPCError(-20, "database error");
729 int64 nNow = GetAdjustedTime();
732 CAccountingEntry debit;
733 debit.strAccount = strFrom;
734 debit.nCreditDebit = -nAmount;
736 debit.strOtherAccount = strTo;
737 debit.strComment = strComment;
738 walletdb.WriteAccountingEntry(debit);
741 CAccountingEntry credit;
742 credit.strAccount = strTo;
743 credit.nCreditDebit = nAmount;
745 credit.strOtherAccount = strFrom;
746 credit.strComment = strComment;
747 walletdb.WriteAccountingEntry(credit);
749 if (!walletdb.TxnCommit())
750 throw JSONRPCError(-20, "database error");
756 Value sendfrom(const Array& params, bool fHelp)
758 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
760 "sendfrom <fromaccount> <tobitcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
761 "<amount> is a real and is rounded to the nearest 0.00000001\n"
762 "requires wallet passphrase to be set with walletpassphrase first");
763 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
765 "sendfrom <fromaccount> <tobitcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
766 "<amount> is a real and is rounded to the nearest 0.00000001");
768 string strAccount = AccountFromValue(params[0]);
769 CBitcoinAddress address(params[1].get_str());
770 if (!address.IsValid())
771 throw JSONRPCError(-5, "Invalid bitcoin address");
772 int64 nAmount = AmountFromValue(params[2]);
774 if (params.size() > 3)
775 nMinDepth = params[3].get_int();
778 wtx.strFromAccount = strAccount;
779 if (params.size() > 4 && params[4].type() != null_type && !params[4].get_str().empty())
780 wtx.mapValue["comment"] = params[4].get_str();
781 if (params.size() > 5 && params[5].type() != null_type && !params[5].get_str().empty())
782 wtx.mapValue["to"] = params[5].get_str();
784 if (pwalletMain->IsLocked())
785 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
788 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
789 if (nAmount > nBalance)
790 throw JSONRPCError(-6, "Account has insufficient funds");
793 string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
795 throw JSONRPCError(-4, strError);
797 return wtx.GetHash().GetHex();
801 Value sendmany(const Array& params, bool fHelp)
803 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
805 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
806 "amounts are double-precision floating point numbers\n"
807 "requires wallet passphrase to be set with walletpassphrase first");
808 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
810 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
811 "amounts are double-precision floating point numbers");
813 string strAccount = AccountFromValue(params[0]);
814 Object sendTo = params[1].get_obj();
816 if (params.size() > 2)
817 nMinDepth = params[2].get_int();
820 wtx.strFromAccount = strAccount;
821 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
822 wtx.mapValue["comment"] = params[3].get_str();
824 set<CBitcoinAddress> setAddress;
825 vector<pair<CScript, int64> > vecSend;
827 int64 totalAmount = 0;
828 BOOST_FOREACH(const Pair& s, sendTo)
830 CBitcoinAddress address(s.name_);
831 if (!address.IsValid())
832 throw JSONRPCError(-5, string("Invalid bitcoin address:")+s.name_);
834 if (setAddress.count(address))
835 throw JSONRPCError(-8, string("Invalid parameter, duplicated address: ")+s.name_);
836 setAddress.insert(address);
838 CScript scriptPubKey;
839 scriptPubKey.SetBitcoinAddress(address);
840 int64 nAmount = AmountFromValue(s.value_);
841 totalAmount += nAmount;
843 vecSend.push_back(make_pair(scriptPubKey, nAmount));
846 if (pwalletMain->IsLocked())
847 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
850 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
851 if (totalAmount > nBalance)
852 throw JSONRPCError(-6, "Account has insufficient funds");
855 CReserveKey keyChange(pwalletMain);
856 int64 nFeeRequired = 0;
857 bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired);
860 if (totalAmount + nFeeRequired > pwalletMain->GetBalance())
861 throw JSONRPCError(-6, "Insufficient funds");
862 throw JSONRPCError(-4, "Transaction creation failed");
864 if (!pwalletMain->CommitTransaction(wtx, keyChange))
865 throw JSONRPCError(-4, "Transaction commit failed");
867 return wtx.GetHash().GetHex();
882 Value ListReceived(const Array& params, bool fByAccounts)
884 // Minimum confirmations
886 if (params.size() > 0)
887 nMinDepth = params[0].get_int();
889 // Whether to include empty accounts
890 bool fIncludeEmpty = false;
891 if (params.size() > 1)
892 fIncludeEmpty = params[1].get_bool();
895 map<CBitcoinAddress, tallyitem> mapTally;
896 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
898 const CWalletTx& wtx = (*it).second;
899 if (wtx.IsCoinBase() || !wtx.IsFinal())
902 int nDepth = wtx.GetDepthInMainChain();
903 if (nDepth < nMinDepth)
906 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
908 CBitcoinAddress address;
909 if (!ExtractAddress(txout.scriptPubKey, pwalletMain, address) || !address.IsValid())
912 tallyitem& item = mapTally[address];
913 item.nAmount += txout.nValue;
914 item.nConf = min(item.nConf, nDepth);
920 map<string, tallyitem> mapAccountTally;
921 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
923 const CBitcoinAddress& address = item.first;
924 const string& strAccount = item.second;
925 map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
926 if (it == mapTally.end() && !fIncludeEmpty)
931 if (it != mapTally.end())
933 nAmount = (*it).second.nAmount;
934 nConf = (*it).second.nConf;
939 tallyitem& item = mapAccountTally[strAccount];
940 item.nAmount += nAmount;
941 item.nConf = min(item.nConf, nConf);
946 obj.push_back(Pair("address", address.ToString()));
947 obj.push_back(Pair("account", strAccount));
948 obj.push_back(Pair("label", strAccount)); // deprecated
949 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
950 obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf)));
957 for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
959 int64 nAmount = (*it).second.nAmount;
960 int nConf = (*it).second.nConf;
962 obj.push_back(Pair("account", (*it).first));
963 obj.push_back(Pair("label", (*it).first)); // deprecated
964 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
965 obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf)));
973 Value listreceivedbyaddress(const Array& params, bool fHelp)
975 if (fHelp || params.size() > 2)
977 "listreceivedbyaddress [minconf=1] [includeempty=false]\n"
978 "[minconf] is the minimum number of confirmations before payments are included.\n"
979 "[includeempty] whether to include addresses that haven't received any payments.\n"
980 "Returns an array of objects containing:\n"
981 " \"address\" : receiving address\n"
982 " \"account\" : the account of the receiving address\n"
983 " \"amount\" : total amount received by the address\n"
984 " \"confirmations\" : number of confirmations of the most recent transaction included");
986 return ListReceived(params, false);
989 Value listreceivedbyaccount(const Array& params, bool fHelp)
991 if (fHelp || params.size() > 2)
993 "listreceivedbyaccount [minconf=1] [includeempty=false]\n"
994 "[minconf] is the minimum number of confirmations before payments are included.\n"
995 "[includeempty] whether to include accounts that haven't received any payments.\n"
996 "Returns an array of objects containing:\n"
997 " \"account\" : the account of the receiving addresses\n"
998 " \"amount\" : total amount received by addresses with this account\n"
999 " \"confirmations\" : number of confirmations of the most recent transaction included");
1001 return ListReceived(params, true);
1004 void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret)
1006 int64 nGeneratedImmature, nGeneratedMature, nFee;
1007 string strSentAccount;
1008 list<pair<CBitcoinAddress, int64> > listReceived;
1009 list<pair<CBitcoinAddress, int64> > listSent;
1010 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1012 bool fAllAccounts = (strAccount == string("*"));
1014 // Generated blocks assigned to account ""
1015 if ((nGeneratedMature+nGeneratedImmature) != 0 && (fAllAccounts || strAccount == ""))
1018 entry.push_back(Pair("account", string("")));
1019 if (nGeneratedImmature)
1021 entry.push_back(Pair("category", wtx.GetDepthInMainChain() ? "immature" : "orphan"));
1022 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedImmature)));
1026 entry.push_back(Pair("category", "generate"));
1027 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedMature)));
1030 WalletTxToJSON(wtx, entry);
1031 ret.push_back(entry);
1035 if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
1037 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1040 entry.push_back(Pair("account", strSentAccount));
1041 entry.push_back(Pair("address", s.first.ToString()));
1042 entry.push_back(Pair("category", "send"));
1043 entry.push_back(Pair("amount", ValueFromAmount(-s.second)));
1044 entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
1046 WalletTxToJSON(wtx, entry);
1047 ret.push_back(entry);
1052 if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
1054 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1057 if (pwalletMain->mapAddressBook.count(r.first))
1058 account = pwalletMain->mapAddressBook[r.first];
1059 if (fAllAccounts || (account == strAccount))
1062 entry.push_back(Pair("account", account));
1063 entry.push_back(Pair("address", r.first.ToString()));
1064 entry.push_back(Pair("category", "receive"));
1065 entry.push_back(Pair("amount", ValueFromAmount(r.second)));
1067 WalletTxToJSON(wtx, entry);
1068 ret.push_back(entry);
1074 void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret)
1076 bool fAllAccounts = (strAccount == string("*"));
1078 if (fAllAccounts || acentry.strAccount == strAccount)
1081 entry.push_back(Pair("account", acentry.strAccount));
1082 entry.push_back(Pair("category", "move"));
1083 entry.push_back(Pair("time", (boost::int64_t)acentry.nTime));
1084 entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
1085 entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
1086 entry.push_back(Pair("comment", acentry.strComment));
1087 ret.push_back(entry);
1091 Value listtransactions(const Array& params, bool fHelp)
1093 if (fHelp || params.size() > 3)
1094 throw runtime_error(
1095 "listtransactions [account] [count=10] [from=0]\n"
1096 "Returns up to [count] most recent transactions skipping the first [from] transactions for account [account].");
1098 string strAccount = "*";
1099 if (params.size() > 0)
1100 strAccount = params[0].get_str();
1102 if (params.size() > 1)
1103 nCount = params[1].get_int();
1105 if (params.size() > 2)
1106 nFrom = params[2].get_int();
1109 throw JSONRPCError(-8, "Negative count");
1111 throw JSONRPCError(-8, "Negative from");
1114 CWalletDB walletdb(pwalletMain->strWalletFile);
1116 // First: get all CWalletTx and CAccountingEntry into a sorted-by-time multimap.
1117 typedef pair<CWalletTx*, CAccountingEntry*> TxPair;
1118 typedef multimap<int64, TxPair > TxItems;
1121 // Note: maintaining indices in the database of (account,time) --> txid and (account, time) --> acentry
1122 // would make this much faster for applications that do this a lot.
1123 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1125 CWalletTx* wtx = &((*it).second);
1126 txByTime.insert(make_pair(wtx->GetTxTime(), TxPair(wtx, (CAccountingEntry*)0)));
1128 list<CAccountingEntry> acentries;
1129 walletdb.ListAccountCreditDebit(strAccount, acentries);
1130 BOOST_FOREACH(CAccountingEntry& entry, acentries)
1132 txByTime.insert(make_pair(entry.nTime, TxPair((CWalletTx*)0, &entry)));
1135 // iterate backwards until we have nCount items to return:
1136 for (TxItems::reverse_iterator it = txByTime.rbegin(); it != txByTime.rend(); ++it)
1138 CWalletTx *const pwtx = (*it).second.first;
1140 ListTransactions(*pwtx, strAccount, 0, true, ret);
1141 CAccountingEntry *const pacentry = (*it).second.second;
1143 AcentryToJSON(*pacentry, strAccount, ret);
1145 if (ret.size() >= (nCount+nFrom)) break;
1147 // ret is newest to oldest
1149 if (nFrom > ret.size()) nFrom = ret.size();
1150 if (nFrom+nCount > ret.size()) nCount = ret.size()-nFrom;
1151 Array::iterator first = ret.begin();
1152 std::advance(first, nFrom);
1153 Array::iterator last = ret.begin();
1154 std::advance(last, nFrom+nCount);
1156 if (last != ret.end()) ret.erase(last, ret.end());
1157 if (first != ret.begin()) ret.erase(ret.begin(), first);
1159 std::reverse(ret.begin(), ret.end()); // Return oldest to newest
1164 Value listaccounts(const Array& params, bool fHelp)
1166 if (fHelp || params.size() > 1)
1167 throw runtime_error(
1168 "listaccounts [minconf=1]\n"
1169 "Returns Object that has account names as keys, account balances as values.");
1172 if (params.size() > 0)
1173 nMinDepth = params[0].get_int();
1175 map<string, int64> mapAccountBalances;
1176 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& entry, pwalletMain->mapAddressBook) {
1177 if (pwalletMain->HaveKey(entry.first)) // This address belongs to me
1178 mapAccountBalances[entry.second] = 0;
1181 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1183 const CWalletTx& wtx = (*it).second;
1184 int64 nGeneratedImmature, nGeneratedMature, nFee;
1185 string strSentAccount;
1186 list<pair<CBitcoinAddress, int64> > listReceived;
1187 list<pair<CBitcoinAddress, int64> > listSent;
1188 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1189 mapAccountBalances[strSentAccount] -= nFee;
1190 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1191 mapAccountBalances[strSentAccount] -= s.second;
1192 if (wtx.GetDepthInMainChain() >= nMinDepth)
1194 mapAccountBalances[""] += nGeneratedMature;
1195 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1196 if (pwalletMain->mapAddressBook.count(r.first))
1197 mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second;
1199 mapAccountBalances[""] += r.second;
1203 list<CAccountingEntry> acentries;
1204 CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
1205 BOOST_FOREACH(const CAccountingEntry& entry, acentries)
1206 mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
1209 BOOST_FOREACH(const PAIRTYPE(string, int64)& accountBalance, mapAccountBalances) {
1210 ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
1215 Value gettransaction(const Array& params, bool fHelp)
1217 if (fHelp || params.size() != 1)
1218 throw runtime_error(
1219 "gettransaction <txid>\n"
1220 "Get detailed information about <txid>");
1223 hash.SetHex(params[0].get_str());
1227 if (!pwalletMain->mapWallet.count(hash))
1228 throw JSONRPCError(-5, "Invalid or non-wallet transaction id");
1229 const CWalletTx& wtx = pwalletMain->mapWallet[hash];
1231 int64 nCredit = wtx.GetCredit();
1232 int64 nDebit = wtx.GetDebit();
1233 int64 nNet = nCredit - nDebit;
1234 int64 nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0);
1236 entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
1238 entry.push_back(Pair("fee", ValueFromAmount(nFee)));
1240 WalletTxToJSON(pwalletMain->mapWallet[hash], entry);
1243 ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details);
1244 entry.push_back(Pair("details", details));
1250 Value backupwallet(const Array& params, bool fHelp)
1252 if (fHelp || params.size() != 1)
1253 throw runtime_error(
1254 "backupwallet <destination>\n"
1255 "Safely copies wallet.dat to destination, which can be a directory or a path with filename.");
1257 string strDest = params[0].get_str();
1258 BackupWallet(*pwalletMain, strDest);
1264 Value keypoolrefill(const Array& params, bool fHelp)
1266 if (pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1267 throw runtime_error(
1269 "Fills the keypool, requires wallet passphrase to be set.");
1270 if (!pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1271 throw runtime_error(
1273 "Fills the keypool.");
1275 if (pwalletMain->IsLocked())
1276 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
1278 pwalletMain->TopUpKeyPool();
1280 if (pwalletMain->GetKeyPoolSize() < GetArg("-keypool", 100))
1281 throw JSONRPCError(-4, "Error refreshing keypool.");
1287 void ThreadTopUpKeyPool(void* parg)
1289 pwalletMain->TopUpKeyPool();
1292 void ThreadCleanWalletPassphrase(void* parg)
1294 int64 nMyWakeTime = GetTimeMillis() + *((int64*)parg) * 1000;
1296 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1298 if (nWalletUnlockTime == 0)
1300 nWalletUnlockTime = nMyWakeTime;
1304 if (nWalletUnlockTime==0)
1306 int64 nToSleep = nWalletUnlockTime - GetTimeMillis();
1310 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1312 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1316 if (nWalletUnlockTime)
1318 nWalletUnlockTime = 0;
1319 pwalletMain->Lock();
1324 if (nWalletUnlockTime < nMyWakeTime)
1325 nWalletUnlockTime = nMyWakeTime;
1328 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1330 delete (int64*)parg;
1333 Value walletpassphrase(const Array& params, bool fHelp)
1335 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1336 throw runtime_error(
1337 "walletpassphrase <passphrase> <timeout>\n"
1338 "Stores the wallet decryption key in memory for <timeout> seconds.");
1341 if (!pwalletMain->IsCrypted())
1342 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
1344 if (!pwalletMain->IsLocked())
1345 throw JSONRPCError(-17, "Error: Wallet is already unlocked.");
1347 // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
1348 string strWalletPass;
1349 strWalletPass.reserve(100);
1350 mlock(&strWalletPass[0], strWalletPass.capacity());
1351 strWalletPass = params[0].get_str();
1353 if (strWalletPass.length() > 0)
1355 if (!pwalletMain->Unlock(strWalletPass))
1357 fill(strWalletPass.begin(), strWalletPass.end(), '\0');
1358 munlock(&strWalletPass[0], strWalletPass.capacity());
1359 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1361 fill(strWalletPass.begin(), strWalletPass.end(), '\0');
1362 munlock(&strWalletPass[0], strWalletPass.capacity());
1365 throw runtime_error(
1366 "walletpassphrase <passphrase> <timeout>\n"
1367 "Stores the wallet decryption key in memory for <timeout> seconds.");
1369 CreateThread(ThreadTopUpKeyPool, NULL);
1370 int64* pnSleepTime = new int64(params[1].get_int64());
1371 CreateThread(ThreadCleanWalletPassphrase, pnSleepTime);
1377 Value walletpassphrasechange(const Array& params, bool fHelp)
1379 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1380 throw runtime_error(
1381 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1382 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1385 if (!pwalletMain->IsCrypted())
1386 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
1388 string strOldWalletPass;
1389 strOldWalletPass.reserve(100);
1390 mlock(&strOldWalletPass[0], strOldWalletPass.capacity());
1391 strOldWalletPass = params[0].get_str();
1393 string strNewWalletPass;
1394 strNewWalletPass.reserve(100);
1395 mlock(&strNewWalletPass[0], strNewWalletPass.capacity());
1396 strNewWalletPass = params[1].get_str();
1398 if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
1399 throw runtime_error(
1400 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1401 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1403 if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
1405 fill(strOldWalletPass.begin(), strOldWalletPass.end(), '\0');
1406 fill(strNewWalletPass.begin(), strNewWalletPass.end(), '\0');
1407 munlock(&strOldWalletPass[0], strOldWalletPass.capacity());
1408 munlock(&strNewWalletPass[0], strNewWalletPass.capacity());
1409 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1411 fill(strNewWalletPass.begin(), strNewWalletPass.end(), '\0');
1412 fill(strOldWalletPass.begin(), strOldWalletPass.end(), '\0');
1413 munlock(&strOldWalletPass[0], strOldWalletPass.capacity());
1414 munlock(&strNewWalletPass[0], strNewWalletPass.capacity());
1420 Value walletlock(const Array& params, bool fHelp)
1422 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
1423 throw runtime_error(
1425 "Removes the wallet encryption key from memory, locking the wallet.\n"
1426 "After calling this method, you will need to call walletpassphrase again\n"
1427 "before being able to call any methods which require the wallet to be unlocked.");
1430 if (!pwalletMain->IsCrypted())
1431 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletlock was called.");
1433 CRITICAL_BLOCK(cs_nWalletUnlockTime)
1435 pwalletMain->Lock();
1436 nWalletUnlockTime = 0;
1443 Value encryptwallet(const Array& params, bool fHelp)
1445 if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
1446 throw runtime_error(
1447 "encryptwallet <passphrase>\n"
1448 "Encrypts the wallet with <passphrase>.");
1451 if (pwalletMain->IsCrypted())
1452 throw JSONRPCError(-15, "Error: running with an encrypted wallet, but encryptwallet was called.");
1455 // shutting down via RPC while the GUI is running does not work (yet):
1456 throw runtime_error("Not Yet Implemented: use GUI to encrypt wallet, not RPC command");
1459 string strWalletPass;
1460 strWalletPass.reserve(100);
1461 mlock(&strWalletPass[0], strWalletPass.capacity());
1462 strWalletPass = params[0].get_str();
1464 if (strWalletPass.length() < 1)
1465 throw runtime_error(
1466 "encryptwallet <passphrase>\n"
1467 "Encrypts the wallet with <passphrase>.");
1469 if (!pwalletMain->EncryptWallet(strWalletPass))
1471 fill(strWalletPass.begin(), strWalletPass.end(), '\0');
1472 munlock(&strWalletPass[0], strWalletPass.capacity());
1473 throw JSONRPCError(-16, "Error: Failed to encrypt the wallet.");
1475 fill(strWalletPass.begin(), strWalletPass.end(), '\0');
1476 munlock(&strWalletPass[0], strWalletPass.capacity());
1478 // BDB seems to have a bad habit of writing old data into
1479 // slack space in .dat files; that is bad if the old data is
1480 // unencrypted private keys. So:
1481 CreateThread(Shutdown, NULL);
1482 return "wallet encrypted; bitcoin server stopping, restart to run with encrypted wallet";
1486 Value validateaddress(const Array& params, bool fHelp)
1488 if (fHelp || params.size() != 1)
1489 throw runtime_error(
1490 "validateaddress <bitcoinaddress>\n"
1491 "Return information about <bitcoinaddress>.");
1493 CBitcoinAddress address(params[0].get_str());
1494 bool isValid = address.IsValid();
1497 ret.push_back(Pair("isvalid", isValid));
1500 // Call Hash160ToAddress() so we always return current ADDRESSVERSION
1501 // version of the address:
1502 string currentAddress = address.ToString();
1503 ret.push_back(Pair("address", currentAddress));
1504 ret.push_back(Pair("ismine", (pwalletMain->HaveKey(address) > 0)));
1505 if (pwalletMain->mapAddressBook.count(address))
1506 ret.push_back(Pair("account", pwalletMain->mapAddressBook[address]));
1512 Value getwork(const Array& params, bool fHelp)
1514 if (fHelp || params.size() > 1)
1515 throw runtime_error(
1517 "If [data] is not specified, returns formatted hash data to work on:\n"
1518 " \"midstate\" : precomputed hash state after hashing the first half of the data\n"
1519 " \"data\" : block data\n"
1520 " \"hash1\" : formatted hash buffer for second hash\n"
1521 " \"target\" : little endian hash target\n"
1522 "If [data] is specified, tries to solve the block and returns true if it was successful.");
1525 throw JSONRPCError(-9, "Bitcoin is not connected!");
1527 if (IsInitialBlockDownload())
1528 throw JSONRPCError(-10, "Bitcoin is downloading blocks...");
1530 typedef map<uint256, pair<CBlock*, CScript> > mapNewBlock_t;
1531 static mapNewBlock_t mapNewBlock;
1532 static vector<CBlock*> vNewBlock;
1533 static CReserveKey reservekey(pwalletMain);
1535 if (params.size() == 0)
1538 static unsigned int nTransactionsUpdatedLast;
1539 static CBlockIndex* pindexPrev;
1540 static int64 nStart;
1541 static CBlock* pblock;
1542 if (pindexPrev != pindexBest ||
1543 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60))
1545 if (pindexPrev != pindexBest)
1547 // Deallocate old blocks since they're obsolete now
1548 mapNewBlock.clear();
1549 BOOST_FOREACH(CBlock* pblock, vNewBlock)
1553 nTransactionsUpdatedLast = nTransactionsUpdated;
1554 pindexPrev = pindexBest;
1558 pblock = CreateNewBlock(reservekey);
1560 throw JSONRPCError(-7, "Out of memory");
1561 vNewBlock.push_back(pblock);
1565 pblock->UpdateTime(pindexPrev);
1568 // Update nExtraNonce
1569 static unsigned int nExtraNonce = 0;
1570 IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
1573 mapNewBlock[pblock->hashMerkleRoot] = make_pair(pblock, pblock->vtx[0].vin[0].scriptSig);
1575 // Prebuild hash buffers
1579 FormatHashBuffers(pblock, pmidstate, pdata, phash1);
1581 uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
1584 result.push_back(Pair("midstate", HexStr(BEGIN(pmidstate), END(pmidstate))));
1585 result.push_back(Pair("data", HexStr(BEGIN(pdata), END(pdata))));
1586 result.push_back(Pair("hash1", HexStr(BEGIN(phash1), END(phash1))));
1587 result.push_back(Pair("target", HexStr(BEGIN(hashTarget), END(hashTarget))));
1593 vector<unsigned char> vchData = ParseHex(params[0].get_str());
1594 if (vchData.size() != 128)
1595 throw JSONRPCError(-8, "Invalid parameter");
1596 CBlock* pdata = (CBlock*)&vchData[0];
1599 for (int i = 0; i < 128/4; i++)
1600 ((unsigned int*)pdata)[i] = CryptoPP::ByteReverse(((unsigned int*)pdata)[i]);
1603 if (!mapNewBlock.count(pdata->hashMerkleRoot))
1605 CBlock* pblock = mapNewBlock[pdata->hashMerkleRoot].first;
1607 pblock->nTime = pdata->nTime;
1608 pblock->nNonce = pdata->nNonce;
1609 pblock->vtx[0].vin[0].scriptSig = mapNewBlock[pdata->hashMerkleRoot].second;
1610 pblock->hashMerkleRoot = pblock->BuildMerkleTree();
1612 return CheckWork(pblock, *pwalletMain, reservekey);
1630 pair<string, rpcfn_type> pCallTable[] =
1632 make_pair("help", &help),
1633 make_pair("stop", &stop),
1634 make_pair("getblockcount", &getblockcount),
1635 make_pair("getblocknumber", &getblocknumber),
1636 make_pair("getconnectioncount", &getconnectioncount),
1637 make_pair("getdifficulty", &getdifficulty),
1638 make_pair("getgenerate", &getgenerate),
1639 make_pair("setgenerate", &setgenerate),
1640 make_pair("gethashespersec", &gethashespersec),
1641 make_pair("getinfo", &getinfo),
1642 make_pair("getnewaddress", &getnewaddress),
1643 make_pair("getaccountaddress", &getaccountaddress),
1644 make_pair("setaccount", &setaccount),
1645 make_pair("setlabel", &setaccount), // deprecated
1646 make_pair("getaccount", &getaccount),
1647 make_pair("getlabel", &getaccount), // deprecated
1648 make_pair("getaddressesbyaccount", &getaddressesbyaccount),
1649 make_pair("getaddressesbylabel", &getaddressesbyaccount), // deprecated
1650 make_pair("sendtoaddress", &sendtoaddress),
1651 make_pair("getamountreceived", &getreceivedbyaddress), // deprecated, renamed to getreceivedbyaddress
1652 make_pair("getallreceived", &listreceivedbyaddress), // deprecated, renamed to listreceivedbyaddress
1653 make_pair("getreceivedbyaddress", &getreceivedbyaddress),
1654 make_pair("getreceivedbyaccount", &getreceivedbyaccount),
1655 make_pair("getreceivedbylabel", &getreceivedbyaccount), // deprecated
1656 make_pair("listreceivedbyaddress", &listreceivedbyaddress),
1657 make_pair("listreceivedbyaccount", &listreceivedbyaccount),
1658 make_pair("listreceivedbylabel", &listreceivedbyaccount), // deprecated
1659 make_pair("backupwallet", &backupwallet),
1660 make_pair("keypoolrefill", &keypoolrefill),
1661 make_pair("walletpassphrase", &walletpassphrase),
1662 make_pair("walletpassphrasechange", &walletpassphrasechange),
1663 make_pair("walletlock", &walletlock),
1664 make_pair("encryptwallet", &encryptwallet),
1665 make_pair("validateaddress", &validateaddress),
1666 make_pair("getbalance", &getbalance),
1667 make_pair("move", &movecmd),
1668 make_pair("sendfrom", &sendfrom),
1669 make_pair("sendmany", &sendmany),
1670 make_pair("gettransaction", &gettransaction),
1671 make_pair("listtransactions", &listtransactions),
1672 make_pair("getwork", &getwork),
1673 make_pair("listaccounts", &listaccounts),
1674 make_pair("settxfee", &settxfee),
1676 map<string, rpcfn_type> mapCallTable(pCallTable, pCallTable + sizeof(pCallTable)/sizeof(pCallTable[0]));
1678 string pAllowInSafeMode[] =
1684 "getconnectioncount",
1691 "getaccountaddress",
1692 "setlabel", // deprecated
1694 "getlabel", // deprecated
1695 "getaddressesbyaccount",
1696 "getaddressesbylabel", // deprecated
1704 set<string> setAllowInSafeMode(pAllowInSafeMode, pAllowInSafeMode + sizeof(pAllowInSafeMode)/sizeof(pAllowInSafeMode[0]));
1712 // This ain't Apache. We're just using HTTP header for the length field
1713 // and to be compatible with other JSON-RPC implementations.
1716 string HTTPPost(const string& strMsg, const map<string,string>& mapRequestHeaders)
1719 s << "POST / HTTP/1.1\r\n"
1720 << "User-Agent: bitcoin-json-rpc/" << FormatFullVersion() << "\r\n"
1721 << "Host: 127.0.0.1\r\n"
1722 << "Content-Type: application/json\r\n"
1723 << "Content-Length: " << strMsg.size() << "\r\n"
1724 << "Accept: application/json\r\n";
1725 BOOST_FOREACH(const PAIRTYPE(string, string)& item, mapRequestHeaders)
1726 s << item.first << ": " << item.second << "\r\n";
1727 s << "\r\n" << strMsg;
1732 string rfc1123Time()
1737 struct tm* now_gmt = gmtime(&now);
1738 string locale(setlocale(LC_TIME, NULL));
1739 setlocale(LC_TIME, "C"); // we want posix (aka "C") weekday/month strings
1740 strftime(buffer, sizeof(buffer), "%a, %d %b %Y %H:%M:%S +0000", now_gmt);
1741 setlocale(LC_TIME, locale.c_str());
1742 return string(buffer);
1745 static string HTTPReply(int nStatus, const string& strMsg)
1748 return strprintf("HTTP/1.0 401 Authorization Required\r\n"
1750 "Server: bitcoin-json-rpc/%s\r\n"
1751 "WWW-Authenticate: Basic realm=\"jsonrpc\"\r\n"
1752 "Content-Type: text/html\r\n"
1753 "Content-Length: 296\r\n"
1755 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\r\n"
1756 "\"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd\">\r\n"
1759 "<TITLE>Error</TITLE>\r\n"
1760 "<META HTTP-EQUIV='Content-Type' CONTENT='text/html; charset=ISO-8859-1'>\r\n"
1762 "<BODY><H1>401 Unauthorized.</H1></BODY>\r\n"
1763 "</HTML>\r\n", rfc1123Time().c_str(), FormatFullVersion().c_str());
1765 if (nStatus == 200) strStatus = "OK";
1766 else if (nStatus == 400) strStatus = "Bad Request";
1767 else if (nStatus == 403) strStatus = "Forbidden";
1768 else if (nStatus == 404) strStatus = "Not Found";
1769 else if (nStatus == 500) strStatus = "Internal Server Error";
1771 "HTTP/1.1 %d %s\r\n"
1773 "Connection: close\r\n"
1774 "Content-Length: %d\r\n"
1775 "Content-Type: application/json\r\n"
1776 "Server: bitcoin-json-rpc/%s\r\n"
1781 rfc1123Time().c_str(),
1783 FormatFullVersion().c_str(),
1787 int ReadHTTPStatus(std::basic_istream<char>& stream)
1790 getline(stream, str);
1791 vector<string> vWords;
1792 boost::split(vWords, str, boost::is_any_of(" "));
1793 if (vWords.size() < 2)
1795 return atoi(vWords[1].c_str());
1798 int ReadHTTPHeader(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet)
1804 std::getline(stream, str);
1805 if (str.empty() || str == "\r")
1807 string::size_type nColon = str.find(":");
1808 if (nColon != string::npos)
1810 string strHeader = str.substr(0, nColon);
1811 boost::trim(strHeader);
1812 boost::to_lower(strHeader);
1813 string strValue = str.substr(nColon+1);
1814 boost::trim(strValue);
1815 mapHeadersRet[strHeader] = strValue;
1816 if (strHeader == "content-length")
1817 nLen = atoi(strValue.c_str());
1823 int ReadHTTP(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet, string& strMessageRet)
1825 mapHeadersRet.clear();
1829 int nStatus = ReadHTTPStatus(stream);
1832 int nLen = ReadHTTPHeader(stream, mapHeadersRet);
1833 if (nLen < 0 || nLen > MAX_SIZE)
1839 vector<char> vch(nLen);
1840 stream.read(&vch[0], nLen);
1841 strMessageRet = string(vch.begin(), vch.end());
1847 string EncodeBase64(string s)
1852 b64 = BIO_new(BIO_f_base64());
1853 BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
1854 bmem = BIO_new(BIO_s_mem());
1855 b64 = BIO_push(b64, bmem);
1856 BIO_write(b64, s.c_str(), s.size());
1858 BIO_get_mem_ptr(b64, &bptr);
1860 string result(bptr->data, bptr->length);
1866 string DecodeBase64(string s)
1870 char* buffer = static_cast<char*>(calloc(s.size(), sizeof(char)));
1872 b64 = BIO_new(BIO_f_base64());
1873 BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
1874 bmem = BIO_new_mem_buf(const_cast<char*>(s.c_str()), s.size());
1875 bmem = BIO_push(b64, bmem);
1876 BIO_read(bmem, buffer, s.size());
1879 string result(buffer);
1884 bool HTTPAuthorized(map<string, string>& mapHeaders)
1886 string strAuth = mapHeaders["authorization"];
1887 if (strAuth.substr(0,6) != "Basic ")
1889 string strUserPass64 = strAuth.substr(6); boost::trim(strUserPass64);
1890 string strUserPass = DecodeBase64(strUserPass64);
1891 string::size_type nColon = strUserPass.find(":");
1892 if (nColon == string::npos)
1894 string strUser = strUserPass.substr(0, nColon);
1895 string strPassword = strUserPass.substr(nColon+1);
1896 return (strUser == mapArgs["-rpcuser"] && strPassword == mapArgs["-rpcpassword"]);
1900 // JSON-RPC protocol. Bitcoin speaks version 1.0 for maximum compatibility,
1901 // but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
1902 // unspecified (HTTP errors and contents of 'error').
1904 // 1.0 spec: http://json-rpc.org/wiki/specification
1905 // 1.2 spec: http://groups.google.com/group/json-rpc/web/json-rpc-over-http
1906 // http://www.codeproject.com/KB/recipes/JSON_Spirit.aspx
1909 string JSONRPCRequest(const string& strMethod, const Array& params, const Value& id)
1912 request.push_back(Pair("method", strMethod));
1913 request.push_back(Pair("params", params));
1914 request.push_back(Pair("id", id));
1915 return write_string(Value(request), false) + "\n";
1918 string JSONRPCReply(const Value& result, const Value& error, const Value& id)
1921 if (error.type() != null_type)
1922 reply.push_back(Pair("result", Value::null));
1924 reply.push_back(Pair("result", result));
1925 reply.push_back(Pair("error", error));
1926 reply.push_back(Pair("id", id));
1927 return write_string(Value(reply), false) + "\n";
1930 void ErrorReply(std::ostream& stream, const Object& objError, const Value& id)
1932 // Send error reply from json-rpc error object
1934 int code = find_value(objError, "code").get_int();
1935 if (code == -32600) nStatus = 400;
1936 else if (code == -32601) nStatus = 404;
1937 string strReply = JSONRPCReply(Value::null, objError, id);
1938 stream << HTTPReply(nStatus, strReply) << std::flush;
1941 bool ClientAllowed(const string& strAddress)
1943 if (strAddress == asio::ip::address_v4::loopback().to_string())
1945 const vector<string>& vAllow = mapMultiArgs["-rpcallowip"];
1946 BOOST_FOREACH(string strAllow, vAllow)
1947 if (WildcardMatch(strAddress, strAllow))
1954 // IOStream device that speaks SSL but can also speak non-SSL
1956 class SSLIOStreamDevice : public iostreams::device<iostreams::bidirectional> {
1958 SSLIOStreamDevice(SSLStream &streamIn, bool fUseSSLIn) : stream(streamIn)
1960 fUseSSL = fUseSSLIn;
1961 fNeedHandshake = fUseSSLIn;
1964 void handshake(ssl::stream_base::handshake_type role)
1966 if (!fNeedHandshake) return;
1967 fNeedHandshake = false;
1968 stream.handshake(role);
1970 std::streamsize read(char* s, std::streamsize n)
1972 handshake(ssl::stream_base::server); // HTTPS servers read first
1973 if (fUseSSL) return stream.read_some(asio::buffer(s, n));
1974 return stream.next_layer().read_some(asio::buffer(s, n));
1976 std::streamsize write(const char* s, std::streamsize n)
1978 handshake(ssl::stream_base::client); // HTTPS clients write first
1979 if (fUseSSL) return asio::write(stream, asio::buffer(s, n));
1980 return asio::write(stream.next_layer(), asio::buffer(s, n));
1982 bool connect(const std::string& server, const std::string& port)
1984 ip::tcp::resolver resolver(stream.get_io_service());
1985 ip::tcp::resolver::query query(server.c_str(), port.c_str());
1986 ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
1987 ip::tcp::resolver::iterator end;
1988 boost::system::error_code error = asio::error::host_not_found;
1989 while (error && endpoint_iterator != end)
1991 stream.lowest_layer().close();
1992 stream.lowest_layer().connect(*endpoint_iterator++, error);
2000 bool fNeedHandshake;
2006 void ThreadRPCServer(void* parg)
2008 IMPLEMENT_RANDOMIZE_STACK(ThreadRPCServer(parg));
2011 vnThreadsRunning[4]++;
2012 ThreadRPCServer2(parg);
2013 vnThreadsRunning[4]--;
2015 catch (std::exception& e) {
2016 vnThreadsRunning[4]--;
2017 PrintException(&e, "ThreadRPCServer()");
2019 vnThreadsRunning[4]--;
2020 PrintException(NULL, "ThreadRPCServer()");
2022 printf("ThreadRPCServer exiting\n");
2025 void ThreadRPCServer2(void* parg)
2027 printf("ThreadRPCServer started\n");
2029 if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
2031 unsigned char rand_pwd[32];
2032 RAND_bytes(rand_pwd, 32);
2033 string strWhatAmI = "To use bitcoind";
2034 if (mapArgs.count("-server"))
2035 strWhatAmI = strprintf(_("To use the %s option"), "\"-server\"");
2036 else if (mapArgs.count("-daemon"))
2037 strWhatAmI = strprintf(_("To use the %s option"), "\"-daemon\"");
2039 _("Warning: %s, you must set a rpcpassword in the configuration file:\n %s\n"
2040 "It is recommended you use the following random password:\n"
2041 "rpcuser=bitcoinrpc\n"
2043 "(you do not need to remember this password)\n"
2044 "If the file does not exist, create it with owner-readable-only file permissions.\n"),
2046 GetConfigFile().c_str(),
2047 EncodeBase58(&rand_pwd[0],&rand_pwd[0]+32).c_str());
2048 CreateThread(Shutdown, NULL);
2052 bool fUseSSL = GetBoolArg("-rpcssl");
2053 asio::ip::address bindAddress = mapArgs.count("-rpcallowip") ? asio::ip::address_v4::any() : asio::ip::address_v4::loopback();
2055 asio::io_service io_service;
2056 ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", 8332));
2057 ip::tcp::acceptor acceptor(io_service, endpoint);
2059 acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
2062 ssl::context context(io_service, ssl::context::sslv23);
2065 context.set_options(ssl::context::no_sslv2);
2066 filesystem::path certfile = GetArg("-rpcsslcertificatechainfile", "server.cert");
2067 if (!certfile.is_complete()) certfile = filesystem::path(GetDataDir()) / certfile;
2068 if (filesystem::exists(certfile)) context.use_certificate_chain_file(certfile.string().c_str());
2069 else printf("ThreadRPCServer ERROR: missing server certificate file %s\n", certfile.string().c_str());
2070 filesystem::path pkfile = GetArg("-rpcsslprivatekeyfile", "server.pem");
2071 if (!pkfile.is_complete()) pkfile = filesystem::path(GetDataDir()) / pkfile;
2072 if (filesystem::exists(pkfile)) context.use_private_key_file(pkfile.string().c_str(), ssl::context::pem);
2073 else printf("ThreadRPCServer ERROR: missing server private key file %s\n", pkfile.string().c_str());
2075 string ciphers = GetArg("-rpcsslciphers",
2076 "TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH");
2077 SSL_CTX_set_cipher_list(context.impl(), ciphers.c_str());
2081 throw runtime_error("-rpcssl=1, but bitcoin compiled without full openssl libraries.");
2086 // Accept connection
2088 SSLStream sslStream(io_service, context);
2089 SSLIOStreamDevice d(sslStream, fUseSSL);
2090 iostreams::stream<SSLIOStreamDevice> stream(d);
2092 ip::tcp::iostream stream;
2095 ip::tcp::endpoint peer;
2096 vnThreadsRunning[4]--;
2098 acceptor.accept(sslStream.lowest_layer(), peer);
2100 acceptor.accept(*stream.rdbuf(), peer);
2102 vnThreadsRunning[4]++;
2106 // Restrict callers by IP
2107 if (!ClientAllowed(peer.address().to_string()))
2109 // Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake.
2111 stream << HTTPReply(403, "") << std::flush;
2115 map<string, string> mapHeaders;
2118 boost::thread api_caller(ReadHTTP, boost::ref(stream), boost::ref(mapHeaders), boost::ref(strRequest));
2119 if (!api_caller.timed_join(boost::posix_time::seconds(GetArg("-rpctimeout", 30))))
2122 printf("ThreadRPCServer ReadHTTP timeout\n");
2126 // Check authorization
2127 if (mapHeaders.count("authorization") == 0)
2129 stream << HTTPReply(401, "") << std::flush;
2132 if (!HTTPAuthorized(mapHeaders))
2134 printf("ThreadRPCServer incorrect password attempt from %s\n",peer.address().to_string().c_str());
2135 /* Deter brute-forcing short passwords.
2136 If this results in a DOS the user really
2137 shouldn't have their RPC port exposed.*/
2138 if (mapArgs["-rpcpassword"].size() < 20)
2141 stream << HTTPReply(401, "") << std::flush;
2145 Value id = Value::null;
2150 if (!read_string(strRequest, valRequest) || valRequest.type() != obj_type)
2151 throw JSONRPCError(-32700, "Parse error");
2152 const Object& request = valRequest.get_obj();
2154 // Parse id now so errors from here on will have the id
2155 id = find_value(request, "id");
2158 Value valMethod = find_value(request, "method");
2159 if (valMethod.type() == null_type)
2160 throw JSONRPCError(-32600, "Missing method");
2161 if (valMethod.type() != str_type)
2162 throw JSONRPCError(-32600, "Method must be a string");
2163 string strMethod = valMethod.get_str();
2164 if (strMethod != "getwork")
2165 printf("ThreadRPCServer method=%s\n", strMethod.c_str());
2168 Value valParams = find_value(request, "params");
2170 if (valParams.type() == array_type)
2171 params = valParams.get_array();
2172 else if (valParams.type() == null_type)
2175 throw JSONRPCError(-32600, "Params must be an array");
2178 map<string, rpcfn_type>::iterator mi = mapCallTable.find(strMethod);
2179 if (mi == mapCallTable.end())
2180 throw JSONRPCError(-32601, "Method not found");
2182 // Observe safe mode
2183 string strWarning = GetWarnings("rpc");
2184 if (strWarning != "" && !GetBoolArg("-disablesafemode") && !setAllowInSafeMode.count(strMethod))
2185 throw JSONRPCError(-2, string("Safe mode: ") + strWarning);
2191 CRITICAL_BLOCK(cs_main)
2192 CRITICAL_BLOCK(pwalletMain->cs_wallet)
2193 result = (*(*mi).second)(params, false);
2196 string strReply = JSONRPCReply(result, Value::null, id);
2197 stream << HTTPReply(200, strReply) << std::flush;
2199 catch (std::exception& e)
2201 ErrorReply(stream, JSONRPCError(-1, e.what()), id);
2204 catch (Object& objError)
2206 ErrorReply(stream, objError, id);
2208 catch (std::exception& e)
2210 ErrorReply(stream, JSONRPCError(-32700, e.what()), id);
2218 Object CallRPC(const string& strMethod, const Array& params)
2220 if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
2221 throw runtime_error(strprintf(
2222 _("You must set rpcpassword=<password> in the configuration file:\n%s\n"
2223 "If the file does not exist, create it with owner-readable-only file permissions."),
2224 GetConfigFile().c_str()));
2226 // Connect to localhost
2227 bool fUseSSL = GetBoolArg("-rpcssl");
2229 asio::io_service io_service;
2230 ssl::context context(io_service, ssl::context::sslv23);
2231 context.set_options(ssl::context::no_sslv2);
2232 SSLStream sslStream(io_service, context);
2233 SSLIOStreamDevice d(sslStream, fUseSSL);
2234 iostreams::stream<SSLIOStreamDevice> stream(d);
2235 if (!d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332")))
2236 throw runtime_error("couldn't connect to server");
2239 throw runtime_error("-rpcssl=1, but bitcoin compiled without full openssl libraries.");
2241 ip::tcp::iostream stream(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332"));
2243 throw runtime_error("couldn't connect to server");
2247 // HTTP basic authentication
2248 string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
2249 map<string, string> mapRequestHeaders;
2250 mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64;
2253 string strRequest = JSONRPCRequest(strMethod, params, 1);
2254 string strPost = HTTPPost(strRequest, mapRequestHeaders);
2255 stream << strPost << std::flush;
2258 map<string, string> mapHeaders;
2260 int nStatus = ReadHTTP(stream, mapHeaders, strReply);
2262 throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
2263 else if (nStatus >= 400 && nStatus != 400 && nStatus != 404 && nStatus != 500)
2264 throw runtime_error(strprintf("server returned HTTP error %d", nStatus));
2265 else if (strReply.empty())
2266 throw runtime_error("no response from server");
2270 if (!read_string(strReply, valReply))
2271 throw runtime_error("couldn't parse reply from server");
2272 const Object& reply = valReply.get_obj();
2274 throw runtime_error("expected reply to have result, error and id properties");
2282 template<typename T>
2283 void ConvertTo(Value& value)
2285 if (value.type() == str_type)
2287 // reinterpret string as unquoted json value
2289 if (!read_string(value.get_str(), value2))
2290 throw runtime_error("type mismatch");
2291 value = value2.get_value<T>();
2295 value = value.get_value<T>();
2299 int CommandLineRPC(int argc, char *argv[])
2306 while (argc > 1 && IsSwitchChar(argv[1][0]))
2314 throw runtime_error("too few parameters");
2315 string strMethod = argv[1];
2317 // Parameters default to strings
2319 for (int i = 2; i < argc; i++)
2320 params.push_back(argv[i]);
2321 int n = params.size();
2324 // Special case non-string parameter types
2326 if (strMethod == "setgenerate" && n > 0) ConvertTo<bool>(params[0]);
2327 if (strMethod == "setgenerate" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2328 if (strMethod == "sendtoaddress" && n > 1) ConvertTo<double>(params[1]);
2329 if (strMethod == "settxfee" && n > 0) ConvertTo<double>(params[0]);
2330 if (strMethod == "getamountreceived" && n > 1) ConvertTo<boost::int64_t>(params[1]); // deprecated
2331 if (strMethod == "getreceivedbyaddress" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2332 if (strMethod == "getreceivedbyaccount" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2333 if (strMethod == "getreceivedbylabel" && n > 1) ConvertTo<boost::int64_t>(params[1]); // deprecated
2334 if (strMethod == "getallreceived" && n > 0) ConvertTo<boost::int64_t>(params[0]); // deprecated
2335 if (strMethod == "getallreceived" && n > 1) ConvertTo<bool>(params[1]); // deprecated
2336 if (strMethod == "listreceivedbyaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2337 if (strMethod == "listreceivedbyaddress" && n > 1) ConvertTo<bool>(params[1]);
2338 if (strMethod == "listreceivedbyaccount" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2339 if (strMethod == "listreceivedbyaccount" && n > 1) ConvertTo<bool>(params[1]);
2340 if (strMethod == "listreceivedbylabel" && n > 0) ConvertTo<boost::int64_t>(params[0]); // deprecated
2341 if (strMethod == "listreceivedbylabel" && n > 1) ConvertTo<bool>(params[1]); // deprecated
2342 if (strMethod == "getbalance" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2343 if (strMethod == "move" && n > 2) ConvertTo<double>(params[2]);
2344 if (strMethod == "move" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2345 if (strMethod == "sendfrom" && n > 2) ConvertTo<double>(params[2]);
2346 if (strMethod == "sendfrom" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2347 if (strMethod == "listtransactions" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2348 if (strMethod == "listtransactions" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2349 if (strMethod == "listaccounts" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2350 if (strMethod == "walletpassphrase" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2351 if (strMethod == "sendmany" && n > 1)
2353 string s = params[1].get_str();
2355 if (!read_string(s, v) || v.type() != obj_type)
2356 throw runtime_error("type mismatch");
2357 params[1] = v.get_obj();
2359 if (strMethod == "sendmany" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2362 Object reply = CallRPC(strMethod, params);
2365 const Value& result = find_value(reply, "result");
2366 const Value& error = find_value(reply, "error");
2368 if (error.type() != null_type)
2371 strPrint = "error: " + write_string(error, false);
2372 int code = find_value(error.get_obj(), "code").get_int();
2378 if (result.type() == null_type)
2380 else if (result.type() == str_type)
2381 strPrint = result.get_str();
2383 strPrint = write_string(result, true);
2386 catch (std::exception& e)
2388 strPrint = string("error: ") + e.what();
2393 PrintException(NULL, "CommandLineRPC()");
2398 #if defined(__WXMSW__) && defined(GUI)
2399 // Windows GUI apps can't print to command line,
2400 // so settle for a message box yuck
2401 MyMessageBox(strPrint, "Bitcoin", wxOK);
2403 fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
2413 int main(int argc, char *argv[])
2416 // Turn off microsoft heap dump noise
2417 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
2418 _CrtSetReportFile(_CRT_WARN, CreateFile("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0));
2420 setbuf(stdin, NULL);
2421 setbuf(stdout, NULL);
2422 setbuf(stderr, NULL);
2426 if (argc >= 2 && string(argv[1]) == "-server")
2428 printf("server ready\n");
2429 ThreadRPCServer(NULL);
2433 return CommandLineRPC(argc, argv);
2436 catch (std::exception& e) {
2437 PrintException(&e, "main()");
2439 PrintException(NULL, "main()");