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);
728 int64 nNow = GetAdjustedTime();
731 CAccountingEntry debit;
732 debit.strAccount = strFrom;
733 debit.nCreditDebit = -nAmount;
735 debit.strOtherAccount = strTo;
736 debit.strComment = strComment;
737 walletdb.WriteAccountingEntry(debit);
740 CAccountingEntry credit;
741 credit.strAccount = strTo;
742 credit.nCreditDebit = nAmount;
744 credit.strOtherAccount = strFrom;
745 credit.strComment = strComment;
746 walletdb.WriteAccountingEntry(credit);
748 walletdb.TxnCommit();
754 Value sendfrom(const Array& params, bool fHelp)
756 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
758 "sendfrom <fromaccount> <tobitcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
759 "<amount> is a real and is rounded to the nearest 0.00000001\n"
760 "requires wallet passphrase to be set with walletpassphrase first");
761 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
763 "sendfrom <fromaccount> <tobitcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
764 "<amount> is a real and is rounded to the nearest 0.00000001");
766 string strAccount = AccountFromValue(params[0]);
767 CBitcoinAddress address(params[1].get_str());
768 if (!address.IsValid())
769 throw JSONRPCError(-5, "Invalid bitcoin address");
770 int64 nAmount = AmountFromValue(params[2]);
772 if (params.size() > 3)
773 nMinDepth = params[3].get_int();
776 wtx.strFromAccount = strAccount;
777 if (params.size() > 4 && params[4].type() != null_type && !params[4].get_str().empty())
778 wtx.mapValue["comment"] = params[4].get_str();
779 if (params.size() > 5 && params[5].type() != null_type && !params[5].get_str().empty())
780 wtx.mapValue["to"] = params[5].get_str();
782 if (pwalletMain->IsLocked())
783 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
786 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
787 if (nAmount > nBalance)
788 throw JSONRPCError(-6, "Account has insufficient funds");
791 string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
793 throw JSONRPCError(-4, strError);
795 return wtx.GetHash().GetHex();
799 Value sendmany(const Array& params, bool fHelp)
801 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
803 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
804 "amounts are double-precision floating point numbers\n"
805 "requires wallet passphrase to be set with walletpassphrase first");
806 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
808 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
809 "amounts are double-precision floating point numbers");
811 string strAccount = AccountFromValue(params[0]);
812 Object sendTo = params[1].get_obj();
814 if (params.size() > 2)
815 nMinDepth = params[2].get_int();
818 wtx.strFromAccount = strAccount;
819 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
820 wtx.mapValue["comment"] = params[3].get_str();
822 set<CBitcoinAddress> setAddress;
823 vector<pair<CScript, int64> > vecSend;
825 int64 totalAmount = 0;
826 BOOST_FOREACH(const Pair& s, sendTo)
828 CBitcoinAddress address(s.name_);
829 if (!address.IsValid())
830 throw JSONRPCError(-5, string("Invalid bitcoin address:")+s.name_);
832 if (setAddress.count(address))
833 throw JSONRPCError(-8, string("Invalid parameter, duplicated address: ")+s.name_);
834 setAddress.insert(address);
836 CScript scriptPubKey;
837 scriptPubKey.SetBitcoinAddress(address);
838 int64 nAmount = AmountFromValue(s.value_);
839 totalAmount += nAmount;
841 vecSend.push_back(make_pair(scriptPubKey, nAmount));
844 if (pwalletMain->IsLocked())
845 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
848 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
849 if (totalAmount > nBalance)
850 throw JSONRPCError(-6, "Account has insufficient funds");
853 CReserveKey keyChange(pwalletMain);
854 int64 nFeeRequired = 0;
855 bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired);
858 if (totalAmount + nFeeRequired > pwalletMain->GetBalance())
859 throw JSONRPCError(-6, "Insufficient funds");
860 throw JSONRPCError(-4, "Transaction creation failed");
862 if (!pwalletMain->CommitTransaction(wtx, keyChange))
863 throw JSONRPCError(-4, "Transaction commit failed");
865 return wtx.GetHash().GetHex();
880 Value ListReceived(const Array& params, bool fByAccounts)
882 // Minimum confirmations
884 if (params.size() > 0)
885 nMinDepth = params[0].get_int();
887 // Whether to include empty accounts
888 bool fIncludeEmpty = false;
889 if (params.size() > 1)
890 fIncludeEmpty = params[1].get_bool();
893 map<CBitcoinAddress, tallyitem> mapTally;
894 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
896 const CWalletTx& wtx = (*it).second;
897 if (wtx.IsCoinBase() || !wtx.IsFinal())
900 int nDepth = wtx.GetDepthInMainChain();
901 if (nDepth < nMinDepth)
904 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
906 CBitcoinAddress address;
907 if (!ExtractAddress(txout.scriptPubKey, pwalletMain, address) || !address.IsValid())
910 tallyitem& item = mapTally[address];
911 item.nAmount += txout.nValue;
912 item.nConf = min(item.nConf, nDepth);
918 map<string, tallyitem> mapAccountTally;
919 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
921 const CBitcoinAddress& address = item.first;
922 const string& strAccount = item.second;
923 map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
924 if (it == mapTally.end() && !fIncludeEmpty)
929 if (it != mapTally.end())
931 nAmount = (*it).second.nAmount;
932 nConf = (*it).second.nConf;
937 tallyitem& item = mapAccountTally[strAccount];
938 item.nAmount += nAmount;
939 item.nConf = min(item.nConf, nConf);
944 obj.push_back(Pair("address", address.ToString()));
945 obj.push_back(Pair("account", strAccount));
946 obj.push_back(Pair("label", strAccount)); // deprecated
947 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
948 obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf)));
955 for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
957 int64 nAmount = (*it).second.nAmount;
958 int nConf = (*it).second.nConf;
960 obj.push_back(Pair("account", (*it).first));
961 obj.push_back(Pair("label", (*it).first)); // deprecated
962 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
963 obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf)));
971 Value listreceivedbyaddress(const Array& params, bool fHelp)
973 if (fHelp || params.size() > 2)
975 "listreceivedbyaddress [minconf=1] [includeempty=false]\n"
976 "[minconf] is the minimum number of confirmations before payments are included.\n"
977 "[includeempty] whether to include addresses that haven't received any payments.\n"
978 "Returns an array of objects containing:\n"
979 " \"address\" : receiving address\n"
980 " \"account\" : the account of the receiving address\n"
981 " \"amount\" : total amount received by the address\n"
982 " \"confirmations\" : number of confirmations of the most recent transaction included");
984 return ListReceived(params, false);
987 Value listreceivedbyaccount(const Array& params, bool fHelp)
989 if (fHelp || params.size() > 2)
991 "listreceivedbyaccount [minconf=1] [includeempty=false]\n"
992 "[minconf] is the minimum number of confirmations before payments are included.\n"
993 "[includeempty] whether to include accounts that haven't received any payments.\n"
994 "Returns an array of objects containing:\n"
995 " \"account\" : the account of the receiving addresses\n"
996 " \"amount\" : total amount received by addresses with this account\n"
997 " \"confirmations\" : number of confirmations of the most recent transaction included");
999 return ListReceived(params, true);
1002 void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret)
1004 int64 nGeneratedImmature, nGeneratedMature, nFee;
1005 string strSentAccount;
1006 list<pair<CBitcoinAddress, int64> > listReceived;
1007 list<pair<CBitcoinAddress, int64> > listSent;
1008 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1010 bool fAllAccounts = (strAccount == string("*"));
1012 // Generated blocks assigned to account ""
1013 if ((nGeneratedMature+nGeneratedImmature) != 0 && (fAllAccounts || strAccount == ""))
1016 entry.push_back(Pair("account", string("")));
1017 if (nGeneratedImmature)
1019 entry.push_back(Pair("category", wtx.GetDepthInMainChain() ? "immature" : "orphan"));
1020 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedImmature)));
1024 entry.push_back(Pair("category", "generate"));
1025 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedMature)));
1028 WalletTxToJSON(wtx, entry);
1029 ret.push_back(entry);
1033 if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
1035 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1038 entry.push_back(Pair("account", strSentAccount));
1039 entry.push_back(Pair("address", s.first.ToString()));
1040 entry.push_back(Pair("category", "send"));
1041 entry.push_back(Pair("amount", ValueFromAmount(-s.second)));
1042 entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
1044 WalletTxToJSON(wtx, entry);
1045 ret.push_back(entry);
1050 if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
1052 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1055 if (pwalletMain->mapAddressBook.count(r.first))
1056 account = pwalletMain->mapAddressBook[r.first];
1057 if (fAllAccounts || (account == strAccount))
1060 entry.push_back(Pair("account", account));
1061 entry.push_back(Pair("address", r.first.ToString()));
1062 entry.push_back(Pair("category", "receive"));
1063 entry.push_back(Pair("amount", ValueFromAmount(r.second)));
1065 WalletTxToJSON(wtx, entry);
1066 ret.push_back(entry);
1072 void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret)
1074 bool fAllAccounts = (strAccount == string("*"));
1076 if (fAllAccounts || acentry.strAccount == strAccount)
1079 entry.push_back(Pair("account", acentry.strAccount));
1080 entry.push_back(Pair("category", "move"));
1081 entry.push_back(Pair("time", (boost::int64_t)acentry.nTime));
1082 entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
1083 entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
1084 entry.push_back(Pair("comment", acentry.strComment));
1085 ret.push_back(entry);
1089 Value listtransactions(const Array& params, bool fHelp)
1091 if (fHelp || params.size() > 3)
1092 throw runtime_error(
1093 "listtransactions [account] [count=10] [from=0]\n"
1094 "Returns up to [count] most recent transactions skipping the first [from] transactions for account [account].");
1096 string strAccount = "*";
1097 if (params.size() > 0)
1098 strAccount = params[0].get_str();
1100 if (params.size() > 1)
1101 nCount = params[1].get_int();
1103 if (params.size() > 2)
1104 nFrom = params[2].get_int();
1107 throw JSONRPCError(-8, "Negative count");
1109 throw JSONRPCError(-8, "Negative from");
1112 CWalletDB walletdb(pwalletMain->strWalletFile);
1114 // First: get all CWalletTx and CAccountingEntry into a sorted-by-time multimap.
1115 typedef pair<CWalletTx*, CAccountingEntry*> TxPair;
1116 typedef multimap<int64, TxPair > TxItems;
1119 // Note: maintaining indices in the database of (account,time) --> txid and (account, time) --> acentry
1120 // would make this much faster for applications that do this a lot.
1121 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1123 CWalletTx* wtx = &((*it).second);
1124 txByTime.insert(make_pair(wtx->GetTxTime(), TxPair(wtx, (CAccountingEntry*)0)));
1126 list<CAccountingEntry> acentries;
1127 walletdb.ListAccountCreditDebit(strAccount, acentries);
1128 BOOST_FOREACH(CAccountingEntry& entry, acentries)
1130 txByTime.insert(make_pair(entry.nTime, TxPair((CWalletTx*)0, &entry)));
1133 // iterate backwards until we have nCount items to return:
1134 for (TxItems::reverse_iterator it = txByTime.rbegin(); it != txByTime.rend(); ++it)
1136 CWalletTx *const pwtx = (*it).second.first;
1138 ListTransactions(*pwtx, strAccount, 0, true, ret);
1139 CAccountingEntry *const pacentry = (*it).second.second;
1141 AcentryToJSON(*pacentry, strAccount, ret);
1143 if (ret.size() >= (nCount+nFrom)) break;
1145 // ret is newest to oldest
1147 if (nFrom > ret.size()) nFrom = ret.size();
1148 if (nFrom+nCount > ret.size()) nCount = ret.size()-nFrom;
1149 Array::iterator first = ret.begin();
1150 std::advance(first, nFrom);
1151 Array::iterator last = ret.begin();
1152 std::advance(last, nFrom+nCount);
1154 if (last != ret.end()) ret.erase(last, ret.end());
1155 if (first != ret.begin()) ret.erase(ret.begin(), first);
1157 std::reverse(ret.begin(), ret.end()); // Return oldest to newest
1162 Value listaccounts(const Array& params, bool fHelp)
1164 if (fHelp || params.size() > 1)
1165 throw runtime_error(
1166 "listaccounts [minconf=1]\n"
1167 "Returns Object that has account names as keys, account balances as values.");
1170 if (params.size() > 0)
1171 nMinDepth = params[0].get_int();
1173 map<string, int64> mapAccountBalances;
1174 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& entry, pwalletMain->mapAddressBook) {
1175 if (pwalletMain->HaveKey(entry.first)) // This address belongs to me
1176 mapAccountBalances[entry.second] = 0;
1179 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1181 const CWalletTx& wtx = (*it).second;
1182 int64 nGeneratedImmature, nGeneratedMature, nFee;
1183 string strSentAccount;
1184 list<pair<CBitcoinAddress, int64> > listReceived;
1185 list<pair<CBitcoinAddress, int64> > listSent;
1186 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1187 mapAccountBalances[strSentAccount] -= nFee;
1188 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1189 mapAccountBalances[strSentAccount] -= s.second;
1190 if (wtx.GetDepthInMainChain() >= nMinDepth)
1192 mapAccountBalances[""] += nGeneratedMature;
1193 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1194 if (pwalletMain->mapAddressBook.count(r.first))
1195 mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second;
1197 mapAccountBalances[""] += r.second;
1201 list<CAccountingEntry> acentries;
1202 CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
1203 BOOST_FOREACH(const CAccountingEntry& entry, acentries)
1204 mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
1207 BOOST_FOREACH(const PAIRTYPE(string, int64)& accountBalance, mapAccountBalances) {
1208 ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
1213 Value gettransaction(const Array& params, bool fHelp)
1215 if (fHelp || params.size() != 1)
1216 throw runtime_error(
1217 "gettransaction <txid>\n"
1218 "Get detailed information about <txid>");
1221 hash.SetHex(params[0].get_str());
1225 if (!pwalletMain->mapWallet.count(hash))
1226 throw JSONRPCError(-5, "Invalid or non-wallet transaction id");
1227 const CWalletTx& wtx = pwalletMain->mapWallet[hash];
1229 int64 nCredit = wtx.GetCredit();
1230 int64 nDebit = wtx.GetDebit();
1231 int64 nNet = nCredit - nDebit;
1232 int64 nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0);
1234 entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
1236 entry.push_back(Pair("fee", ValueFromAmount(nFee)));
1238 WalletTxToJSON(pwalletMain->mapWallet[hash], entry);
1241 ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details);
1242 entry.push_back(Pair("details", details));
1248 Value backupwallet(const Array& params, bool fHelp)
1250 if (fHelp || params.size() != 1)
1251 throw runtime_error(
1252 "backupwallet <destination>\n"
1253 "Safely copies wallet.dat to destination, which can be a directory or a path with filename.");
1255 string strDest = params[0].get_str();
1256 BackupWallet(*pwalletMain, strDest);
1262 Value keypoolrefill(const Array& params, bool fHelp)
1264 if (pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1265 throw runtime_error(
1267 "Fills the keypool, requires wallet passphrase to be set.");
1268 if (!pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1269 throw runtime_error(
1271 "Fills the keypool.");
1273 if (pwalletMain->IsLocked())
1274 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
1276 pwalletMain->TopUpKeyPool();
1278 if (pwalletMain->GetKeyPoolSize() < GetArg("-keypool", 100))
1279 throw JSONRPCError(-4, "Error refreshing keypool.");
1285 void ThreadTopUpKeyPool(void* parg)
1287 pwalletMain->TopUpKeyPool();
1290 void ThreadCleanWalletPassphrase(void* parg)
1292 int64 nMyWakeTime = GetTimeMillis() + *((int64*)parg) * 1000;
1294 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1296 if (nWalletUnlockTime == 0)
1298 nWalletUnlockTime = nMyWakeTime;
1302 if (nWalletUnlockTime==0)
1304 int64 nToSleep = nWalletUnlockTime - GetTimeMillis();
1308 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1310 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1314 if (nWalletUnlockTime)
1316 nWalletUnlockTime = 0;
1317 pwalletMain->Lock();
1322 if (nWalletUnlockTime < nMyWakeTime)
1323 nWalletUnlockTime = nMyWakeTime;
1326 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1328 delete (int64*)parg;
1331 Value walletpassphrase(const Array& params, bool fHelp)
1333 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1334 throw runtime_error(
1335 "walletpassphrase <passphrase> <timeout>\n"
1336 "Stores the wallet decryption key in memory for <timeout> seconds.");
1339 if (!pwalletMain->IsCrypted())
1340 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
1342 if (!pwalletMain->IsLocked())
1343 throw JSONRPCError(-17, "Error: Wallet is already unlocked.");
1345 // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
1346 string strWalletPass;
1347 strWalletPass.reserve(100);
1348 mlock(&strWalletPass[0], strWalletPass.capacity());
1349 strWalletPass = params[0].get_str();
1351 if (strWalletPass.length() > 0)
1353 if (!pwalletMain->Unlock(strWalletPass))
1355 fill(strWalletPass.begin(), strWalletPass.end(), '\0');
1356 munlock(&strWalletPass[0], strWalletPass.capacity());
1357 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1359 fill(strWalletPass.begin(), strWalletPass.end(), '\0');
1360 munlock(&strWalletPass[0], strWalletPass.capacity());
1363 throw runtime_error(
1364 "walletpassphrase <passphrase> <timeout>\n"
1365 "Stores the wallet decryption key in memory for <timeout> seconds.");
1367 CreateThread(ThreadTopUpKeyPool, NULL);
1368 int64* pnSleepTime = new int64(params[1].get_int64());
1369 CreateThread(ThreadCleanWalletPassphrase, pnSleepTime);
1375 Value walletpassphrasechange(const Array& params, bool fHelp)
1377 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1378 throw runtime_error(
1379 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1380 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1383 if (!pwalletMain->IsCrypted())
1384 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
1386 string strOldWalletPass;
1387 strOldWalletPass.reserve(100);
1388 mlock(&strOldWalletPass[0], strOldWalletPass.capacity());
1389 strOldWalletPass = params[0].get_str();
1391 string strNewWalletPass;
1392 strNewWalletPass.reserve(100);
1393 mlock(&strNewWalletPass[0], strNewWalletPass.capacity());
1394 strNewWalletPass = params[1].get_str();
1396 if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
1397 throw runtime_error(
1398 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1399 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1401 if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
1403 fill(strOldWalletPass.begin(), strOldWalletPass.end(), '\0');
1404 fill(strNewWalletPass.begin(), strNewWalletPass.end(), '\0');
1405 munlock(&strOldWalletPass[0], strOldWalletPass.capacity());
1406 munlock(&strNewWalletPass[0], strNewWalletPass.capacity());
1407 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1409 fill(strNewWalletPass.begin(), strNewWalletPass.end(), '\0');
1410 fill(strOldWalletPass.begin(), strOldWalletPass.end(), '\0');
1411 munlock(&strOldWalletPass[0], strOldWalletPass.capacity());
1412 munlock(&strNewWalletPass[0], strNewWalletPass.capacity());
1418 Value walletlock(const Array& params, bool fHelp)
1420 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
1421 throw runtime_error(
1423 "Removes the wallet encryption key from memory, locking the wallet.\n"
1424 "After calling this method, you will need to call walletpassphrase again\n"
1425 "before being able to call any methods which require the wallet to be unlocked.");
1428 if (!pwalletMain->IsCrypted())
1429 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletlock was called.");
1431 CRITICAL_BLOCK(cs_nWalletUnlockTime)
1433 pwalletMain->Lock();
1434 nWalletUnlockTime = 0;
1441 Value encryptwallet(const Array& params, bool fHelp)
1443 if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
1444 throw runtime_error(
1445 "encryptwallet <passphrase>\n"
1446 "Encrypts the wallet with <passphrase>.");
1449 if (pwalletMain->IsCrypted())
1450 throw JSONRPCError(-15, "Error: running with an encrypted wallet, but encryptwallet was called.");
1453 // shutting down via RPC while the GUI is running does not work (yet):
1454 throw runtime_error("Not Yet Implemented: use GUI to encrypt wallet, not RPC command");
1457 string strWalletPass;
1458 strWalletPass.reserve(100);
1459 mlock(&strWalletPass[0], strWalletPass.capacity());
1460 strWalletPass = params[0].get_str();
1462 if (strWalletPass.length() < 1)
1463 throw runtime_error(
1464 "encryptwallet <passphrase>\n"
1465 "Encrypts the wallet with <passphrase>.");
1467 if (!pwalletMain->EncryptWallet(strWalletPass))
1469 fill(strWalletPass.begin(), strWalletPass.end(), '\0');
1470 munlock(&strWalletPass[0], strWalletPass.capacity());
1471 throw JSONRPCError(-16, "Error: Failed to encrypt the wallet.");
1473 fill(strWalletPass.begin(), strWalletPass.end(), '\0');
1474 munlock(&strWalletPass[0], strWalletPass.capacity());
1476 // BDB seems to have a bad habit of writing old data into
1477 // slack space in .dat files; that is bad if the old data is
1478 // unencrypted private keys. So:
1479 CreateThread(Shutdown, NULL);
1480 return "wallet encrypted; bitcoin server stopping, restart to run with encrypted wallet";
1484 Value validateaddress(const Array& params, bool fHelp)
1486 if (fHelp || params.size() != 1)
1487 throw runtime_error(
1488 "validateaddress <bitcoinaddress>\n"
1489 "Return information about <bitcoinaddress>.");
1491 CBitcoinAddress address(params[0].get_str());
1492 bool isValid = address.IsValid();
1495 ret.push_back(Pair("isvalid", isValid));
1498 // Call Hash160ToAddress() so we always return current ADDRESSVERSION
1499 // version of the address:
1500 string currentAddress = address.ToString();
1501 ret.push_back(Pair("address", currentAddress));
1502 ret.push_back(Pair("ismine", (pwalletMain->HaveKey(address) > 0)));
1503 if (pwalletMain->mapAddressBook.count(address))
1504 ret.push_back(Pair("account", pwalletMain->mapAddressBook[address]));
1510 Value getwork(const Array& params, bool fHelp)
1512 if (fHelp || params.size() > 1)
1513 throw runtime_error(
1515 "If [data] is not specified, returns formatted hash data to work on:\n"
1516 " \"midstate\" : precomputed hash state after hashing the first half of the data\n"
1517 " \"data\" : block data\n"
1518 " \"hash1\" : formatted hash buffer for second hash\n"
1519 " \"target\" : little endian hash target\n"
1520 "If [data] is specified, tries to solve the block and returns true if it was successful.");
1523 throw JSONRPCError(-9, "Bitcoin is not connected!");
1525 if (IsInitialBlockDownload())
1526 throw JSONRPCError(-10, "Bitcoin is downloading blocks...");
1528 typedef map<uint256, pair<CBlock*, CScript> > mapNewBlock_t;
1529 static mapNewBlock_t mapNewBlock;
1530 static vector<CBlock*> vNewBlock;
1531 static CReserveKey reservekey(pwalletMain);
1533 if (params.size() == 0)
1536 static unsigned int nTransactionsUpdatedLast;
1537 static CBlockIndex* pindexPrev;
1538 static int64 nStart;
1539 static CBlock* pblock;
1540 if (pindexPrev != pindexBest ||
1541 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60))
1543 if (pindexPrev != pindexBest)
1545 // Deallocate old blocks since they're obsolete now
1546 mapNewBlock.clear();
1547 BOOST_FOREACH(CBlock* pblock, vNewBlock)
1551 nTransactionsUpdatedLast = nTransactionsUpdated;
1552 pindexPrev = pindexBest;
1556 pblock = CreateNewBlock(reservekey);
1558 throw JSONRPCError(-7, "Out of memory");
1559 vNewBlock.push_back(pblock);
1563 pblock->UpdateTime(pindexPrev);
1566 // Update nExtraNonce
1567 static unsigned int nExtraNonce = 0;
1568 IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
1571 mapNewBlock[pblock->hashMerkleRoot] = make_pair(pblock, pblock->vtx[0].vin[0].scriptSig);
1573 // Prebuild hash buffers
1577 FormatHashBuffers(pblock, pmidstate, pdata, phash1);
1579 uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
1582 result.push_back(Pair("midstate", HexStr(BEGIN(pmidstate), END(pmidstate))));
1583 result.push_back(Pair("data", HexStr(BEGIN(pdata), END(pdata))));
1584 result.push_back(Pair("hash1", HexStr(BEGIN(phash1), END(phash1))));
1585 result.push_back(Pair("target", HexStr(BEGIN(hashTarget), END(hashTarget))));
1591 vector<unsigned char> vchData = ParseHex(params[0].get_str());
1592 if (vchData.size() != 128)
1593 throw JSONRPCError(-8, "Invalid parameter");
1594 CBlock* pdata = (CBlock*)&vchData[0];
1597 for (int i = 0; i < 128/4; i++)
1598 ((unsigned int*)pdata)[i] = CryptoPP::ByteReverse(((unsigned int*)pdata)[i]);
1601 if (!mapNewBlock.count(pdata->hashMerkleRoot))
1603 CBlock* pblock = mapNewBlock[pdata->hashMerkleRoot].first;
1605 pblock->nTime = pdata->nTime;
1606 pblock->nNonce = pdata->nNonce;
1607 pblock->vtx[0].vin[0].scriptSig = mapNewBlock[pdata->hashMerkleRoot].second;
1608 pblock->hashMerkleRoot = pblock->BuildMerkleTree();
1610 return CheckWork(pblock, *pwalletMain, reservekey);
1628 pair<string, rpcfn_type> pCallTable[] =
1630 make_pair("help", &help),
1631 make_pair("stop", &stop),
1632 make_pair("getblockcount", &getblockcount),
1633 make_pair("getblocknumber", &getblocknumber),
1634 make_pair("getconnectioncount", &getconnectioncount),
1635 make_pair("getdifficulty", &getdifficulty),
1636 make_pair("getgenerate", &getgenerate),
1637 make_pair("setgenerate", &setgenerate),
1638 make_pair("gethashespersec", &gethashespersec),
1639 make_pair("getinfo", &getinfo),
1640 make_pair("getnewaddress", &getnewaddress),
1641 make_pair("getaccountaddress", &getaccountaddress),
1642 make_pair("setaccount", &setaccount),
1643 make_pair("setlabel", &setaccount), // deprecated
1644 make_pair("getaccount", &getaccount),
1645 make_pair("getlabel", &getaccount), // deprecated
1646 make_pair("getaddressesbyaccount", &getaddressesbyaccount),
1647 make_pair("getaddressesbylabel", &getaddressesbyaccount), // deprecated
1648 make_pair("sendtoaddress", &sendtoaddress),
1649 make_pair("getamountreceived", &getreceivedbyaddress), // deprecated, renamed to getreceivedbyaddress
1650 make_pair("getallreceived", &listreceivedbyaddress), // deprecated, renamed to listreceivedbyaddress
1651 make_pair("getreceivedbyaddress", &getreceivedbyaddress),
1652 make_pair("getreceivedbyaccount", &getreceivedbyaccount),
1653 make_pair("getreceivedbylabel", &getreceivedbyaccount), // deprecated
1654 make_pair("listreceivedbyaddress", &listreceivedbyaddress),
1655 make_pair("listreceivedbyaccount", &listreceivedbyaccount),
1656 make_pair("listreceivedbylabel", &listreceivedbyaccount), // deprecated
1657 make_pair("backupwallet", &backupwallet),
1658 make_pair("keypoolrefill", &keypoolrefill),
1659 make_pair("walletpassphrase", &walletpassphrase),
1660 make_pair("walletpassphrasechange", &walletpassphrasechange),
1661 make_pair("walletlock", &walletlock),
1662 make_pair("encryptwallet", &encryptwallet),
1663 make_pair("validateaddress", &validateaddress),
1664 make_pair("getbalance", &getbalance),
1665 make_pair("move", &movecmd),
1666 make_pair("sendfrom", &sendfrom),
1667 make_pair("sendmany", &sendmany),
1668 make_pair("gettransaction", &gettransaction),
1669 make_pair("listtransactions", &listtransactions),
1670 make_pair("getwork", &getwork),
1671 make_pair("listaccounts", &listaccounts),
1672 make_pair("settxfee", &settxfee),
1674 map<string, rpcfn_type> mapCallTable(pCallTable, pCallTable + sizeof(pCallTable)/sizeof(pCallTable[0]));
1676 string pAllowInSafeMode[] =
1682 "getconnectioncount",
1689 "getaccountaddress",
1690 "setlabel", // deprecated
1692 "getlabel", // deprecated
1693 "getaddressesbyaccount",
1694 "getaddressesbylabel", // deprecated
1702 set<string> setAllowInSafeMode(pAllowInSafeMode, pAllowInSafeMode + sizeof(pAllowInSafeMode)/sizeof(pAllowInSafeMode[0]));
1710 // This ain't Apache. We're just using HTTP header for the length field
1711 // and to be compatible with other JSON-RPC implementations.
1714 string HTTPPost(const string& strMsg, const map<string,string>& mapRequestHeaders)
1717 s << "POST / HTTP/1.1\r\n"
1718 << "User-Agent: bitcoin-json-rpc/" << FormatFullVersion() << "\r\n"
1719 << "Host: 127.0.0.1\r\n"
1720 << "Content-Type: application/json\r\n"
1721 << "Content-Length: " << strMsg.size() << "\r\n"
1722 << "Accept: application/json\r\n";
1723 BOOST_FOREACH(const PAIRTYPE(string, string)& item, mapRequestHeaders)
1724 s << item.first << ": " << item.second << "\r\n";
1725 s << "\r\n" << strMsg;
1730 string rfc1123Time()
1735 struct tm* now_gmt = gmtime(&now);
1736 string locale(setlocale(LC_TIME, NULL));
1737 setlocale(LC_TIME, "C"); // we want posix (aka "C") weekday/month strings
1738 strftime(buffer, sizeof(buffer), "%a, %d %b %Y %H:%M:%S +0000", now_gmt);
1739 setlocale(LC_TIME, locale.c_str());
1740 return string(buffer);
1743 static string HTTPReply(int nStatus, const string& strMsg)
1746 return strprintf("HTTP/1.0 401 Authorization Required\r\n"
1748 "Server: bitcoin-json-rpc/%s\r\n"
1749 "WWW-Authenticate: Basic realm=\"jsonrpc\"\r\n"
1750 "Content-Type: text/html\r\n"
1751 "Content-Length: 296\r\n"
1753 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\r\n"
1754 "\"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd\">\r\n"
1757 "<TITLE>Error</TITLE>\r\n"
1758 "<META HTTP-EQUIV='Content-Type' CONTENT='text/html; charset=ISO-8859-1'>\r\n"
1760 "<BODY><H1>401 Unauthorized.</H1></BODY>\r\n"
1761 "</HTML>\r\n", rfc1123Time().c_str(), FormatFullVersion().c_str());
1763 if (nStatus == 200) strStatus = "OK";
1764 else if (nStatus == 400) strStatus = "Bad Request";
1765 else if (nStatus == 403) strStatus = "Forbidden";
1766 else if (nStatus == 404) strStatus = "Not Found";
1767 else if (nStatus == 500) strStatus = "Internal Server Error";
1769 "HTTP/1.1 %d %s\r\n"
1771 "Connection: close\r\n"
1772 "Content-Length: %d\r\n"
1773 "Content-Type: application/json\r\n"
1774 "Server: bitcoin-json-rpc/%s\r\n"
1779 rfc1123Time().c_str(),
1781 FormatFullVersion().c_str(),
1785 int ReadHTTPStatus(std::basic_istream<char>& stream)
1788 getline(stream, str);
1789 vector<string> vWords;
1790 boost::split(vWords, str, boost::is_any_of(" "));
1791 if (vWords.size() < 2)
1793 return atoi(vWords[1].c_str());
1796 int ReadHTTPHeader(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet)
1802 std::getline(stream, str);
1803 if (str.empty() || str == "\r")
1805 string::size_type nColon = str.find(":");
1806 if (nColon != string::npos)
1808 string strHeader = str.substr(0, nColon);
1809 boost::trim(strHeader);
1810 boost::to_lower(strHeader);
1811 string strValue = str.substr(nColon+1);
1812 boost::trim(strValue);
1813 mapHeadersRet[strHeader] = strValue;
1814 if (strHeader == "content-length")
1815 nLen = atoi(strValue.c_str());
1821 int ReadHTTP(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet, string& strMessageRet)
1823 mapHeadersRet.clear();
1827 int nStatus = ReadHTTPStatus(stream);
1830 int nLen = ReadHTTPHeader(stream, mapHeadersRet);
1831 if (nLen < 0 || nLen > MAX_SIZE)
1837 vector<char> vch(nLen);
1838 stream.read(&vch[0], nLen);
1839 strMessageRet = string(vch.begin(), vch.end());
1845 string EncodeBase64(string s)
1850 b64 = BIO_new(BIO_f_base64());
1851 BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
1852 bmem = BIO_new(BIO_s_mem());
1853 b64 = BIO_push(b64, bmem);
1854 BIO_write(b64, s.c_str(), s.size());
1856 BIO_get_mem_ptr(b64, &bptr);
1858 string result(bptr->data, bptr->length);
1864 string DecodeBase64(string s)
1868 char* buffer = static_cast<char*>(calloc(s.size(), sizeof(char)));
1870 b64 = BIO_new(BIO_f_base64());
1871 BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
1872 bmem = BIO_new_mem_buf(const_cast<char*>(s.c_str()), s.size());
1873 bmem = BIO_push(b64, bmem);
1874 BIO_read(bmem, buffer, s.size());
1877 string result(buffer);
1882 bool HTTPAuthorized(map<string, string>& mapHeaders)
1884 string strAuth = mapHeaders["authorization"];
1885 if (strAuth.substr(0,6) != "Basic ")
1887 string strUserPass64 = strAuth.substr(6); boost::trim(strUserPass64);
1888 string strUserPass = DecodeBase64(strUserPass64);
1889 string::size_type nColon = strUserPass.find(":");
1890 if (nColon == string::npos)
1892 string strUser = strUserPass.substr(0, nColon);
1893 string strPassword = strUserPass.substr(nColon+1);
1894 return (strUser == mapArgs["-rpcuser"] && strPassword == mapArgs["-rpcpassword"]);
1898 // JSON-RPC protocol. Bitcoin speaks version 1.0 for maximum compatibility,
1899 // but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
1900 // unspecified (HTTP errors and contents of 'error').
1902 // 1.0 spec: http://json-rpc.org/wiki/specification
1903 // 1.2 spec: http://groups.google.com/group/json-rpc/web/json-rpc-over-http
1904 // http://www.codeproject.com/KB/recipes/JSON_Spirit.aspx
1907 string JSONRPCRequest(const string& strMethod, const Array& params, const Value& id)
1910 request.push_back(Pair("method", strMethod));
1911 request.push_back(Pair("params", params));
1912 request.push_back(Pair("id", id));
1913 return write_string(Value(request), false) + "\n";
1916 string JSONRPCReply(const Value& result, const Value& error, const Value& id)
1919 if (error.type() != null_type)
1920 reply.push_back(Pair("result", Value::null));
1922 reply.push_back(Pair("result", result));
1923 reply.push_back(Pair("error", error));
1924 reply.push_back(Pair("id", id));
1925 return write_string(Value(reply), false) + "\n";
1928 void ErrorReply(std::ostream& stream, const Object& objError, const Value& id)
1930 // Send error reply from json-rpc error object
1932 int code = find_value(objError, "code").get_int();
1933 if (code == -32600) nStatus = 400;
1934 else if (code == -32601) nStatus = 404;
1935 string strReply = JSONRPCReply(Value::null, objError, id);
1936 stream << HTTPReply(nStatus, strReply) << std::flush;
1939 bool ClientAllowed(const string& strAddress)
1941 if (strAddress == asio::ip::address_v4::loopback().to_string())
1943 const vector<string>& vAllow = mapMultiArgs["-rpcallowip"];
1944 BOOST_FOREACH(string strAllow, vAllow)
1945 if (WildcardMatch(strAddress, strAllow))
1952 // IOStream device that speaks SSL but can also speak non-SSL
1954 class SSLIOStreamDevice : public iostreams::device<iostreams::bidirectional> {
1956 SSLIOStreamDevice(SSLStream &streamIn, bool fUseSSLIn) : stream(streamIn)
1958 fUseSSL = fUseSSLIn;
1959 fNeedHandshake = fUseSSLIn;
1962 void handshake(ssl::stream_base::handshake_type role)
1964 if (!fNeedHandshake) return;
1965 fNeedHandshake = false;
1966 stream.handshake(role);
1968 std::streamsize read(char* s, std::streamsize n)
1970 handshake(ssl::stream_base::server); // HTTPS servers read first
1971 if (fUseSSL) return stream.read_some(asio::buffer(s, n));
1972 return stream.next_layer().read_some(asio::buffer(s, n));
1974 std::streamsize write(const char* s, std::streamsize n)
1976 handshake(ssl::stream_base::client); // HTTPS clients write first
1977 if (fUseSSL) return asio::write(stream, asio::buffer(s, n));
1978 return asio::write(stream.next_layer(), asio::buffer(s, n));
1980 bool connect(const std::string& server, const std::string& port)
1982 ip::tcp::resolver resolver(stream.get_io_service());
1983 ip::tcp::resolver::query query(server.c_str(), port.c_str());
1984 ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
1985 ip::tcp::resolver::iterator end;
1986 boost::system::error_code error = asio::error::host_not_found;
1987 while (error && endpoint_iterator != end)
1989 stream.lowest_layer().close();
1990 stream.lowest_layer().connect(*endpoint_iterator++, error);
1998 bool fNeedHandshake;
2004 void ThreadRPCServer(void* parg)
2006 IMPLEMENT_RANDOMIZE_STACK(ThreadRPCServer(parg));
2009 vnThreadsRunning[4]++;
2010 ThreadRPCServer2(parg);
2011 vnThreadsRunning[4]--;
2013 catch (std::exception& e) {
2014 vnThreadsRunning[4]--;
2015 PrintException(&e, "ThreadRPCServer()");
2017 vnThreadsRunning[4]--;
2018 PrintException(NULL, "ThreadRPCServer()");
2020 printf("ThreadRPCServer exiting\n");
2023 void ThreadRPCServer2(void* parg)
2025 printf("ThreadRPCServer started\n");
2027 if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
2029 unsigned char rand_pwd[32];
2030 RAND_bytes(rand_pwd, 32);
2031 string strWhatAmI = "To use bitcoind";
2032 if (mapArgs.count("-server"))
2033 strWhatAmI = strprintf(_("To use the %s option"), "\"-server\"");
2034 else if (mapArgs.count("-daemon"))
2035 strWhatAmI = strprintf(_("To use the %s option"), "\"-daemon\"");
2037 _("Warning: %s, you must set a rpcpassword in the configuration file:\n %s\n"
2038 "It is recommended you use the following random password:\n"
2039 "rpcuser=bitcoinrpc\n"
2041 "(you do not need to remember this password)\n"
2042 "If the file does not exist, create it with owner-readable-only file permissions.\n"),
2044 GetConfigFile().c_str(),
2045 EncodeBase58(&rand_pwd[0],&rand_pwd[0]+32).c_str());
2046 CreateThread(Shutdown, NULL);
2050 bool fUseSSL = GetBoolArg("-rpcssl");
2051 asio::ip::address bindAddress = mapArgs.count("-rpcallowip") ? asio::ip::address_v4::any() : asio::ip::address_v4::loopback();
2053 asio::io_service io_service;
2054 ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", 8332));
2055 ip::tcp::acceptor acceptor(io_service, endpoint);
2057 acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
2060 ssl::context context(io_service, ssl::context::sslv23);
2063 context.set_options(ssl::context::no_sslv2);
2064 filesystem::path certfile = GetArg("-rpcsslcertificatechainfile", "server.cert");
2065 if (!certfile.is_complete()) certfile = filesystem::path(GetDataDir()) / certfile;
2066 if (filesystem::exists(certfile)) context.use_certificate_chain_file(certfile.string().c_str());
2067 else printf("ThreadRPCServer ERROR: missing server certificate file %s\n", certfile.string().c_str());
2068 filesystem::path pkfile = GetArg("-rpcsslprivatekeyfile", "server.pem");
2069 if (!pkfile.is_complete()) pkfile = filesystem::path(GetDataDir()) / pkfile;
2070 if (filesystem::exists(pkfile)) context.use_private_key_file(pkfile.string().c_str(), ssl::context::pem);
2071 else printf("ThreadRPCServer ERROR: missing server private key file %s\n", pkfile.string().c_str());
2073 string ciphers = GetArg("-rpcsslciphers",
2074 "TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH");
2075 SSL_CTX_set_cipher_list(context.impl(), ciphers.c_str());
2079 throw runtime_error("-rpcssl=1, but bitcoin compiled without full openssl libraries.");
2084 // Accept connection
2086 SSLStream sslStream(io_service, context);
2087 SSLIOStreamDevice d(sslStream, fUseSSL);
2088 iostreams::stream<SSLIOStreamDevice> stream(d);
2090 ip::tcp::iostream stream;
2093 ip::tcp::endpoint peer;
2094 vnThreadsRunning[4]--;
2096 acceptor.accept(sslStream.lowest_layer(), peer);
2098 acceptor.accept(*stream.rdbuf(), peer);
2100 vnThreadsRunning[4]++;
2104 // Restrict callers by IP
2105 if (!ClientAllowed(peer.address().to_string()))
2107 // Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake.
2109 stream << HTTPReply(403, "") << std::flush;
2113 map<string, string> mapHeaders;
2116 boost::thread api_caller(ReadHTTP, boost::ref(stream), boost::ref(mapHeaders), boost::ref(strRequest));
2117 if (!api_caller.timed_join(boost::posix_time::seconds(GetArg("-rpctimeout", 30))))
2120 printf("ThreadRPCServer ReadHTTP timeout\n");
2124 // Check authorization
2125 if (mapHeaders.count("authorization") == 0)
2127 stream << HTTPReply(401, "") << std::flush;
2130 if (!HTTPAuthorized(mapHeaders))
2132 printf("ThreadRPCServer incorrect password attempt from %s\n",peer.address().to_string().c_str());
2133 /* Deter brute-forcing short passwords.
2134 If this results in a DOS the user really
2135 shouldn't have their RPC port exposed.*/
2136 if (mapArgs["-rpcpassword"].size() < 20)
2139 stream << HTTPReply(401, "") << std::flush;
2143 Value id = Value::null;
2148 if (!read_string(strRequest, valRequest) || valRequest.type() != obj_type)
2149 throw JSONRPCError(-32700, "Parse error");
2150 const Object& request = valRequest.get_obj();
2152 // Parse id now so errors from here on will have the id
2153 id = find_value(request, "id");
2156 Value valMethod = find_value(request, "method");
2157 if (valMethod.type() == null_type)
2158 throw JSONRPCError(-32600, "Missing method");
2159 if (valMethod.type() != str_type)
2160 throw JSONRPCError(-32600, "Method must be a string");
2161 string strMethod = valMethod.get_str();
2162 if (strMethod != "getwork")
2163 printf("ThreadRPCServer method=%s\n", strMethod.c_str());
2166 Value valParams = find_value(request, "params");
2168 if (valParams.type() == array_type)
2169 params = valParams.get_array();
2170 else if (valParams.type() == null_type)
2173 throw JSONRPCError(-32600, "Params must be an array");
2176 map<string, rpcfn_type>::iterator mi = mapCallTable.find(strMethod);
2177 if (mi == mapCallTable.end())
2178 throw JSONRPCError(-32601, "Method not found");
2180 // Observe safe mode
2181 string strWarning = GetWarnings("rpc");
2182 if (strWarning != "" && !GetBoolArg("-disablesafemode") && !setAllowInSafeMode.count(strMethod))
2183 throw JSONRPCError(-2, string("Safe mode: ") + strWarning);
2189 CRITICAL_BLOCK(cs_main)
2190 CRITICAL_BLOCK(pwalletMain->cs_wallet)
2191 result = (*(*mi).second)(params, false);
2194 string strReply = JSONRPCReply(result, Value::null, id);
2195 stream << HTTPReply(200, strReply) << std::flush;
2197 catch (std::exception& e)
2199 ErrorReply(stream, JSONRPCError(-1, e.what()), id);
2202 catch (Object& objError)
2204 ErrorReply(stream, objError, id);
2206 catch (std::exception& e)
2208 ErrorReply(stream, JSONRPCError(-32700, e.what()), id);
2216 Object CallRPC(const string& strMethod, const Array& params)
2218 if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
2219 throw runtime_error(strprintf(
2220 _("You must set rpcpassword=<password> in the configuration file:\n%s\n"
2221 "If the file does not exist, create it with owner-readable-only file permissions."),
2222 GetConfigFile().c_str()));
2224 // Connect to localhost
2225 bool fUseSSL = GetBoolArg("-rpcssl");
2227 asio::io_service io_service;
2228 ssl::context context(io_service, ssl::context::sslv23);
2229 context.set_options(ssl::context::no_sslv2);
2230 SSLStream sslStream(io_service, context);
2231 SSLIOStreamDevice d(sslStream, fUseSSL);
2232 iostreams::stream<SSLIOStreamDevice> stream(d);
2233 if (!d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332")))
2234 throw runtime_error("couldn't connect to server");
2237 throw runtime_error("-rpcssl=1, but bitcoin compiled without full openssl libraries.");
2239 ip::tcp::iostream stream(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332"));
2241 throw runtime_error("couldn't connect to server");
2245 // HTTP basic authentication
2246 string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
2247 map<string, string> mapRequestHeaders;
2248 mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64;
2251 string strRequest = JSONRPCRequest(strMethod, params, 1);
2252 string strPost = HTTPPost(strRequest, mapRequestHeaders);
2253 stream << strPost << std::flush;
2256 map<string, string> mapHeaders;
2258 int nStatus = ReadHTTP(stream, mapHeaders, strReply);
2260 throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
2261 else if (nStatus >= 400 && nStatus != 400 && nStatus != 404 && nStatus != 500)
2262 throw runtime_error(strprintf("server returned HTTP error %d", nStatus));
2263 else if (strReply.empty())
2264 throw runtime_error("no response from server");
2268 if (!read_string(strReply, valReply))
2269 throw runtime_error("couldn't parse reply from server");
2270 const Object& reply = valReply.get_obj();
2272 throw runtime_error("expected reply to have result, error and id properties");
2280 template<typename T>
2281 void ConvertTo(Value& value)
2283 if (value.type() == str_type)
2285 // reinterpret string as unquoted json value
2287 if (!read_string(value.get_str(), value2))
2288 throw runtime_error("type mismatch");
2289 value = value2.get_value<T>();
2293 value = value.get_value<T>();
2297 int CommandLineRPC(int argc, char *argv[])
2304 while (argc > 1 && IsSwitchChar(argv[1][0]))
2312 throw runtime_error("too few parameters");
2313 string strMethod = argv[1];
2315 // Parameters default to strings
2317 for (int i = 2; i < argc; i++)
2318 params.push_back(argv[i]);
2319 int n = params.size();
2322 // Special case non-string parameter types
2324 if (strMethod == "setgenerate" && n > 0) ConvertTo<bool>(params[0]);
2325 if (strMethod == "setgenerate" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2326 if (strMethod == "sendtoaddress" && n > 1) ConvertTo<double>(params[1]);
2327 if (strMethod == "settxfee" && n > 0) ConvertTo<double>(params[0]);
2328 if (strMethod == "getamountreceived" && n > 1) ConvertTo<boost::int64_t>(params[1]); // deprecated
2329 if (strMethod == "getreceivedbyaddress" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2330 if (strMethod == "getreceivedbyaccount" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2331 if (strMethod == "getreceivedbylabel" && n > 1) ConvertTo<boost::int64_t>(params[1]); // deprecated
2332 if (strMethod == "getallreceived" && n > 0) ConvertTo<boost::int64_t>(params[0]); // deprecated
2333 if (strMethod == "getallreceived" && n > 1) ConvertTo<bool>(params[1]); // deprecated
2334 if (strMethod == "listreceivedbyaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2335 if (strMethod == "listreceivedbyaddress" && n > 1) ConvertTo<bool>(params[1]);
2336 if (strMethod == "listreceivedbyaccount" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2337 if (strMethod == "listreceivedbyaccount" && n > 1) ConvertTo<bool>(params[1]);
2338 if (strMethod == "listreceivedbylabel" && n > 0) ConvertTo<boost::int64_t>(params[0]); // deprecated
2339 if (strMethod == "listreceivedbylabel" && n > 1) ConvertTo<bool>(params[1]); // deprecated
2340 if (strMethod == "getbalance" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2341 if (strMethod == "move" && n > 2) ConvertTo<double>(params[2]);
2342 if (strMethod == "move" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2343 if (strMethod == "sendfrom" && n > 2) ConvertTo<double>(params[2]);
2344 if (strMethod == "sendfrom" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2345 if (strMethod == "listtransactions" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2346 if (strMethod == "listtransactions" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2347 if (strMethod == "listaccounts" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2348 if (strMethod == "walletpassphrase" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2349 if (strMethod == "sendmany" && n > 1)
2351 string s = params[1].get_str();
2353 if (!read_string(s, v) || v.type() != obj_type)
2354 throw runtime_error("type mismatch");
2355 params[1] = v.get_obj();
2357 if (strMethod == "sendmany" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2360 Object reply = CallRPC(strMethod, params);
2363 const Value& result = find_value(reply, "result");
2364 const Value& error = find_value(reply, "error");
2366 if (error.type() != null_type)
2369 strPrint = "error: " + write_string(error, false);
2370 int code = find_value(error.get_obj(), "code").get_int();
2376 if (result.type() == null_type)
2378 else if (result.type() == str_type)
2379 strPrint = result.get_str();
2381 strPrint = write_string(result, true);
2384 catch (std::exception& e)
2386 strPrint = string("error: ") + e.what();
2391 PrintException(NULL, "CommandLineRPC()");
2396 #if defined(__WXMSW__) && defined(GUI)
2397 // Windows GUI apps can't print to command line,
2398 // so settle for a message box yuck
2399 MyMessageBox(strPrint, "Bitcoin", wxOK);
2401 fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
2411 int main(int argc, char *argv[])
2414 // Turn off microsoft heap dump noise
2415 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
2416 _CrtSetReportFile(_CRT_WARN, CreateFile("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0));
2418 setbuf(stdin, NULL);
2419 setbuf(stdout, NULL);
2420 setbuf(stderr, NULL);
2424 if (argc >= 2 && string(argv[1]) == "-server")
2426 printf("server ready\n");
2427 ThreadRPCServer(NULL);
2431 return CommandLineRPC(argc, argv);
2434 catch (std::exception& e) {
2435 PrintException(&e, "main()");
2437 PrintException(NULL, "main()");