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') != -1)
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)
688 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listReceived)
689 nBalance += r.second;
690 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listSent)
691 nBalance -= r.second;
693 nBalance += allGeneratedMature;
695 return ValueFromAmount(nBalance);
698 string strAccount = AccountFromValue(params[0]);
700 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
702 return ValueFromAmount(nBalance);
706 Value movecmd(const Array& params, bool fHelp)
708 if (fHelp || params.size() < 3 || params.size() > 5)
710 "move <fromaccount> <toaccount> <amount> [minconf=1] [comment]\n"
711 "Move from one account in your wallet to another.");
713 string strFrom = AccountFromValue(params[0]);
714 string strTo = AccountFromValue(params[1]);
715 int64 nAmount = AmountFromValue(params[2]);
716 if (params.size() > 3)
717 // unused parameter, used to be nMinDepth, keep type-checking it though
718 (void)params[3].get_int();
720 if (params.size() > 4)
721 strComment = params[4].get_str();
723 CWalletDB walletdb(pwalletMain->strWalletFile);
726 int64 nNow = GetAdjustedTime();
729 CAccountingEntry debit;
730 debit.strAccount = strFrom;
731 debit.nCreditDebit = -nAmount;
733 debit.strOtherAccount = strTo;
734 debit.strComment = strComment;
735 walletdb.WriteAccountingEntry(debit);
738 CAccountingEntry credit;
739 credit.strAccount = strTo;
740 credit.nCreditDebit = nAmount;
742 credit.strOtherAccount = strFrom;
743 credit.strComment = strComment;
744 walletdb.WriteAccountingEntry(credit);
746 walletdb.TxnCommit();
752 Value sendfrom(const Array& params, bool fHelp)
754 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
756 "sendfrom <fromaccount> <tobitcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
757 "<amount> is a real and is rounded to the nearest 0.00000001\n"
758 "requires wallet passphrase to be set with walletpassphrase first");
759 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
761 "sendfrom <fromaccount> <tobitcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
762 "<amount> is a real and is rounded to the nearest 0.00000001");
764 string strAccount = AccountFromValue(params[0]);
765 CBitcoinAddress address(params[1].get_str());
766 if (!address.IsValid())
767 throw JSONRPCError(-5, "Invalid bitcoin address");
768 int64 nAmount = AmountFromValue(params[2]);
770 if (params.size() > 3)
771 nMinDepth = params[3].get_int();
774 wtx.strFromAccount = strAccount;
775 if (params.size() > 4 && params[4].type() != null_type && !params[4].get_str().empty())
776 wtx.mapValue["comment"] = params[4].get_str();
777 if (params.size() > 5 && params[5].type() != null_type && !params[5].get_str().empty())
778 wtx.mapValue["to"] = params[5].get_str();
780 if (pwalletMain->IsLocked())
781 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
784 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
785 if (nAmount > nBalance)
786 throw JSONRPCError(-6, "Account has insufficient funds");
789 string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
791 throw JSONRPCError(-4, strError);
793 return wtx.GetHash().GetHex();
797 Value sendmany(const Array& params, bool fHelp)
799 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
801 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
802 "amounts are double-precision floating point numbers\n"
803 "requires wallet passphrase to be set with walletpassphrase first");
804 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
806 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
807 "amounts are double-precision floating point numbers");
809 string strAccount = AccountFromValue(params[0]);
810 Object sendTo = params[1].get_obj();
812 if (params.size() > 2)
813 nMinDepth = params[2].get_int();
816 wtx.strFromAccount = strAccount;
817 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
818 wtx.mapValue["comment"] = params[3].get_str();
820 set<CBitcoinAddress> setAddress;
821 vector<pair<CScript, int64> > vecSend;
823 int64 totalAmount = 0;
824 BOOST_FOREACH(const Pair& s, sendTo)
826 CBitcoinAddress address(s.name_);
827 if (!address.IsValid())
828 throw JSONRPCError(-5, string("Invalid bitcoin address:")+s.name_);
830 if (setAddress.count(address))
831 throw JSONRPCError(-8, string("Invalid parameter, duplicated address: ")+s.name_);
832 setAddress.insert(address);
834 CScript scriptPubKey;
835 scriptPubKey.SetBitcoinAddress(address);
836 int64 nAmount = AmountFromValue(s.value_);
837 totalAmount += nAmount;
839 vecSend.push_back(make_pair(scriptPubKey, nAmount));
842 if (pwalletMain->IsLocked())
843 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
846 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
847 if (totalAmount > nBalance)
848 throw JSONRPCError(-6, "Account has insufficient funds");
851 CReserveKey keyChange(pwalletMain);
852 int64 nFeeRequired = 0;
853 bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired);
856 if (totalAmount + nFeeRequired > pwalletMain->GetBalance())
857 throw JSONRPCError(-6, "Insufficient funds");
858 throw JSONRPCError(-4, "Transaction creation failed");
860 if (!pwalletMain->CommitTransaction(wtx, keyChange))
861 throw JSONRPCError(-4, "Transaction commit failed");
863 return wtx.GetHash().GetHex();
878 Value ListReceived(const Array& params, bool fByAccounts)
880 // Minimum confirmations
882 if (params.size() > 0)
883 nMinDepth = params[0].get_int();
885 // Whether to include empty accounts
886 bool fIncludeEmpty = false;
887 if (params.size() > 1)
888 fIncludeEmpty = params[1].get_bool();
891 map<CBitcoinAddress, tallyitem> mapTally;
892 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
894 const CWalletTx& wtx = (*it).second;
895 if (wtx.IsCoinBase() || !wtx.IsFinal())
898 int nDepth = wtx.GetDepthInMainChain();
899 if (nDepth < nMinDepth)
902 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
904 CBitcoinAddress address;
905 if (!ExtractAddress(txout.scriptPubKey, pwalletMain, address) || !address.IsValid())
908 tallyitem& item = mapTally[address];
909 item.nAmount += txout.nValue;
910 item.nConf = min(item.nConf, nDepth);
916 map<string, tallyitem> mapAccountTally;
917 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
919 const CBitcoinAddress& address = item.first;
920 const string& strAccount = item.second;
921 map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
922 if (it == mapTally.end() && !fIncludeEmpty)
927 if (it != mapTally.end())
929 nAmount = (*it).second.nAmount;
930 nConf = (*it).second.nConf;
935 tallyitem& item = mapAccountTally[strAccount];
936 item.nAmount += nAmount;
937 item.nConf = min(item.nConf, nConf);
942 obj.push_back(Pair("address", address.ToString()));
943 obj.push_back(Pair("account", strAccount));
944 obj.push_back(Pair("label", strAccount)); // deprecated
945 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
946 obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf)));
953 for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
955 int64 nAmount = (*it).second.nAmount;
956 int nConf = (*it).second.nConf;
958 obj.push_back(Pair("account", (*it).first));
959 obj.push_back(Pair("label", (*it).first)); // deprecated
960 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
961 obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf)));
969 Value listreceivedbyaddress(const Array& params, bool fHelp)
971 if (fHelp || params.size() > 2)
973 "listreceivedbyaddress [minconf=1] [includeempty=false]\n"
974 "[minconf] is the minimum number of confirmations before payments are included.\n"
975 "[includeempty] whether to include addresses that haven't received any payments.\n"
976 "Returns an array of objects containing:\n"
977 " \"address\" : receiving address\n"
978 " \"account\" : the account of the receiving address\n"
979 " \"amount\" : total amount received by the address\n"
980 " \"confirmations\" : number of confirmations of the most recent transaction included");
982 return ListReceived(params, false);
985 Value listreceivedbyaccount(const Array& params, bool fHelp)
987 if (fHelp || params.size() > 2)
989 "listreceivedbyaccount [minconf=1] [includeempty=false]\n"
990 "[minconf] is the minimum number of confirmations before payments are included.\n"
991 "[includeempty] whether to include accounts that haven't received any payments.\n"
992 "Returns an array of objects containing:\n"
993 " \"account\" : the account of the receiving addresses\n"
994 " \"amount\" : total amount received by addresses with this account\n"
995 " \"confirmations\" : number of confirmations of the most recent transaction included");
997 return ListReceived(params, true);
1000 void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret)
1002 int64 nGeneratedImmature, nGeneratedMature, nFee;
1003 string strSentAccount;
1004 list<pair<CBitcoinAddress, int64> > listReceived;
1005 list<pair<CBitcoinAddress, int64> > listSent;
1006 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1008 bool fAllAccounts = (strAccount == string("*"));
1010 // Generated blocks assigned to account ""
1011 if ((nGeneratedMature+nGeneratedImmature) != 0 && (fAllAccounts || strAccount == ""))
1014 entry.push_back(Pair("account", string("")));
1015 if (nGeneratedImmature)
1017 entry.push_back(Pair("category", wtx.GetDepthInMainChain() ? "immature" : "orphan"));
1018 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedImmature)));
1022 entry.push_back(Pair("category", "generate"));
1023 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedMature)));
1026 WalletTxToJSON(wtx, entry);
1027 ret.push_back(entry);
1031 if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
1033 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1036 entry.push_back(Pair("account", strSentAccount));
1037 entry.push_back(Pair("address", s.first.ToString()));
1038 entry.push_back(Pair("category", "send"));
1039 entry.push_back(Pair("amount", ValueFromAmount(-s.second)));
1040 entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
1042 WalletTxToJSON(wtx, entry);
1043 ret.push_back(entry);
1048 if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
1049 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1052 if (pwalletMain->mapAddressBook.count(r.first))
1053 account = pwalletMain->mapAddressBook[r.first];
1054 if (fAllAccounts || (account == strAccount))
1057 entry.push_back(Pair("account", account));
1058 entry.push_back(Pair("address", r.first.ToString()));
1059 entry.push_back(Pair("category", "receive"));
1060 entry.push_back(Pair("amount", ValueFromAmount(r.second)));
1062 WalletTxToJSON(wtx, entry);
1063 ret.push_back(entry);
1068 void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret)
1070 bool fAllAccounts = (strAccount == string("*"));
1072 if (fAllAccounts || acentry.strAccount == strAccount)
1075 entry.push_back(Pair("account", acentry.strAccount));
1076 entry.push_back(Pair("category", "move"));
1077 entry.push_back(Pair("time", (boost::int64_t)acentry.nTime));
1078 entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
1079 entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
1080 entry.push_back(Pair("comment", acentry.strComment));
1081 ret.push_back(entry);
1085 Value listtransactions(const Array& params, bool fHelp)
1087 if (fHelp || params.size() > 3)
1088 throw runtime_error(
1089 "listtransactions [account] [count=10] [from=0]\n"
1090 "Returns up to [count] most recent transactions skipping the first [from] transactions for account [account].");
1092 string strAccount = "*";
1093 if (params.size() > 0)
1094 strAccount = params[0].get_str();
1096 if (params.size() > 1)
1097 nCount = params[1].get_int();
1099 if (params.size() > 2)
1100 nFrom = params[2].get_int();
1103 throw JSONRPCError(-8, "Negative count");
1105 throw JSONRPCError(-8, "Negative from");
1108 CWalletDB walletdb(pwalletMain->strWalletFile);
1110 // First: get all CWalletTx and CAccountingEntry into a sorted-by-time multimap.
1111 typedef pair<CWalletTx*, CAccountingEntry*> TxPair;
1112 typedef multimap<int64, TxPair > TxItems;
1115 // Note: maintaining indices in the database of (account,time) --> txid and (account, time) --> acentry
1116 // would make this much faster for applications that do this a lot.
1117 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1119 CWalletTx* wtx = &((*it).second);
1120 txByTime.insert(make_pair(wtx->GetTxTime(), TxPair(wtx, (CAccountingEntry*)0)));
1122 list<CAccountingEntry> acentries;
1123 walletdb.ListAccountCreditDebit(strAccount, acentries);
1124 BOOST_FOREACH(CAccountingEntry& entry, acentries)
1126 txByTime.insert(make_pair(entry.nTime, TxPair((CWalletTx*)0, &entry)));
1129 // iterate backwards until we have nCount items to return:
1130 for (TxItems::reverse_iterator it = txByTime.rbegin(); it != txByTime.rend(); ++it)
1132 CWalletTx *const pwtx = (*it).second.first;
1134 ListTransactions(*pwtx, strAccount, 0, true, ret);
1135 CAccountingEntry *const pacentry = (*it).second.second;
1137 AcentryToJSON(*pacentry, strAccount, ret);
1139 if (ret.size() >= (nCount+nFrom)) break;
1141 // ret is newest to oldest
1143 if (nFrom > ret.size()) nFrom = ret.size();
1144 if (nFrom+nCount > ret.size()) nCount = ret.size()-nFrom;
1145 Array::iterator first = ret.begin();
1146 std::advance(first, nFrom);
1147 Array::iterator last = ret.begin();
1148 std::advance(last, nFrom+nCount);
1150 if (last != ret.end()) ret.erase(last, ret.end());
1151 if (first != ret.begin()) ret.erase(ret.begin(), first);
1153 std::reverse(ret.begin(), ret.end()); // Return oldest to newest
1158 Value listaccounts(const Array& params, bool fHelp)
1160 if (fHelp || params.size() > 1)
1161 throw runtime_error(
1162 "listaccounts [minconf=1]\n"
1163 "Returns Object that has account names as keys, account balances as values.");
1166 if (params.size() > 0)
1167 nMinDepth = params[0].get_int();
1169 map<string, int64> mapAccountBalances;
1170 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& entry, pwalletMain->mapAddressBook) {
1171 if (pwalletMain->HaveKey(entry.first)) // This address belongs to me
1172 mapAccountBalances[entry.second] = 0;
1175 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1177 const CWalletTx& wtx = (*it).second;
1178 int64 nGeneratedImmature, nGeneratedMature, nFee;
1179 string strSentAccount;
1180 list<pair<CBitcoinAddress, int64> > listReceived;
1181 list<pair<CBitcoinAddress, int64> > listSent;
1182 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1183 mapAccountBalances[strSentAccount] -= nFee;
1184 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1185 mapAccountBalances[strSentAccount] -= s.second;
1186 if (wtx.GetDepthInMainChain() >= nMinDepth)
1188 mapAccountBalances[""] += nGeneratedMature;
1189 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1190 if (pwalletMain->mapAddressBook.count(r.first))
1191 mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second;
1193 mapAccountBalances[""] += r.second;
1197 list<CAccountingEntry> acentries;
1198 CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
1199 BOOST_FOREACH(const CAccountingEntry& entry, acentries)
1200 mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
1203 BOOST_FOREACH(const PAIRTYPE(string, int64)& accountBalance, mapAccountBalances) {
1204 ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
1209 Value gettransaction(const Array& params, bool fHelp)
1211 if (fHelp || params.size() != 1)
1212 throw runtime_error(
1213 "gettransaction <txid>\n"
1214 "Get detailed information about <txid>");
1217 hash.SetHex(params[0].get_str());
1221 if (!pwalletMain->mapWallet.count(hash))
1222 throw JSONRPCError(-5, "Invalid or non-wallet transaction id");
1223 const CWalletTx& wtx = pwalletMain->mapWallet[hash];
1225 int64 nCredit = wtx.GetCredit();
1226 int64 nDebit = wtx.GetDebit();
1227 int64 nNet = nCredit - nDebit;
1228 int64 nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0);
1230 entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
1232 entry.push_back(Pair("fee", ValueFromAmount(nFee)));
1234 WalletTxToJSON(pwalletMain->mapWallet[hash], entry);
1237 ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details);
1238 entry.push_back(Pair("details", details));
1244 Value backupwallet(const Array& params, bool fHelp)
1246 if (fHelp || params.size() != 1)
1247 throw runtime_error(
1248 "backupwallet <destination>\n"
1249 "Safely copies wallet.dat to destination, which can be a directory or a path with filename.");
1251 string strDest = params[0].get_str();
1252 BackupWallet(*pwalletMain, strDest);
1258 Value keypoolrefill(const Array& params, bool fHelp)
1260 if (pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1261 throw runtime_error(
1263 "Fills the keypool, requires wallet passphrase to be set.");
1264 if (!pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1265 throw runtime_error(
1267 "Fills the keypool.");
1269 if (pwalletMain->IsLocked())
1270 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
1272 pwalletMain->TopUpKeyPool();
1274 if (pwalletMain->GetKeyPoolSize() < GetArg("-keypool", 100))
1275 throw JSONRPCError(-4, "Error refreshing keypool.");
1281 void ThreadTopUpKeyPool(void* parg)
1283 pwalletMain->TopUpKeyPool();
1286 void ThreadCleanWalletPassphrase(void* parg)
1288 int64 nMyWakeTime = GetTimeMillis() + *((int64*)parg) * 1000;
1290 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1292 if (nWalletUnlockTime == 0)
1294 nWalletUnlockTime = nMyWakeTime;
1298 if (nWalletUnlockTime==0)
1300 int64 nToSleep = nWalletUnlockTime - GetTimeMillis();
1304 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1306 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1310 if (nWalletUnlockTime)
1312 nWalletUnlockTime = 0;
1313 pwalletMain->Lock();
1318 if (nWalletUnlockTime < nMyWakeTime)
1319 nWalletUnlockTime = nMyWakeTime;
1322 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1324 delete (int64*)parg;
1327 Value walletpassphrase(const Array& params, bool fHelp)
1329 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1330 throw runtime_error(
1331 "walletpassphrase <passphrase> <timeout>\n"
1332 "Stores the wallet decryption key in memory for <timeout> seconds.");
1335 if (!pwalletMain->IsCrypted())
1336 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
1338 if (!pwalletMain->IsLocked())
1339 throw JSONRPCError(-17, "Error: Wallet is already unlocked.");
1341 // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
1342 string strWalletPass;
1343 strWalletPass.reserve(100);
1344 mlock(&strWalletPass[0], strWalletPass.capacity());
1345 strWalletPass = params[0].get_str();
1347 if (strWalletPass.length() > 0)
1349 if (!pwalletMain->Unlock(strWalletPass))
1351 fill(strWalletPass.begin(), strWalletPass.end(), '\0');
1352 munlock(&strWalletPass[0], strWalletPass.capacity());
1353 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1355 fill(strWalletPass.begin(), strWalletPass.end(), '\0');
1356 munlock(&strWalletPass[0], strWalletPass.capacity());
1359 throw runtime_error(
1360 "walletpassphrase <passphrase> <timeout>\n"
1361 "Stores the wallet decryption key in memory for <timeout> seconds.");
1363 CreateThread(ThreadTopUpKeyPool, NULL);
1364 int64* pnSleepTime = new int64(params[1].get_int64());
1365 CreateThread(ThreadCleanWalletPassphrase, pnSleepTime);
1371 Value walletpassphrasechange(const Array& params, bool fHelp)
1373 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1374 throw runtime_error(
1375 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1376 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1379 if (!pwalletMain->IsCrypted())
1380 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
1382 string strOldWalletPass;
1383 strOldWalletPass.reserve(100);
1384 mlock(&strOldWalletPass[0], strOldWalletPass.capacity());
1385 strOldWalletPass = params[0].get_str();
1387 string strNewWalletPass;
1388 strNewWalletPass.reserve(100);
1389 mlock(&strNewWalletPass[0], strNewWalletPass.capacity());
1390 strNewWalletPass = params[1].get_str();
1392 if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
1393 throw runtime_error(
1394 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1395 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1397 if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
1399 fill(strOldWalletPass.begin(), strOldWalletPass.end(), '\0');
1400 fill(strNewWalletPass.begin(), strNewWalletPass.end(), '\0');
1401 munlock(&strOldWalletPass[0], strOldWalletPass.capacity());
1402 munlock(&strNewWalletPass[0], strNewWalletPass.capacity());
1403 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1405 fill(strNewWalletPass.begin(), strNewWalletPass.end(), '\0');
1406 fill(strOldWalletPass.begin(), strOldWalletPass.end(), '\0');
1407 munlock(&strOldWalletPass[0], strOldWalletPass.capacity());
1408 munlock(&strNewWalletPass[0], strNewWalletPass.capacity());
1414 Value walletlock(const Array& params, bool fHelp)
1416 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
1417 throw runtime_error(
1419 "Removes the wallet encryption key from memory, locking the wallet.\n"
1420 "After calling this method, you will need to call walletpassphrase again\n"
1421 "before being able to call any methods which require the wallet to be unlocked.");
1424 if (!pwalletMain->IsCrypted())
1425 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletlock was called.");
1427 CRITICAL_BLOCK(cs_nWalletUnlockTime)
1429 pwalletMain->Lock();
1430 nWalletUnlockTime = 0;
1437 Value encryptwallet(const Array& params, bool fHelp)
1439 if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
1440 throw runtime_error(
1441 "encryptwallet <passphrase>\n"
1442 "Encrypts the wallet with <passphrase>.");
1445 if (pwalletMain->IsCrypted())
1446 throw JSONRPCError(-15, "Error: running with an encrypted wallet, but encryptwallet was called.");
1449 // shutting down via RPC while the GUI is running does not work (yet):
1450 throw runtime_error("Not Yet Implemented: use GUI to encrypt wallet, not RPC command");
1453 string strWalletPass;
1454 strWalletPass.reserve(100);
1455 mlock(&strWalletPass[0], strWalletPass.capacity());
1456 strWalletPass = params[0].get_str();
1458 if (strWalletPass.length() < 1)
1459 throw runtime_error(
1460 "encryptwallet <passphrase>\n"
1461 "Encrypts the wallet with <passphrase>.");
1463 if (!pwalletMain->EncryptWallet(strWalletPass))
1465 fill(strWalletPass.begin(), strWalletPass.end(), '\0');
1466 munlock(&strWalletPass[0], strWalletPass.capacity());
1467 throw JSONRPCError(-16, "Error: Failed to encrypt the wallet.");
1469 fill(strWalletPass.begin(), strWalletPass.end(), '\0');
1470 munlock(&strWalletPass[0], strWalletPass.capacity());
1472 // BDB seems to have a bad habit of writing old data into
1473 // slack space in .dat files; that is bad if the old data is
1474 // unencrypted private keys. So:
1475 CreateThread(Shutdown, NULL);
1476 return "wallet encrypted; bitcoin server stopping, restart to run with encrypted wallet";
1480 Value validateaddress(const Array& params, bool fHelp)
1482 if (fHelp || params.size() != 1)
1483 throw runtime_error(
1484 "validateaddress <bitcoinaddress>\n"
1485 "Return information about <bitcoinaddress>.");
1487 CBitcoinAddress address(params[0].get_str());
1488 bool isValid = address.IsValid();
1491 ret.push_back(Pair("isvalid", isValid));
1494 // Call Hash160ToAddress() so we always return current ADDRESSVERSION
1495 // version of the address:
1496 string currentAddress = address.ToString();
1497 ret.push_back(Pair("address", currentAddress));
1498 ret.push_back(Pair("ismine", (pwalletMain->HaveKey(address) > 0)));
1499 if (pwalletMain->mapAddressBook.count(address))
1500 ret.push_back(Pair("account", pwalletMain->mapAddressBook[address]));
1506 Value getwork(const Array& params, bool fHelp)
1508 if (fHelp || params.size() > 1)
1509 throw runtime_error(
1511 "If [data] is not specified, returns formatted hash data to work on:\n"
1512 " \"midstate\" : precomputed hash state after hashing the first half of the data\n"
1513 " \"data\" : block data\n"
1514 " \"hash1\" : formatted hash buffer for second hash\n"
1515 " \"target\" : little endian hash target\n"
1516 "If [data] is specified, tries to solve the block and returns true if it was successful.");
1519 throw JSONRPCError(-9, "Bitcoin is not connected!");
1521 if (IsInitialBlockDownload())
1522 throw JSONRPCError(-10, "Bitcoin is downloading blocks...");
1524 typedef map<uint256, pair<CBlock*, CScript> > mapNewBlock_t;
1525 static mapNewBlock_t mapNewBlock;
1526 static vector<CBlock*> vNewBlock;
1527 static CReserveKey reservekey(pwalletMain);
1529 if (params.size() == 0)
1532 static unsigned int nTransactionsUpdatedLast;
1533 static CBlockIndex* pindexPrev;
1534 static int64 nStart;
1535 static CBlock* pblock;
1536 if (pindexPrev != pindexBest ||
1537 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60))
1539 if (pindexPrev != pindexBest)
1541 // Deallocate old blocks since they're obsolete now
1542 mapNewBlock.clear();
1543 BOOST_FOREACH(CBlock* pblock, vNewBlock)
1547 nTransactionsUpdatedLast = nTransactionsUpdated;
1548 pindexPrev = pindexBest;
1552 pblock = CreateNewBlock(reservekey);
1554 throw JSONRPCError(-7, "Out of memory");
1555 vNewBlock.push_back(pblock);
1559 pblock->UpdateTime(pindexPrev);
1562 // Update nExtraNonce
1563 static unsigned int nExtraNonce = 0;
1564 IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
1567 mapNewBlock[pblock->hashMerkleRoot] = make_pair(pblock, pblock->vtx[0].vin[0].scriptSig);
1569 // Prebuild hash buffers
1573 FormatHashBuffers(pblock, pmidstate, pdata, phash1);
1575 uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
1578 result.push_back(Pair("midstate", HexStr(BEGIN(pmidstate), END(pmidstate))));
1579 result.push_back(Pair("data", HexStr(BEGIN(pdata), END(pdata))));
1580 result.push_back(Pair("hash1", HexStr(BEGIN(phash1), END(phash1))));
1581 result.push_back(Pair("target", HexStr(BEGIN(hashTarget), END(hashTarget))));
1587 vector<unsigned char> vchData = ParseHex(params[0].get_str());
1588 if (vchData.size() != 128)
1589 throw JSONRPCError(-8, "Invalid parameter");
1590 CBlock* pdata = (CBlock*)&vchData[0];
1593 for (int i = 0; i < 128/4; i++)
1594 ((unsigned int*)pdata)[i] = CryptoPP::ByteReverse(((unsigned int*)pdata)[i]);
1597 if (!mapNewBlock.count(pdata->hashMerkleRoot))
1599 CBlock* pblock = mapNewBlock[pdata->hashMerkleRoot].first;
1601 pblock->nTime = pdata->nTime;
1602 pblock->nNonce = pdata->nNonce;
1603 pblock->vtx[0].vin[0].scriptSig = mapNewBlock[pdata->hashMerkleRoot].second;
1604 pblock->hashMerkleRoot = pblock->BuildMerkleTree();
1606 return CheckWork(pblock, *pwalletMain, reservekey);
1624 pair<string, rpcfn_type> pCallTable[] =
1626 make_pair("help", &help),
1627 make_pair("stop", &stop),
1628 make_pair("getblockcount", &getblockcount),
1629 make_pair("getblocknumber", &getblocknumber),
1630 make_pair("getconnectioncount", &getconnectioncount),
1631 make_pair("getdifficulty", &getdifficulty),
1632 make_pair("getgenerate", &getgenerate),
1633 make_pair("setgenerate", &setgenerate),
1634 make_pair("gethashespersec", &gethashespersec),
1635 make_pair("getinfo", &getinfo),
1636 make_pair("getnewaddress", &getnewaddress),
1637 make_pair("getaccountaddress", &getaccountaddress),
1638 make_pair("setaccount", &setaccount),
1639 make_pair("setlabel", &setaccount), // deprecated
1640 make_pair("getaccount", &getaccount),
1641 make_pair("getlabel", &getaccount), // deprecated
1642 make_pair("getaddressesbyaccount", &getaddressesbyaccount),
1643 make_pair("getaddressesbylabel", &getaddressesbyaccount), // deprecated
1644 make_pair("sendtoaddress", &sendtoaddress),
1645 make_pair("getamountreceived", &getreceivedbyaddress), // deprecated, renamed to getreceivedbyaddress
1646 make_pair("getallreceived", &listreceivedbyaddress), // deprecated, renamed to listreceivedbyaddress
1647 make_pair("getreceivedbyaddress", &getreceivedbyaddress),
1648 make_pair("getreceivedbyaccount", &getreceivedbyaccount),
1649 make_pair("getreceivedbylabel", &getreceivedbyaccount), // deprecated
1650 make_pair("listreceivedbyaddress", &listreceivedbyaddress),
1651 make_pair("listreceivedbyaccount", &listreceivedbyaccount),
1652 make_pair("listreceivedbylabel", &listreceivedbyaccount), // deprecated
1653 make_pair("backupwallet", &backupwallet),
1654 make_pair("keypoolrefill", &keypoolrefill),
1655 make_pair("walletpassphrase", &walletpassphrase),
1656 make_pair("walletpassphrasechange", &walletpassphrasechange),
1657 make_pair("walletlock", &walletlock),
1658 make_pair("encryptwallet", &encryptwallet),
1659 make_pair("validateaddress", &validateaddress),
1660 make_pair("getbalance", &getbalance),
1661 make_pair("move", &movecmd),
1662 make_pair("sendfrom", &sendfrom),
1663 make_pair("sendmany", &sendmany),
1664 make_pair("gettransaction", &gettransaction),
1665 make_pair("listtransactions", &listtransactions),
1666 make_pair("getwork", &getwork),
1667 make_pair("listaccounts", &listaccounts),
1668 make_pair("settxfee", &settxfee),
1670 map<string, rpcfn_type> mapCallTable(pCallTable, pCallTable + sizeof(pCallTable)/sizeof(pCallTable[0]));
1672 string pAllowInSafeMode[] =
1678 "getconnectioncount",
1685 "getaccountaddress",
1686 "setlabel", // deprecated
1688 "getlabel", // deprecated
1689 "getaddressesbyaccount",
1690 "getaddressesbylabel", // deprecated
1698 set<string> setAllowInSafeMode(pAllowInSafeMode, pAllowInSafeMode + sizeof(pAllowInSafeMode)/sizeof(pAllowInSafeMode[0]));
1706 // This ain't Apache. We're just using HTTP header for the length field
1707 // and to be compatible with other JSON-RPC implementations.
1710 string HTTPPost(const string& strMsg, const map<string,string>& mapRequestHeaders)
1713 s << "POST / HTTP/1.1\r\n"
1714 << "User-Agent: bitcoin-json-rpc/" << FormatFullVersion() << "\r\n"
1715 << "Host: 127.0.0.1\r\n"
1716 << "Content-Type: application/json\r\n"
1717 << "Content-Length: " << strMsg.size() << "\r\n"
1718 << "Accept: application/json\r\n";
1719 BOOST_FOREACH(const PAIRTYPE(string, string)& item, mapRequestHeaders)
1720 s << item.first << ": " << item.second << "\r\n";
1721 s << "\r\n" << strMsg;
1726 string rfc1123Time()
1731 struct tm* now_gmt = gmtime(&now);
1732 string locale(setlocale(LC_TIME, NULL));
1733 setlocale(LC_TIME, "C"); // we want posix (aka "C") weekday/month strings
1734 strftime(buffer, sizeof(buffer), "%a, %d %b %Y %H:%M:%S +0000", now_gmt);
1735 setlocale(LC_TIME, locale.c_str());
1736 return string(buffer);
1739 static string HTTPReply(int nStatus, const string& strMsg)
1742 return strprintf("HTTP/1.0 401 Authorization Required\r\n"
1744 "Server: bitcoin-json-rpc/%s\r\n"
1745 "WWW-Authenticate: Basic realm=\"jsonrpc\"\r\n"
1746 "Content-Type: text/html\r\n"
1747 "Content-Length: 296\r\n"
1749 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\r\n"
1750 "\"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd\">\r\n"
1753 "<TITLE>Error</TITLE>\r\n"
1754 "<META HTTP-EQUIV='Content-Type' CONTENT='text/html; charset=ISO-8859-1'>\r\n"
1756 "<BODY><H1>401 Unauthorized.</H1></BODY>\r\n"
1757 "</HTML>\r\n", rfc1123Time().c_str(), FormatFullVersion().c_str());
1759 if (nStatus == 200) strStatus = "OK";
1760 else if (nStatus == 400) strStatus = "Bad Request";
1761 else if (nStatus == 403) strStatus = "Forbidden";
1762 else if (nStatus == 404) strStatus = "Not Found";
1763 else if (nStatus == 500) strStatus = "Internal Server Error";
1765 "HTTP/1.1 %d %s\r\n"
1767 "Connection: close\r\n"
1768 "Content-Length: %d\r\n"
1769 "Content-Type: application/json\r\n"
1770 "Server: bitcoin-json-rpc/%s\r\n"
1775 rfc1123Time().c_str(),
1777 FormatFullVersion().c_str(),
1781 int ReadHTTPStatus(std::basic_istream<char>& stream)
1784 getline(stream, str);
1785 vector<string> vWords;
1786 boost::split(vWords, str, boost::is_any_of(" "));
1787 if (vWords.size() < 2)
1789 return atoi(vWords[1].c_str());
1792 int ReadHTTPHeader(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet)
1798 std::getline(stream, str);
1799 if (str.empty() || str == "\r")
1801 string::size_type nColon = str.find(":");
1802 if (nColon != string::npos)
1804 string strHeader = str.substr(0, nColon);
1805 boost::trim(strHeader);
1806 boost::to_lower(strHeader);
1807 string strValue = str.substr(nColon+1);
1808 boost::trim(strValue);
1809 mapHeadersRet[strHeader] = strValue;
1810 if (strHeader == "content-length")
1811 nLen = atoi(strValue.c_str());
1817 int ReadHTTP(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet, string& strMessageRet)
1819 mapHeadersRet.clear();
1823 int nStatus = ReadHTTPStatus(stream);
1826 int nLen = ReadHTTPHeader(stream, mapHeadersRet);
1827 if (nLen < 0 || nLen > MAX_SIZE)
1833 vector<char> vch(nLen);
1834 stream.read(&vch[0], nLen);
1835 strMessageRet = string(vch.begin(), vch.end());
1841 string EncodeBase64(string s)
1846 b64 = BIO_new(BIO_f_base64());
1847 BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
1848 bmem = BIO_new(BIO_s_mem());
1849 b64 = BIO_push(b64, bmem);
1850 BIO_write(b64, s.c_str(), s.size());
1852 BIO_get_mem_ptr(b64, &bptr);
1854 string result(bptr->data, bptr->length);
1860 string DecodeBase64(string s)
1864 char* buffer = static_cast<char*>(calloc(s.size(), sizeof(char)));
1866 b64 = BIO_new(BIO_f_base64());
1867 BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
1868 bmem = BIO_new_mem_buf(const_cast<char*>(s.c_str()), s.size());
1869 bmem = BIO_push(b64, bmem);
1870 BIO_read(bmem, buffer, s.size());
1873 string result(buffer);
1878 bool HTTPAuthorized(map<string, string>& mapHeaders)
1880 string strAuth = mapHeaders["authorization"];
1881 if (strAuth.substr(0,6) != "Basic ")
1883 string strUserPass64 = strAuth.substr(6); boost::trim(strUserPass64);
1884 string strUserPass = DecodeBase64(strUserPass64);
1885 string::size_type nColon = strUserPass.find(":");
1886 if (nColon == string::npos)
1888 string strUser = strUserPass.substr(0, nColon);
1889 string strPassword = strUserPass.substr(nColon+1);
1890 return (strUser == mapArgs["-rpcuser"] && strPassword == mapArgs["-rpcpassword"]);
1894 // JSON-RPC protocol. Bitcoin speaks version 1.0 for maximum compatibility,
1895 // but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
1896 // unspecified (HTTP errors and contents of 'error').
1898 // 1.0 spec: http://json-rpc.org/wiki/specification
1899 // 1.2 spec: http://groups.google.com/group/json-rpc/web/json-rpc-over-http
1900 // http://www.codeproject.com/KB/recipes/JSON_Spirit.aspx
1903 string JSONRPCRequest(const string& strMethod, const Array& params, const Value& id)
1906 request.push_back(Pair("method", strMethod));
1907 request.push_back(Pair("params", params));
1908 request.push_back(Pair("id", id));
1909 return write_string(Value(request), false) + "\n";
1912 string JSONRPCReply(const Value& result, const Value& error, const Value& id)
1915 if (error.type() != null_type)
1916 reply.push_back(Pair("result", Value::null));
1918 reply.push_back(Pair("result", result));
1919 reply.push_back(Pair("error", error));
1920 reply.push_back(Pair("id", id));
1921 return write_string(Value(reply), false) + "\n";
1924 void ErrorReply(std::ostream& stream, const Object& objError, const Value& id)
1926 // Send error reply from json-rpc error object
1928 int code = find_value(objError, "code").get_int();
1929 if (code == -32600) nStatus = 400;
1930 else if (code == -32601) nStatus = 404;
1931 string strReply = JSONRPCReply(Value::null, objError, id);
1932 stream << HTTPReply(nStatus, strReply) << std::flush;
1935 bool ClientAllowed(const string& strAddress)
1937 if (strAddress == asio::ip::address_v4::loopback().to_string())
1939 const vector<string>& vAllow = mapMultiArgs["-rpcallowip"];
1940 BOOST_FOREACH(string strAllow, vAllow)
1941 if (WildcardMatch(strAddress, strAllow))
1948 // IOStream device that speaks SSL but can also speak non-SSL
1950 class SSLIOStreamDevice : public iostreams::device<iostreams::bidirectional> {
1952 SSLIOStreamDevice(SSLStream &streamIn, bool fUseSSLIn) : stream(streamIn)
1954 fUseSSL = fUseSSLIn;
1955 fNeedHandshake = fUseSSLIn;
1958 void handshake(ssl::stream_base::handshake_type role)
1960 if (!fNeedHandshake) return;
1961 fNeedHandshake = false;
1962 stream.handshake(role);
1964 std::streamsize read(char* s, std::streamsize n)
1966 handshake(ssl::stream_base::server); // HTTPS servers read first
1967 if (fUseSSL) return stream.read_some(asio::buffer(s, n));
1968 return stream.next_layer().read_some(asio::buffer(s, n));
1970 std::streamsize write(const char* s, std::streamsize n)
1972 handshake(ssl::stream_base::client); // HTTPS clients write first
1973 if (fUseSSL) return asio::write(stream, asio::buffer(s, n));
1974 return asio::write(stream.next_layer(), asio::buffer(s, n));
1976 bool connect(const std::string& server, const std::string& port)
1978 ip::tcp::resolver resolver(stream.get_io_service());
1979 ip::tcp::resolver::query query(server.c_str(), port.c_str());
1980 ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
1981 ip::tcp::resolver::iterator end;
1982 boost::system::error_code error = asio::error::host_not_found;
1983 while (error && endpoint_iterator != end)
1985 stream.lowest_layer().close();
1986 stream.lowest_layer().connect(*endpoint_iterator++, error);
1994 bool fNeedHandshake;
2000 void ThreadRPCServer(void* parg)
2002 IMPLEMENT_RANDOMIZE_STACK(ThreadRPCServer(parg));
2005 vnThreadsRunning[4]++;
2006 ThreadRPCServer2(parg);
2007 vnThreadsRunning[4]--;
2009 catch (std::exception& e) {
2010 vnThreadsRunning[4]--;
2011 PrintException(&e, "ThreadRPCServer()");
2013 vnThreadsRunning[4]--;
2014 PrintException(NULL, "ThreadRPCServer()");
2016 printf("ThreadRPCServer exiting\n");
2019 void ThreadRPCServer2(void* parg)
2021 printf("ThreadRPCServer started\n");
2023 if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
2025 unsigned char rand_pwd[32];
2026 RAND_bytes(rand_pwd, 32);
2027 string strWhatAmI = "To use bitcoind";
2028 if (mapArgs.count("-server"))
2029 strWhatAmI = strprintf(_("To use the %s option"), "\"-server\"");
2030 else if (mapArgs.count("-daemon"))
2031 strWhatAmI = strprintf(_("To use the %s option"), "\"-daemon\"");
2033 _("Warning: %s, you must set a rpcpassword in the configuration file:\n %s\n"
2034 "It is recommended you use the following random password:\n"
2035 "rpcuser=bitcoinrpc\n"
2037 "(you do not need to remember this password)\n"
2038 "If the file does not exist, create it with owner-readable-only file permissions.\n"),
2040 GetConfigFile().c_str(),
2041 EncodeBase58(&rand_pwd[0],&rand_pwd[0]+32).c_str());
2042 CreateThread(Shutdown, NULL);
2046 bool fUseSSL = GetBoolArg("-rpcssl");
2047 asio::ip::address bindAddress = mapArgs.count("-rpcallowip") ? asio::ip::address_v4::any() : asio::ip::address_v4::loopback();
2049 asio::io_service io_service;
2050 ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", 8332));
2051 ip::tcp::acceptor acceptor(io_service, endpoint);
2053 acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
2056 ssl::context context(io_service, ssl::context::sslv23);
2059 context.set_options(ssl::context::no_sslv2);
2060 filesystem::path certfile = GetArg("-rpcsslcertificatechainfile", "server.cert");
2061 if (!certfile.is_complete()) certfile = filesystem::path(GetDataDir()) / certfile;
2062 if (filesystem::exists(certfile)) context.use_certificate_chain_file(certfile.string().c_str());
2063 else printf("ThreadRPCServer ERROR: missing server certificate file %s\n", certfile.string().c_str());
2064 filesystem::path pkfile = GetArg("-rpcsslprivatekeyfile", "server.pem");
2065 if (!pkfile.is_complete()) pkfile = filesystem::path(GetDataDir()) / pkfile;
2066 if (filesystem::exists(pkfile)) context.use_private_key_file(pkfile.string().c_str(), ssl::context::pem);
2067 else printf("ThreadRPCServer ERROR: missing server private key file %s\n", pkfile.string().c_str());
2069 string ciphers = GetArg("-rpcsslciphers",
2070 "TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH");
2071 SSL_CTX_set_cipher_list(context.impl(), ciphers.c_str());
2075 throw runtime_error("-rpcssl=1, but bitcoin compiled without full openssl libraries.");
2080 // Accept connection
2082 SSLStream sslStream(io_service, context);
2083 SSLIOStreamDevice d(sslStream, fUseSSL);
2084 iostreams::stream<SSLIOStreamDevice> stream(d);
2086 ip::tcp::iostream stream;
2089 ip::tcp::endpoint peer;
2090 vnThreadsRunning[4]--;
2092 acceptor.accept(sslStream.lowest_layer(), peer);
2094 acceptor.accept(*stream.rdbuf(), peer);
2096 vnThreadsRunning[4]++;
2100 // Restrict callers by IP
2101 if (!ClientAllowed(peer.address().to_string()))
2103 // Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake.
2105 stream << HTTPReply(403, "") << std::flush;
2109 map<string, string> mapHeaders;
2112 boost::thread api_caller(ReadHTTP, boost::ref(stream), boost::ref(mapHeaders), boost::ref(strRequest));
2113 if (!api_caller.timed_join(boost::posix_time::seconds(GetArg("-rpctimeout", 30))))
2116 printf("ThreadRPCServer ReadHTTP timeout\n");
2120 // Check authorization
2121 if (mapHeaders.count("authorization") == 0)
2123 stream << HTTPReply(401, "") << std::flush;
2126 if (!HTTPAuthorized(mapHeaders))
2128 printf("ThreadRPCServer incorrect password attempt from %s\n",peer.address().to_string().c_str());
2129 /* Deter brute-forcing short passwords.
2130 If this results in a DOS the user really
2131 shouldn't have their RPC port exposed.*/
2132 if (mapArgs["-rpcpassword"].size() < 20)
2135 stream << HTTPReply(401, "") << std::flush;
2139 Value id = Value::null;
2144 if (!read_string(strRequest, valRequest) || valRequest.type() != obj_type)
2145 throw JSONRPCError(-32700, "Parse error");
2146 const Object& request = valRequest.get_obj();
2148 // Parse id now so errors from here on will have the id
2149 id = find_value(request, "id");
2152 Value valMethod = find_value(request, "method");
2153 if (valMethod.type() == null_type)
2154 throw JSONRPCError(-32600, "Missing method");
2155 if (valMethod.type() != str_type)
2156 throw JSONRPCError(-32600, "Method must be a string");
2157 string strMethod = valMethod.get_str();
2158 if (strMethod != "getwork")
2159 printf("ThreadRPCServer method=%s\n", strMethod.c_str());
2162 Value valParams = find_value(request, "params");
2164 if (valParams.type() == array_type)
2165 params = valParams.get_array();
2166 else if (valParams.type() == null_type)
2169 throw JSONRPCError(-32600, "Params must be an array");
2172 map<string, rpcfn_type>::iterator mi = mapCallTable.find(strMethod);
2173 if (mi == mapCallTable.end())
2174 throw JSONRPCError(-32601, "Method not found");
2176 // Observe safe mode
2177 string strWarning = GetWarnings("rpc");
2178 if (strWarning != "" && !GetBoolArg("-disablesafemode") && !setAllowInSafeMode.count(strMethod))
2179 throw JSONRPCError(-2, string("Safe mode: ") + strWarning);
2185 CRITICAL_BLOCK(cs_main)
2186 CRITICAL_BLOCK(pwalletMain->cs_wallet)
2187 result = (*(*mi).second)(params, false);
2190 string strReply = JSONRPCReply(result, Value::null, id);
2191 stream << HTTPReply(200, strReply) << std::flush;
2193 catch (std::exception& e)
2195 ErrorReply(stream, JSONRPCError(-1, e.what()), id);
2198 catch (Object& objError)
2200 ErrorReply(stream, objError, id);
2202 catch (std::exception& e)
2204 ErrorReply(stream, JSONRPCError(-32700, e.what()), id);
2212 Object CallRPC(const string& strMethod, const Array& params)
2214 if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
2215 throw runtime_error(strprintf(
2216 _("You must set rpcpassword=<password> in the configuration file:\n%s\n"
2217 "If the file does not exist, create it with owner-readable-only file permissions."),
2218 GetConfigFile().c_str()));
2220 // Connect to localhost
2221 bool fUseSSL = GetBoolArg("-rpcssl");
2223 asio::io_service io_service;
2224 ssl::context context(io_service, ssl::context::sslv23);
2225 context.set_options(ssl::context::no_sslv2);
2226 SSLStream sslStream(io_service, context);
2227 SSLIOStreamDevice d(sslStream, fUseSSL);
2228 iostreams::stream<SSLIOStreamDevice> stream(d);
2229 if (!d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332")))
2230 throw runtime_error("couldn't connect to server");
2233 throw runtime_error("-rpcssl=1, but bitcoin compiled without full openssl libraries.");
2235 ip::tcp::iostream stream(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332"));
2237 throw runtime_error("couldn't connect to server");
2241 // HTTP basic authentication
2242 string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
2243 map<string, string> mapRequestHeaders;
2244 mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64;
2247 string strRequest = JSONRPCRequest(strMethod, params, 1);
2248 string strPost = HTTPPost(strRequest, mapRequestHeaders);
2249 stream << strPost << std::flush;
2252 map<string, string> mapHeaders;
2254 int nStatus = ReadHTTP(stream, mapHeaders, strReply);
2256 throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
2257 else if (nStatus >= 400 && nStatus != 400 && nStatus != 404 && nStatus != 500)
2258 throw runtime_error(strprintf("server returned HTTP error %d", nStatus));
2259 else if (strReply.empty())
2260 throw runtime_error("no response from server");
2264 if (!read_string(strReply, valReply))
2265 throw runtime_error("couldn't parse reply from server");
2266 const Object& reply = valReply.get_obj();
2268 throw runtime_error("expected reply to have result, error and id properties");
2276 template<typename T>
2277 void ConvertTo(Value& value)
2279 if (value.type() == str_type)
2281 // reinterpret string as unquoted json value
2283 if (!read_string(value.get_str(), value2))
2284 throw runtime_error("type mismatch");
2285 value = value2.get_value<T>();
2289 value = value.get_value<T>();
2293 int CommandLineRPC(int argc, char *argv[])
2300 while (argc > 1 && IsSwitchChar(argv[1][0]))
2308 throw runtime_error("too few parameters");
2309 string strMethod = argv[1];
2311 // Parameters default to strings
2313 for (int i = 2; i < argc; i++)
2314 params.push_back(argv[i]);
2315 int n = params.size();
2318 // Special case non-string parameter types
2320 if (strMethod == "setgenerate" && n > 0) ConvertTo<bool>(params[0]);
2321 if (strMethod == "setgenerate" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2322 if (strMethod == "sendtoaddress" && n > 1) ConvertTo<double>(params[1]);
2323 if (strMethod == "settxfee" && n > 0) ConvertTo<double>(params[0]);
2324 if (strMethod == "getamountreceived" && n > 1) ConvertTo<boost::int64_t>(params[1]); // deprecated
2325 if (strMethod == "getreceivedbyaddress" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2326 if (strMethod == "getreceivedbyaccount" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2327 if (strMethod == "getreceivedbylabel" && n > 1) ConvertTo<boost::int64_t>(params[1]); // deprecated
2328 if (strMethod == "getallreceived" && n > 0) ConvertTo<boost::int64_t>(params[0]); // deprecated
2329 if (strMethod == "getallreceived" && n > 1) ConvertTo<bool>(params[1]); // deprecated
2330 if (strMethod == "listreceivedbyaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2331 if (strMethod == "listreceivedbyaddress" && n > 1) ConvertTo<bool>(params[1]);
2332 if (strMethod == "listreceivedbyaccount" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2333 if (strMethod == "listreceivedbyaccount" && n > 1) ConvertTo<bool>(params[1]);
2334 if (strMethod == "listreceivedbylabel" && n > 0) ConvertTo<boost::int64_t>(params[0]); // deprecated
2335 if (strMethod == "listreceivedbylabel" && n > 1) ConvertTo<bool>(params[1]); // deprecated
2336 if (strMethod == "getbalance" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2337 if (strMethod == "move" && n > 2) ConvertTo<double>(params[2]);
2338 if (strMethod == "move" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2339 if (strMethod == "sendfrom" && n > 2) ConvertTo<double>(params[2]);
2340 if (strMethod == "sendfrom" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2341 if (strMethod == "listtransactions" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2342 if (strMethod == "listtransactions" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2343 if (strMethod == "listaccounts" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2344 if (strMethod == "walletpassphrase" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2345 if (strMethod == "sendmany" && n > 1)
2347 string s = params[1].get_str();
2349 if (!read_string(s, v) || v.type() != obj_type)
2350 throw runtime_error("type mismatch");
2351 params[1] = v.get_obj();
2353 if (strMethod == "sendmany" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2356 Object reply = CallRPC(strMethod, params);
2359 const Value& result = find_value(reply, "result");
2360 const Value& error = find_value(reply, "error");
2362 if (error.type() != null_type)
2365 strPrint = "error: " + write_string(error, false);
2366 int code = find_value(error.get_obj(), "code").get_int();
2372 if (result.type() == null_type)
2374 else if (result.type() == str_type)
2375 strPrint = result.get_str();
2377 strPrint = write_string(result, true);
2380 catch (std::exception& e)
2382 strPrint = string("error: ") + e.what();
2387 PrintException(NULL, "CommandLineRPC()");
2392 #if defined(__WXMSW__) && defined(GUI)
2393 // Windows GUI apps can't print to command line,
2394 // so settle for a message box yuck
2395 MyMessageBox(strPrint, "Bitcoin", wxOK);
2397 fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
2407 int main(int argc, char *argv[])
2410 // Turn off microsoft heap dump noise
2411 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
2412 _CrtSetReportFile(_CRT_WARN, CreateFile("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0));
2414 setbuf(stdin, NULL);
2415 setbuf(stdout, NULL);
2416 setbuf(stderr, NULL);
2420 if (argc >= 2 && string(argv[1]) == "-server")
2422 printf("server ready\n");
2423 ThreadRPCServer(NULL);
2427 return CommandLineRPC(argc, argv);
2430 catch (std::exception& e) {
2431 PrintException(&e, "main()");
2433 PrintException(NULL, "main()");