1 // Copyright (c) 2010 Satoshi Nakamoto
2 // Copyright (c) 2011 The Bitcoin developers
3 // Distributed under the MIT/X11 software license, see the accompanying
4 // file license.txt or http://www.opensource.org/licenses/mit-license.php.
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 > MAX_MONEY)
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));
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.0001\n"
487 "Minimum and default transaction fee is 1 coin");
490 int64 nAmount = MIN_TX_FEE;
491 if (params[0].get_real() != 0.0) // rejects 0.0 amounts
492 nAmount = max(nAmount, AmountFromValue(params[0]));
494 nTransactionFee = nAmount;
498 Value sendtoaddress(const Array& params, bool fHelp)
500 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
502 "sendtoaddress <bitcoinaddress> <amount> [comment] [comment-to]\n"
503 "<amount> is a real and is rounded to the nearest 0.00000001\n"
504 "requires wallet passphrase to be set with walletpassphrase first");
505 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
507 "sendtoaddress <bitcoinaddress> <amount> [comment] [comment-to]\n"
508 "<amount> is a real and is rounded to the nearest 0.00000001");
510 CBitcoinAddress address(params[0].get_str());
511 if (!address.IsValid())
512 throw JSONRPCError(-5, "Invalid bitcoin address");
515 int64 nAmount = AmountFromValue(params[1]);
519 if (params.size() > 2 && params[2].type() != null_type && !params[2].get_str().empty())
520 wtx.mapValue["comment"] = params[2].get_str();
521 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
522 wtx.mapValue["to"] = params[3].get_str();
524 if (pwalletMain->IsLocked())
525 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
527 string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
529 throw JSONRPCError(-4, strError);
531 return wtx.GetHash().GetHex();
535 Value getreceivedbyaddress(const Array& params, bool fHelp)
537 if (fHelp || params.size() < 1 || params.size() > 2)
539 "getreceivedbyaddress <bitcoinaddress> [minconf=1]\n"
540 "Returns the total amount received by <bitcoinaddress> in transactions with at least [minconf] confirmations.");
543 CBitcoinAddress address = CBitcoinAddress(params[0].get_str());
544 CScript scriptPubKey;
545 if (!address.IsValid())
546 throw JSONRPCError(-5, "Invalid bitcoin address");
547 scriptPubKey.SetBitcoinAddress(address);
548 if (!IsMine(*pwalletMain,scriptPubKey))
551 // Minimum confirmations
553 if (params.size() > 1)
554 nMinDepth = params[1].get_int();
558 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
560 const CWalletTx& wtx = (*it).second;
561 if (wtx.IsCoinBase() || !wtx.IsFinal())
564 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
565 if (txout.scriptPubKey == scriptPubKey)
566 if (wtx.GetDepthInMainChain() >= nMinDepth)
567 nAmount += txout.nValue;
570 return ValueFromAmount(nAmount);
574 void GetAccountAddresses(string strAccount, set<CBitcoinAddress>& setAddress)
576 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
578 const CBitcoinAddress& address = item.first;
579 const string& strName = item.second;
580 if (strName == strAccount)
581 setAddress.insert(address);
586 Value getreceivedbyaccount(const Array& params, bool fHelp)
588 if (fHelp || params.size() < 1 || params.size() > 2)
590 "getreceivedbyaccount <account> [minconf=1]\n"
591 "Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.");
593 // Minimum confirmations
595 if (params.size() > 1)
596 nMinDepth = params[1].get_int();
598 // Get the set of pub keys that have the label
599 string strAccount = AccountFromValue(params[0]);
600 set<CBitcoinAddress> setAddress;
601 GetAccountAddresses(strAccount, setAddress);
605 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
607 const CWalletTx& wtx = (*it).second;
608 if (wtx.IsCoinBase() || !wtx.IsFinal())
611 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
613 CBitcoinAddress address;
614 if (ExtractAddress(txout.scriptPubKey, pwalletMain, address) && setAddress.count(address))
615 if (wtx.GetDepthInMainChain() >= nMinDepth)
616 nAmount += txout.nValue;
620 return (double)nAmount / (double)COIN;
624 int64 GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth)
628 // Tally wallet transactions
629 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
631 const CWalletTx& wtx = (*it).second;
635 int64 nGenerated, nReceived, nSent, nFee;
636 wtx.GetAccountAmounts(strAccount, nGenerated, nReceived, nSent, nFee);
638 if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
639 nBalance += nReceived;
640 nBalance += nGenerated - nSent - nFee;
643 // Tally internal accounting entries
644 nBalance += walletdb.GetAccountCreditDebit(strAccount);
649 int64 GetAccountBalance(const string& strAccount, int nMinDepth)
651 CWalletDB walletdb(pwalletMain->strWalletFile);
652 return GetAccountBalance(walletdb, strAccount, nMinDepth);
656 Value getbalance(const Array& params, bool fHelp)
658 if (fHelp || params.size() > 2)
660 "getbalance [account] [minconf=1]\n"
661 "If [account] is not specified, returns the server's total available balance.\n"
662 "If [account] is specified, returns the balance in the account.");
664 if (params.size() == 0)
665 return ValueFromAmount(pwalletMain->GetBalance());
668 if (params.size() > 1)
669 nMinDepth = params[1].get_int();
671 if (params[0].get_str() == "*") {
672 // Calculate total balance a different way from GetBalance()
673 // (GetBalance() sums up all unspent TxOuts)
674 // getbalance and getbalance '*' should always return the same number.
676 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
678 const CWalletTx& wtx = (*it).second;
682 int64 allGeneratedImmature, allGeneratedMature, allFee;
683 allGeneratedImmature = allGeneratedMature = allFee = 0;
684 string strSentAccount;
685 list<pair<CBitcoinAddress, int64> > listReceived;
686 list<pair<CBitcoinAddress, int64> > listSent;
687 wtx.GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount);
688 if (wtx.GetDepthInMainChain() >= nMinDepth)
689 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listReceived)
690 nBalance += r.second;
691 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listSent)
692 nBalance -= r.second;
694 nBalance += allGeneratedMature;
696 return ValueFromAmount(nBalance);
699 string strAccount = AccountFromValue(params[0]);
701 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
703 return ValueFromAmount(nBalance);
707 Value movecmd(const Array& params, bool fHelp)
709 if (fHelp || params.size() < 3 || params.size() > 5)
711 "move <fromaccount> <toaccount> <amount> [minconf=1] [comment]\n"
712 "Move from one account in your wallet to another.");
714 string strFrom = AccountFromValue(params[0]);
715 string strTo = AccountFromValue(params[1]);
716 int64 nAmount = AmountFromValue(params[2]);
717 if (params.size() > 3)
718 // unused parameter, used to be nMinDepth, keep type-checking it though
719 (void)params[3].get_int();
721 if (params.size() > 4)
722 strComment = params[4].get_str();
724 CWalletDB walletdb(pwalletMain->strWalletFile);
727 int64 nNow = GetAdjustedTime();
730 CAccountingEntry debit;
731 debit.strAccount = strFrom;
732 debit.nCreditDebit = -nAmount;
734 debit.strOtherAccount = strTo;
735 debit.strComment = strComment;
736 walletdb.WriteAccountingEntry(debit);
739 CAccountingEntry credit;
740 credit.strAccount = strTo;
741 credit.nCreditDebit = nAmount;
743 credit.strOtherAccount = strFrom;
744 credit.strComment = strComment;
745 walletdb.WriteAccountingEntry(credit);
747 walletdb.TxnCommit();
753 Value sendfrom(const Array& params, bool fHelp)
755 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
757 "sendfrom <fromaccount> <tobitcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
758 "<amount> is a real and is rounded to the nearest 0.00000001\n"
759 "requires wallet passphrase to be set with walletpassphrase first");
760 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
762 "sendfrom <fromaccount> <tobitcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
763 "<amount> is a real and is rounded to the nearest 0.00000001");
765 string strAccount = AccountFromValue(params[0]);
766 CBitcoinAddress address(params[1].get_str());
767 if (!address.IsValid())
768 throw JSONRPCError(-5, "Invalid bitcoin address");
769 int64 nAmount = AmountFromValue(params[2]);
771 if (params.size() > 3)
772 nMinDepth = params[3].get_int();
775 wtx.strFromAccount = strAccount;
776 if (params.size() > 4 && params[4].type() != null_type && !params[4].get_str().empty())
777 wtx.mapValue["comment"] = params[4].get_str();
778 if (params.size() > 5 && params[5].type() != null_type && !params[5].get_str().empty())
779 wtx.mapValue["to"] = params[5].get_str();
781 if (pwalletMain->IsLocked())
782 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
785 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
786 if (nAmount > nBalance)
787 throw JSONRPCError(-6, "Account has insufficient funds");
790 string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
792 throw JSONRPCError(-4, strError);
794 return wtx.GetHash().GetHex();
798 Value sendmany(const Array& params, bool fHelp)
800 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
802 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
803 "amounts are double-precision floating point numbers\n"
804 "requires wallet passphrase to be set with walletpassphrase first");
805 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
807 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
808 "amounts are double-precision floating point numbers");
810 string strAccount = AccountFromValue(params[0]);
811 Object sendTo = params[1].get_obj();
813 if (params.size() > 2)
814 nMinDepth = params[2].get_int();
817 wtx.strFromAccount = strAccount;
818 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
819 wtx.mapValue["comment"] = params[3].get_str();
821 set<CBitcoinAddress> setAddress;
822 vector<pair<CScript, int64> > vecSend;
824 int64 totalAmount = 0;
825 BOOST_FOREACH(const Pair& s, sendTo)
827 CBitcoinAddress address(s.name_);
828 if (!address.IsValid())
829 throw JSONRPCError(-5, string("Invalid bitcoin address:")+s.name_);
831 if (setAddress.count(address))
832 throw JSONRPCError(-8, string("Invalid parameter, duplicated address: ")+s.name_);
833 setAddress.insert(address);
835 CScript scriptPubKey;
836 scriptPubKey.SetBitcoinAddress(address);
837 int64 nAmount = AmountFromValue(s.value_);
838 totalAmount += nAmount;
840 vecSend.push_back(make_pair(scriptPubKey, nAmount));
843 if (pwalletMain->IsLocked())
844 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
847 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
848 if (totalAmount > nBalance)
849 throw JSONRPCError(-6, "Account has insufficient funds");
852 CReserveKey keyChange(pwalletMain);
853 int64 nFeeRequired = 0;
854 bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired);
857 if (totalAmount + nFeeRequired > pwalletMain->GetBalance())
858 throw JSONRPCError(-6, "Insufficient funds");
859 throw JSONRPCError(-4, "Transaction creation failed");
861 if (!pwalletMain->CommitTransaction(wtx, keyChange))
862 throw JSONRPCError(-4, "Transaction commit failed");
864 return wtx.GetHash().GetHex();
879 Value ListReceived(const Array& params, bool fByAccounts)
881 // Minimum confirmations
883 if (params.size() > 0)
884 nMinDepth = params[0].get_int();
886 // Whether to include empty accounts
887 bool fIncludeEmpty = false;
888 if (params.size() > 1)
889 fIncludeEmpty = params[1].get_bool();
892 map<CBitcoinAddress, tallyitem> mapTally;
893 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
895 const CWalletTx& wtx = (*it).second;
896 if (wtx.IsCoinBase() || !wtx.IsFinal())
899 int nDepth = wtx.GetDepthInMainChain();
900 if (nDepth < nMinDepth)
903 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
905 CBitcoinAddress address;
906 if (!ExtractAddress(txout.scriptPubKey, pwalletMain, address) || !address.IsValid())
909 tallyitem& item = mapTally[address];
910 item.nAmount += txout.nValue;
911 item.nConf = min(item.nConf, nDepth);
917 map<string, tallyitem> mapAccountTally;
918 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
920 const CBitcoinAddress& address = item.first;
921 const string& strAccount = item.second;
922 map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
923 if (it == mapTally.end() && !fIncludeEmpty)
928 if (it != mapTally.end())
930 nAmount = (*it).second.nAmount;
931 nConf = (*it).second.nConf;
936 tallyitem& item = mapAccountTally[strAccount];
937 item.nAmount += nAmount;
938 item.nConf = min(item.nConf, nConf);
943 obj.push_back(Pair("address", address.ToString()));
944 obj.push_back(Pair("account", strAccount));
945 obj.push_back(Pair("label", strAccount)); // deprecated
946 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
947 obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf)));
954 for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
956 int64 nAmount = (*it).second.nAmount;
957 int nConf = (*it).second.nConf;
959 obj.push_back(Pair("account", (*it).first));
960 obj.push_back(Pair("label", (*it).first)); // deprecated
961 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
962 obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf)));
970 Value listreceivedbyaddress(const Array& params, bool fHelp)
972 if (fHelp || params.size() > 2)
974 "listreceivedbyaddress [minconf=1] [includeempty=false]\n"
975 "[minconf] is the minimum number of confirmations before payments are included.\n"
976 "[includeempty] whether to include addresses that haven't received any payments.\n"
977 "Returns an array of objects containing:\n"
978 " \"address\" : receiving address\n"
979 " \"account\" : the account of the receiving address\n"
980 " \"amount\" : total amount received by the address\n"
981 " \"confirmations\" : number of confirmations of the most recent transaction included");
983 return ListReceived(params, false);
986 Value listreceivedbyaccount(const Array& params, bool fHelp)
988 if (fHelp || params.size() > 2)
990 "listreceivedbyaccount [minconf=1] [includeempty=false]\n"
991 "[minconf] is the minimum number of confirmations before payments are included.\n"
992 "[includeempty] whether to include accounts that haven't received any payments.\n"
993 "Returns an array of objects containing:\n"
994 " \"account\" : the account of the receiving addresses\n"
995 " \"amount\" : total amount received by addresses with this account\n"
996 " \"confirmations\" : number of confirmations of the most recent transaction included");
998 return ListReceived(params, true);
1001 void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret)
1003 int64 nGeneratedImmature, nGeneratedMature, nFee;
1004 string strSentAccount;
1005 list<pair<CBitcoinAddress, int64> > listReceived;
1006 list<pair<CBitcoinAddress, int64> > listSent;
1007 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1009 bool fAllAccounts = (strAccount == string("*"));
1011 // Generated blocks assigned to account ""
1012 if ((nGeneratedMature+nGeneratedImmature) != 0 && (fAllAccounts || strAccount == ""))
1015 entry.push_back(Pair("account", string("")));
1016 if (nGeneratedImmature)
1018 entry.push_back(Pair("category", wtx.GetDepthInMainChain() ? "immature" : "orphan"));
1019 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedImmature)));
1023 entry.push_back(Pair("category", "generate"));
1024 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedMature)));
1027 WalletTxToJSON(wtx, entry);
1028 ret.push_back(entry);
1032 if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
1034 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1037 entry.push_back(Pair("account", strSentAccount));
1038 entry.push_back(Pair("address", s.first.ToString()));
1039 entry.push_back(Pair("category", "send"));
1040 entry.push_back(Pair("amount", ValueFromAmount(-s.second)));
1041 entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
1043 WalletTxToJSON(wtx, entry);
1044 ret.push_back(entry);
1049 if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
1050 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1053 if (pwalletMain->mapAddressBook.count(r.first))
1054 account = pwalletMain->mapAddressBook[r.first];
1055 if (fAllAccounts || (account == strAccount))
1058 entry.push_back(Pair("account", account));
1059 entry.push_back(Pair("address", r.first.ToString()));
1060 entry.push_back(Pair("category", "receive"));
1061 entry.push_back(Pair("amount", ValueFromAmount(r.second)));
1063 WalletTxToJSON(wtx, entry);
1064 ret.push_back(entry);
1069 void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret)
1071 bool fAllAccounts = (strAccount == string("*"));
1073 if (fAllAccounts || acentry.strAccount == strAccount)
1076 entry.push_back(Pair("account", acentry.strAccount));
1077 entry.push_back(Pair("category", "move"));
1078 entry.push_back(Pair("time", (boost::int64_t)acentry.nTime));
1079 entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
1080 entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
1081 entry.push_back(Pair("comment", acentry.strComment));
1082 ret.push_back(entry);
1086 Value listtransactions(const Array& params, bool fHelp)
1088 if (fHelp || params.size() > 3)
1089 throw runtime_error(
1090 "listtransactions [account] [count=10] [from=0]\n"
1091 "Returns up to [count] most recent transactions skipping the first [from] transactions for account [account].");
1093 string strAccount = "*";
1094 if (params.size() > 0)
1095 strAccount = params[0].get_str();
1097 if (params.size() > 1)
1098 nCount = params[1].get_int();
1100 if (params.size() > 2)
1101 nFrom = params[2].get_int();
1104 CWalletDB walletdb(pwalletMain->strWalletFile);
1106 // Firs: get all CWalletTx and CAccountingEntry into a sorted-by-time multimap:
1107 typedef pair<CWalletTx*, CAccountingEntry*> TxPair;
1108 typedef multimap<int64, TxPair > TxItems;
1111 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1113 CWalletTx* wtx = &((*it).second);
1114 txByTime.insert(make_pair(wtx->GetTxTime(), TxPair(wtx, (CAccountingEntry*)0)));
1116 list<CAccountingEntry> acentries;
1117 walletdb.ListAccountCreditDebit(strAccount, acentries);
1118 BOOST_FOREACH(CAccountingEntry& entry, acentries)
1120 txByTime.insert(make_pair(entry.nTime, TxPair((CWalletTx*)0, &entry)));
1123 // Now: iterate backwards until we have nCount items to return:
1124 TxItems::reverse_iterator it = txByTime.rbegin();
1125 if (txByTime.size() > nFrom) std::advance(it, nFrom);
1126 for (; it != txByTime.rend(); ++it)
1128 CWalletTx *const pwtx = (*it).second.first;
1130 ListTransactions(*pwtx, strAccount, 0, true, ret);
1131 CAccountingEntry *const pacentry = (*it).second.second;
1133 AcentryToJSON(*pacentry, strAccount, ret);
1135 if (ret.size() >= nCount) break;
1137 // ret is now newest to oldest
1139 // Make sure we return only last nCount items (sends-to-self might give us an extra):
1140 if (ret.size() > nCount)
1142 Array::iterator last = ret.begin();
1143 std::advance(last, nCount);
1144 ret.erase(last, ret.end());
1146 std::reverse(ret.begin(), ret.end()); // oldest to newest
1151 Value listaccounts(const Array& params, bool fHelp)
1153 if (fHelp || params.size() > 1)
1154 throw runtime_error(
1155 "listaccounts [minconf=1]\n"
1156 "Returns Object that has account names as keys, account balances as values.");
1159 if (params.size() > 0)
1160 nMinDepth = params[0].get_int();
1162 map<string, int64> mapAccountBalances;
1163 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& entry, pwalletMain->mapAddressBook) {
1164 if (pwalletMain->HaveKey(entry.first)) // This address belongs to me
1165 mapAccountBalances[entry.second] = 0;
1168 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1170 const CWalletTx& wtx = (*it).second;
1171 int64 nGeneratedImmature, nGeneratedMature, nFee;
1172 string strSentAccount;
1173 list<pair<CBitcoinAddress, int64> > listReceived;
1174 list<pair<CBitcoinAddress, int64> > listSent;
1175 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1176 mapAccountBalances[strSentAccount] -= nFee;
1177 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1178 mapAccountBalances[strSentAccount] -= s.second;
1179 if (wtx.GetDepthInMainChain() >= nMinDepth)
1181 mapAccountBalances[""] += nGeneratedMature;
1182 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1183 if (pwalletMain->mapAddressBook.count(r.first))
1184 mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second;
1186 mapAccountBalances[""] += r.second;
1190 list<CAccountingEntry> acentries;
1191 CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
1192 BOOST_FOREACH(const CAccountingEntry& entry, acentries)
1193 mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
1196 BOOST_FOREACH(const PAIRTYPE(string, int64)& accountBalance, mapAccountBalances) {
1197 ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
1202 Value gettransaction(const Array& params, bool fHelp)
1204 if (fHelp || params.size() != 1)
1205 throw runtime_error(
1206 "gettransaction <txid>\n"
1207 "Get detailed information about <txid>");
1210 hash.SetHex(params[0].get_str());
1214 if (!pwalletMain->mapWallet.count(hash))
1215 throw JSONRPCError(-5, "Invalid or non-wallet transaction id");
1216 const CWalletTx& wtx = pwalletMain->mapWallet[hash];
1218 int64 nCredit = wtx.GetCredit();
1219 int64 nDebit = wtx.GetDebit();
1220 int64 nNet = nCredit - nDebit;
1221 int64 nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0);
1223 entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
1225 entry.push_back(Pair("fee", ValueFromAmount(nFee)));
1227 WalletTxToJSON(pwalletMain->mapWallet[hash], entry);
1230 ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details);
1231 entry.push_back(Pair("details", details));
1237 Value backupwallet(const Array& params, bool fHelp)
1239 if (fHelp || params.size() != 1)
1240 throw runtime_error(
1241 "backupwallet <destination>\n"
1242 "Safely copies wallet.dat to destination, which can be a directory or a path with filename.");
1244 string strDest = params[0].get_str();
1245 BackupWallet(*pwalletMain, strDest);
1251 Value keypoolrefill(const Array& params, bool fHelp)
1253 if (pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1254 throw runtime_error(
1256 "Fills the keypool, requires wallet passphrase to be set.");
1257 if (!pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1258 throw runtime_error(
1260 "Fills the keypool.");
1262 if (pwalletMain->IsLocked())
1263 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
1265 pwalletMain->TopUpKeyPool();
1267 if (pwalletMain->GetKeyPoolSize() < GetArg("-keypool", 100))
1268 throw JSONRPCError(-4, "Error refreshing keypool.");
1274 void ThreadTopUpKeyPool(void* parg)
1276 pwalletMain->TopUpKeyPool();
1279 void ThreadCleanWalletPassphrase(void* parg)
1281 int64 nMyWakeTime = GetTime() + *((int*)parg);
1283 if (nWalletUnlockTime == 0)
1285 CRITICAL_BLOCK(cs_nWalletUnlockTime)
1287 nWalletUnlockTime = nMyWakeTime;
1290 while (GetTime() < nWalletUnlockTime)
1291 Sleep(GetTime() - nWalletUnlockTime);
1293 CRITICAL_BLOCK(cs_nWalletUnlockTime)
1295 nWalletUnlockTime = 0;
1300 CRITICAL_BLOCK(cs_nWalletUnlockTime)
1302 if (nWalletUnlockTime < nMyWakeTime)
1303 nWalletUnlockTime = nMyWakeTime;
1309 pwalletMain->Lock();
1314 Value walletpassphrase(const Array& params, bool fHelp)
1316 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1317 throw runtime_error(
1318 "walletpassphrase <passphrase> <timeout>\n"
1319 "Stores the wallet decryption key in memory for <timeout> seconds.");
1322 if (!pwalletMain->IsCrypted())
1323 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
1325 if (!pwalletMain->IsLocked())
1326 throw JSONRPCError(-17, "Error: Wallet is already unlocked.");
1328 // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
1329 string strWalletPass;
1330 strWalletPass.reserve(100);
1331 mlock(&strWalletPass[0], strWalletPass.capacity());
1332 strWalletPass = params[0].get_str();
1334 if (strWalletPass.length() > 0)
1336 if (!pwalletMain->Unlock(strWalletPass))
1338 fill(strWalletPass.begin(), strWalletPass.end(), '\0');
1339 munlock(&strWalletPass[0], strWalletPass.capacity());
1340 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1342 fill(strWalletPass.begin(), strWalletPass.end(), '\0');
1343 munlock(&strWalletPass[0], strWalletPass.capacity());
1346 throw runtime_error(
1347 "walletpassphrase <passphrase> <timeout>\n"
1348 "Stores the wallet decryption key in memory for <timeout> seconds.");
1350 CreateThread(ThreadTopUpKeyPool, NULL);
1351 int* pnSleepTime = new int(params[1].get_int());
1352 CreateThread(ThreadCleanWalletPassphrase, pnSleepTime);
1358 Value walletpassphrasechange(const Array& params, bool fHelp)
1360 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1361 throw runtime_error(
1362 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1363 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1366 if (!pwalletMain->IsCrypted())
1367 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
1369 string strOldWalletPass;
1370 strOldWalletPass.reserve(100);
1371 mlock(&strOldWalletPass[0], strOldWalletPass.capacity());
1372 strOldWalletPass = params[0].get_str();
1374 string strNewWalletPass;
1375 strNewWalletPass.reserve(100);
1376 mlock(&strNewWalletPass[0], strNewWalletPass.capacity());
1377 strNewWalletPass = params[1].get_str();
1379 if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
1380 throw runtime_error(
1381 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1382 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1384 if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
1386 fill(strOldWalletPass.begin(), strOldWalletPass.end(), '\0');
1387 fill(strNewWalletPass.begin(), strNewWalletPass.end(), '\0');
1388 munlock(&strOldWalletPass[0], strOldWalletPass.capacity());
1389 munlock(&strNewWalletPass[0], strNewWalletPass.capacity());
1390 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1392 fill(strNewWalletPass.begin(), strNewWalletPass.end(), '\0');
1393 fill(strOldWalletPass.begin(), strOldWalletPass.end(), '\0');
1394 munlock(&strOldWalletPass[0], strOldWalletPass.capacity());
1395 munlock(&strNewWalletPass[0], strNewWalletPass.capacity());
1401 Value walletlock(const Array& params, bool fHelp)
1403 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
1404 throw runtime_error(
1406 "Removes the wallet encryption key from memory, locking the wallet.\n"
1407 "After calling this method, you will need to call walletpassphrase again\n"
1408 "before being able to call any methods which require the wallet to be unlocked.");
1411 if (!pwalletMain->IsCrypted())
1412 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletlock was called.");
1414 pwalletMain->Lock();
1415 CRITICAL_BLOCK(cs_nWalletUnlockTime)
1417 nWalletUnlockTime = 0;
1424 Value encryptwallet(const Array& params, bool fHelp)
1426 if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
1427 throw runtime_error(
1428 "encryptwallet <passphrase>\n"
1429 "Encrypts the wallet with <passphrase>.");
1432 if (pwalletMain->IsCrypted())
1433 throw JSONRPCError(-15, "Error: running with an encrypted wallet, but encryptwallet was called.");
1435 string strWalletPass;
1436 strWalletPass.reserve(100);
1437 mlock(&strWalletPass[0], strWalletPass.capacity());
1438 strWalletPass = params[0].get_str();
1440 if (strWalletPass.length() < 1)
1441 throw runtime_error(
1442 "encryptwallet <passphrase>\n"
1443 "Encrypts the wallet with <passphrase>.");
1445 if (!pwalletMain->EncryptWallet(strWalletPass))
1447 fill(strWalletPass.begin(), strWalletPass.end(), '\0');
1448 munlock(&strWalletPass[0], strWalletPass.capacity());
1449 throw JSONRPCError(-16, "Error: Failed to encrypt the wallet.");
1451 fill(strWalletPass.begin(), strWalletPass.end(), '\0');
1452 munlock(&strWalletPass[0], strWalletPass.capacity());
1458 Value validateaddress(const Array& params, bool fHelp)
1460 if (fHelp || params.size() != 1)
1461 throw runtime_error(
1462 "validateaddress <bitcoinaddress>\n"
1463 "Return information about <bitcoinaddress>.");
1465 CBitcoinAddress address(params[0].get_str());
1466 bool isValid = address.IsValid();
1469 ret.push_back(Pair("isvalid", isValid));
1472 // Call Hash160ToAddress() so we always return current ADDRESSVERSION
1473 // version of the address:
1474 string currentAddress = address.ToString();
1475 ret.push_back(Pair("address", currentAddress));
1476 ret.push_back(Pair("ismine", (pwalletMain->HaveKey(address) > 0)));
1477 if (pwalletMain->mapAddressBook.count(address))
1478 ret.push_back(Pair("account", pwalletMain->mapAddressBook[address]));
1484 Value getwork(const Array& params, bool fHelp)
1486 if (fHelp || params.size() > 1)
1487 throw runtime_error(
1489 "If [data] is not specified, returns formatted hash data to work on:\n"
1490 " \"midstate\" : precomputed hash state after hashing the first half of the data\n"
1491 " \"data\" : block data\n"
1492 " \"hash1\" : formatted hash buffer for second hash\n"
1493 " \"target\" : little endian hash target\n"
1494 "If [data] is specified, tries to solve the block and returns true if it was successful.");
1497 throw JSONRPCError(-9, "Bitcoin is not connected!");
1499 if (IsInitialBlockDownload())
1500 throw JSONRPCError(-10, "Bitcoin is downloading blocks...");
1502 typedef map<uint256, pair<CBlock*, CScript> > mapNewBlock_t;
1503 static mapNewBlock_t mapNewBlock;
1504 static vector<CBlock*> vNewBlock;
1505 static CReserveKey reservekey(pwalletMain);
1507 if (params.size() == 0)
1510 static unsigned int nTransactionsUpdatedLast;
1511 static CBlockIndex* pindexPrev;
1512 static int64 nStart;
1513 static CBlock* pblock;
1514 if (pindexPrev != pindexBest ||
1515 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60))
1517 if (pindexPrev != pindexBest)
1519 // Deallocate old blocks since they're obsolete now
1520 mapNewBlock.clear();
1521 BOOST_FOREACH(CBlock* pblock, vNewBlock)
1525 nTransactionsUpdatedLast = nTransactionsUpdated;
1526 pindexPrev = pindexBest;
1530 pblock = CreateNewBlock(reservekey);
1532 throw JSONRPCError(-7, "Out of memory");
1533 vNewBlock.push_back(pblock);
1537 pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
1540 // Update nExtraNonce
1541 static unsigned int nExtraNonce = 0;
1542 IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
1545 mapNewBlock[pblock->hashMerkleRoot] = make_pair(pblock, pblock->vtx[0].vin[0].scriptSig);
1547 // Prebuild hash buffers
1551 FormatHashBuffers(pblock, pmidstate, pdata, phash1);
1553 uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
1556 result.push_back(Pair("midstate", HexStr(BEGIN(pmidstate), END(pmidstate))));
1557 result.push_back(Pair("data", HexStr(BEGIN(pdata), END(pdata))));
1558 result.push_back(Pair("hash1", HexStr(BEGIN(phash1), END(phash1))));
1559 result.push_back(Pair("target", HexStr(BEGIN(hashTarget), END(hashTarget))));
1565 vector<unsigned char> vchData = ParseHex(params[0].get_str());
1566 if (vchData.size() != 128)
1567 throw JSONRPCError(-8, "Invalid parameter");
1568 CBlock* pdata = (CBlock*)&vchData[0];
1571 for (int i = 0; i < 128/4; i++)
1572 ((unsigned int*)pdata)[i] = CryptoPP::ByteReverse(((unsigned int*)pdata)[i]);
1575 if (!mapNewBlock.count(pdata->hashMerkleRoot))
1577 CBlock* pblock = mapNewBlock[pdata->hashMerkleRoot].first;
1579 pblock->nTime = pdata->nTime;
1580 pblock->nNonce = pdata->nNonce;
1581 pblock->vtx[0].vin[0].scriptSig = mapNewBlock[pdata->hashMerkleRoot].second;
1582 pblock->hashMerkleRoot = pblock->BuildMerkleTree();
1584 return CheckWork(pblock, *pwalletMain, reservekey);
1602 pair<string, rpcfn_type> pCallTable[] =
1604 make_pair("help", &help),
1605 make_pair("stop", &stop),
1606 make_pair("getblockcount", &getblockcount),
1607 make_pair("getblocknumber", &getblocknumber),
1608 make_pair("getconnectioncount", &getconnectioncount),
1609 make_pair("getdifficulty", &getdifficulty),
1610 make_pair("getgenerate", &getgenerate),
1611 make_pair("setgenerate", &setgenerate),
1612 make_pair("gethashespersec", &gethashespersec),
1613 make_pair("getinfo", &getinfo),
1614 make_pair("getnewaddress", &getnewaddress),
1615 make_pair("getaccountaddress", &getaccountaddress),
1616 make_pair("setaccount", &setaccount),
1617 make_pair("setlabel", &setaccount), // deprecated
1618 make_pair("getaccount", &getaccount),
1619 make_pair("getlabel", &getaccount), // deprecated
1620 make_pair("getaddressesbyaccount", &getaddressesbyaccount),
1621 make_pair("getaddressesbylabel", &getaddressesbyaccount), // deprecated
1622 make_pair("sendtoaddress", &sendtoaddress),
1623 make_pair("getamountreceived", &getreceivedbyaddress), // deprecated, renamed to getreceivedbyaddress
1624 make_pair("getallreceived", &listreceivedbyaddress), // deprecated, renamed to listreceivedbyaddress
1625 make_pair("getreceivedbyaddress", &getreceivedbyaddress),
1626 make_pair("getreceivedbyaccount", &getreceivedbyaccount),
1627 make_pair("getreceivedbylabel", &getreceivedbyaccount), // deprecated
1628 make_pair("listreceivedbyaddress", &listreceivedbyaddress),
1629 make_pair("listreceivedbyaccount", &listreceivedbyaccount),
1630 make_pair("listreceivedbylabel", &listreceivedbyaccount), // deprecated
1631 make_pair("backupwallet", &backupwallet),
1632 make_pair("keypoolrefill", &keypoolrefill),
1633 make_pair("walletpassphrase", &walletpassphrase),
1634 make_pair("walletpassphrasechange", &walletpassphrasechange),
1635 make_pair("walletlock", &walletlock),
1636 make_pair("encryptwallet", &encryptwallet),
1637 make_pair("validateaddress", &validateaddress),
1638 make_pair("getbalance", &getbalance),
1639 make_pair("move", &movecmd),
1640 make_pair("sendfrom", &sendfrom),
1641 make_pair("sendmany", &sendmany),
1642 make_pair("gettransaction", &gettransaction),
1643 make_pair("listtransactions", &listtransactions),
1644 make_pair("getwork", &getwork),
1645 make_pair("listaccounts", &listaccounts),
1646 make_pair("settxfee", &settxfee),
1648 map<string, rpcfn_type> mapCallTable(pCallTable, pCallTable + sizeof(pCallTable)/sizeof(pCallTable[0]));
1650 string pAllowInSafeMode[] =
1656 "getconnectioncount",
1663 "getaccountaddress",
1664 "setlabel", // deprecated
1666 "getlabel", // deprecated
1667 "getaddressesbyaccount",
1668 "getaddressesbylabel", // deprecated
1676 set<string> setAllowInSafeMode(pAllowInSafeMode, pAllowInSafeMode + sizeof(pAllowInSafeMode)/sizeof(pAllowInSafeMode[0]));
1684 // This ain't Apache. We're just using HTTP header for the length field
1685 // and to be compatible with other JSON-RPC implementations.
1688 string HTTPPost(const string& strMsg, const map<string,string>& mapRequestHeaders)
1691 s << "POST / HTTP/1.1\r\n"
1692 << "User-Agent: bitcoin-json-rpc/" << FormatFullVersion() << "\r\n"
1693 << "Host: 127.0.0.1\r\n"
1694 << "Content-Type: application/json\r\n"
1695 << "Content-Length: " << strMsg.size() << "\r\n"
1696 << "Accept: application/json\r\n";
1697 BOOST_FOREACH(const PAIRTYPE(string, string)& item, mapRequestHeaders)
1698 s << item.first << ": " << item.second << "\r\n";
1699 s << "\r\n" << strMsg;
1704 string rfc1123Time()
1709 struct tm* now_gmt = gmtime(&now);
1710 string locale(setlocale(LC_TIME, NULL));
1711 setlocale(LC_TIME, "C"); // we want posix (aka "C") weekday/month strings
1712 strftime(buffer, sizeof(buffer), "%a, %d %b %Y %H:%M:%S +0000", now_gmt);
1713 setlocale(LC_TIME, locale.c_str());
1714 return string(buffer);
1717 static string HTTPReply(int nStatus, const string& strMsg)
1720 return strprintf("HTTP/1.0 401 Authorization Required\r\n"
1722 "Server: bitcoin-json-rpc/%s\r\n"
1723 "WWW-Authenticate: Basic realm=\"jsonrpc\"\r\n"
1724 "Content-Type: text/html\r\n"
1725 "Content-Length: 296\r\n"
1727 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\r\n"
1728 "\"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd\">\r\n"
1731 "<TITLE>Error</TITLE>\r\n"
1732 "<META HTTP-EQUIV='Content-Type' CONTENT='text/html; charset=ISO-8859-1'>\r\n"
1734 "<BODY><H1>401 Unauthorized.</H1></BODY>\r\n"
1735 "</HTML>\r\n", rfc1123Time().c_str(), FormatFullVersion().c_str());
1737 if (nStatus == 200) strStatus = "OK";
1738 else if (nStatus == 400) strStatus = "Bad Request";
1739 else if (nStatus == 403) strStatus = "Forbidden";
1740 else if (nStatus == 404) strStatus = "Not Found";
1741 else if (nStatus == 500) strStatus = "Internal Server Error";
1743 "HTTP/1.1 %d %s\r\n"
1745 "Connection: close\r\n"
1746 "Content-Length: %d\r\n"
1747 "Content-Type: application/json\r\n"
1748 "Server: bitcoin-json-rpc/%s\r\n"
1753 rfc1123Time().c_str(),
1755 FormatFullVersion().c_str(),
1759 int ReadHTTPStatus(std::basic_istream<char>& stream)
1762 getline(stream, str);
1763 vector<string> vWords;
1764 boost::split(vWords, str, boost::is_any_of(" "));
1765 if (vWords.size() < 2)
1767 return atoi(vWords[1].c_str());
1770 int ReadHTTPHeader(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet)
1776 std::getline(stream, str);
1777 if (str.empty() || str == "\r")
1779 string::size_type nColon = str.find(":");
1780 if (nColon != string::npos)
1782 string strHeader = str.substr(0, nColon);
1783 boost::trim(strHeader);
1784 boost::to_lower(strHeader);
1785 string strValue = str.substr(nColon+1);
1786 boost::trim(strValue);
1787 mapHeadersRet[strHeader] = strValue;
1788 if (strHeader == "content-length")
1789 nLen = atoi(strValue.c_str());
1795 int ReadHTTP(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet, string& strMessageRet)
1797 mapHeadersRet.clear();
1801 int nStatus = ReadHTTPStatus(stream);
1804 int nLen = ReadHTTPHeader(stream, mapHeadersRet);
1805 if (nLen < 0 || nLen > MAX_SIZE)
1811 vector<char> vch(nLen);
1812 stream.read(&vch[0], nLen);
1813 strMessageRet = string(vch.begin(), vch.end());
1819 string EncodeBase64(string s)
1824 b64 = BIO_new(BIO_f_base64());
1825 BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
1826 bmem = BIO_new(BIO_s_mem());
1827 b64 = BIO_push(b64, bmem);
1828 BIO_write(b64, s.c_str(), s.size());
1830 BIO_get_mem_ptr(b64, &bptr);
1832 string result(bptr->data, bptr->length);
1838 string DecodeBase64(string s)
1842 char* buffer = static_cast<char*>(calloc(s.size(), sizeof(char)));
1844 b64 = BIO_new(BIO_f_base64());
1845 BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
1846 bmem = BIO_new_mem_buf(const_cast<char*>(s.c_str()), s.size());
1847 bmem = BIO_push(b64, bmem);
1848 BIO_read(bmem, buffer, s.size());
1851 string result(buffer);
1856 bool HTTPAuthorized(map<string, string>& mapHeaders)
1858 string strAuth = mapHeaders["authorization"];
1859 if (strAuth.substr(0,6) != "Basic ")
1861 string strUserPass64 = strAuth.substr(6); boost::trim(strUserPass64);
1862 string strUserPass = DecodeBase64(strUserPass64);
1863 string::size_type nColon = strUserPass.find(":");
1864 if (nColon == string::npos)
1866 string strUser = strUserPass.substr(0, nColon);
1867 string strPassword = strUserPass.substr(nColon+1);
1868 return (strUser == mapArgs["-rpcuser"] && strPassword == mapArgs["-rpcpassword"]);
1872 // JSON-RPC protocol. Bitcoin speaks version 1.0 for maximum compatibility,
1873 // but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
1874 // unspecified (HTTP errors and contents of 'error').
1876 // 1.0 spec: http://json-rpc.org/wiki/specification
1877 // 1.2 spec: http://groups.google.com/group/json-rpc/web/json-rpc-over-http
1878 // http://www.codeproject.com/KB/recipes/JSON_Spirit.aspx
1881 string JSONRPCRequest(const string& strMethod, const Array& params, const Value& id)
1884 request.push_back(Pair("method", strMethod));
1885 request.push_back(Pair("params", params));
1886 request.push_back(Pair("id", id));
1887 return write_string(Value(request), false) + "\n";
1890 string JSONRPCReply(const Value& result, const Value& error, const Value& id)
1893 if (error.type() != null_type)
1894 reply.push_back(Pair("result", Value::null));
1896 reply.push_back(Pair("result", result));
1897 reply.push_back(Pair("error", error));
1898 reply.push_back(Pair("id", id));
1899 return write_string(Value(reply), false) + "\n";
1902 void ErrorReply(std::ostream& stream, const Object& objError, const Value& id)
1904 // Send error reply from json-rpc error object
1906 int code = find_value(objError, "code").get_int();
1907 if (code == -32600) nStatus = 400;
1908 else if (code == -32601) nStatus = 404;
1909 string strReply = JSONRPCReply(Value::null, objError, id);
1910 stream << HTTPReply(nStatus, strReply) << std::flush;
1913 bool ClientAllowed(const string& strAddress)
1915 if (strAddress == asio::ip::address_v4::loopback().to_string())
1917 const vector<string>& vAllow = mapMultiArgs["-rpcallowip"];
1918 BOOST_FOREACH(string strAllow, vAllow)
1919 if (WildcardMatch(strAddress, strAllow))
1926 // IOStream device that speaks SSL but can also speak non-SSL
1928 class SSLIOStreamDevice : public iostreams::device<iostreams::bidirectional> {
1930 SSLIOStreamDevice(SSLStream &streamIn, bool fUseSSLIn) : stream(streamIn)
1932 fUseSSL = fUseSSLIn;
1933 fNeedHandshake = fUseSSLIn;
1936 void handshake(ssl::stream_base::handshake_type role)
1938 if (!fNeedHandshake) return;
1939 fNeedHandshake = false;
1940 stream.handshake(role);
1942 std::streamsize read(char* s, std::streamsize n)
1944 handshake(ssl::stream_base::server); // HTTPS servers read first
1945 if (fUseSSL) return stream.read_some(asio::buffer(s, n));
1946 return stream.next_layer().read_some(asio::buffer(s, n));
1948 std::streamsize write(const char* s, std::streamsize n)
1950 handshake(ssl::stream_base::client); // HTTPS clients write first
1951 if (fUseSSL) return asio::write(stream, asio::buffer(s, n));
1952 return asio::write(stream.next_layer(), asio::buffer(s, n));
1954 bool connect(const std::string& server, const std::string& port)
1956 ip::tcp::resolver resolver(stream.get_io_service());
1957 ip::tcp::resolver::query query(server.c_str(), port.c_str());
1958 ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
1959 ip::tcp::resolver::iterator end;
1960 boost::system::error_code error = asio::error::host_not_found;
1961 while (error && endpoint_iterator != end)
1963 stream.lowest_layer().close();
1964 stream.lowest_layer().connect(*endpoint_iterator++, error);
1972 bool fNeedHandshake;
1978 void ThreadRPCServer(void* parg)
1980 IMPLEMENT_RANDOMIZE_STACK(ThreadRPCServer(parg));
1983 vnThreadsRunning[4]++;
1984 ThreadRPCServer2(parg);
1985 vnThreadsRunning[4]--;
1987 catch (std::exception& e) {
1988 vnThreadsRunning[4]--;
1989 PrintException(&e, "ThreadRPCServer()");
1991 vnThreadsRunning[4]--;
1992 PrintException(NULL, "ThreadRPCServer()");
1994 printf("ThreadRPCServer exiting\n");
1997 void ThreadRPCServer2(void* parg)
1999 printf("ThreadRPCServer started\n");
2001 if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
2003 string strWhatAmI = "To use bitcoind";
2004 if (mapArgs.count("-server"))
2005 strWhatAmI = strprintf(_("To use the %s option"), "\"-server\"");
2006 else if (mapArgs.count("-daemon"))
2007 strWhatAmI = strprintf(_("To use the %s option"), "\"-daemon\"");
2009 _("Warning: %s, you must set rpcpassword=<password>\nin the configuration file: %s\n"
2010 "If the file does not exist, create it with owner-readable-only file permissions.\n"),
2012 GetConfigFile().c_str());
2013 CreateThread(Shutdown, NULL);
2017 bool fUseSSL = GetBoolArg("-rpcssl");
2018 asio::ip::address bindAddress = mapArgs.count("-rpcallowip") ? asio::ip::address_v4::any() : asio::ip::address_v4::loopback();
2020 asio::io_service io_service;
2021 ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", 8332));
2022 ip::tcp::acceptor acceptor(io_service, endpoint);
2024 acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
2027 ssl::context context(io_service, ssl::context::sslv23);
2030 context.set_options(ssl::context::no_sslv2);
2031 filesystem::path certfile = GetArg("-rpcsslcertificatechainfile", "server.cert");
2032 if (!certfile.is_complete()) certfile = filesystem::path(GetDataDir()) / certfile;
2033 if (filesystem::exists(certfile)) context.use_certificate_chain_file(certfile.string().c_str());
2034 else printf("ThreadRPCServer ERROR: missing server certificate file %s\n", certfile.string().c_str());
2035 filesystem::path pkfile = GetArg("-rpcsslprivatekeyfile", "server.pem");
2036 if (!pkfile.is_complete()) pkfile = filesystem::path(GetDataDir()) / pkfile;
2037 if (filesystem::exists(pkfile)) context.use_private_key_file(pkfile.string().c_str(), ssl::context::pem);
2038 else printf("ThreadRPCServer ERROR: missing server private key file %s\n", pkfile.string().c_str());
2040 string ciphers = GetArg("-rpcsslciphers",
2041 "TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH");
2042 SSL_CTX_set_cipher_list(context.impl(), ciphers.c_str());
2046 throw runtime_error("-rpcssl=1, but bitcoin compiled without full openssl libraries.");
2051 // Accept connection
2053 SSLStream sslStream(io_service, context);
2054 SSLIOStreamDevice d(sslStream, fUseSSL);
2055 iostreams::stream<SSLIOStreamDevice> stream(d);
2057 ip::tcp::iostream stream;
2060 ip::tcp::endpoint peer;
2061 vnThreadsRunning[4]--;
2063 acceptor.accept(sslStream.lowest_layer(), peer);
2065 acceptor.accept(*stream.rdbuf(), peer);
2067 vnThreadsRunning[4]++;
2071 // Restrict callers by IP
2072 if (!ClientAllowed(peer.address().to_string()))
2074 // Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake.
2076 stream << HTTPReply(403, "") << std::flush;
2080 map<string, string> mapHeaders;
2083 boost::thread api_caller(ReadHTTP, boost::ref(stream), boost::ref(mapHeaders), boost::ref(strRequest));
2084 if (!api_caller.timed_join(boost::posix_time::seconds(GetArg("-rpctimeout", 30))))
2087 printf("ThreadRPCServer ReadHTTP timeout\n");
2091 // Check authorization
2092 if (mapHeaders.count("authorization") == 0)
2094 stream << HTTPReply(401, "") << std::flush;
2097 if (!HTTPAuthorized(mapHeaders))
2099 // Deter brute-forcing short passwords
2100 if (mapArgs["-rpcpassword"].size() < 15)
2103 stream << HTTPReply(401, "") << std::flush;
2104 printf("ThreadRPCServer incorrect password attempt\n");
2108 Value id = Value::null;
2113 if (!read_string(strRequest, valRequest) || valRequest.type() != obj_type)
2114 throw JSONRPCError(-32700, "Parse error");
2115 const Object& request = valRequest.get_obj();
2117 // Parse id now so errors from here on will have the id
2118 id = find_value(request, "id");
2121 Value valMethod = find_value(request, "method");
2122 if (valMethod.type() == null_type)
2123 throw JSONRPCError(-32600, "Missing method");
2124 if (valMethod.type() != str_type)
2125 throw JSONRPCError(-32600, "Method must be a string");
2126 string strMethod = valMethod.get_str();
2127 if (strMethod != "getwork")
2128 printf("ThreadRPCServer method=%s\n", strMethod.c_str());
2131 Value valParams = find_value(request, "params");
2133 if (valParams.type() == array_type)
2134 params = valParams.get_array();
2135 else if (valParams.type() == null_type)
2138 throw JSONRPCError(-32600, "Params must be an array");
2141 map<string, rpcfn_type>::iterator mi = mapCallTable.find(strMethod);
2142 if (mi == mapCallTable.end())
2143 throw JSONRPCError(-32601, "Method not found");
2145 // Observe safe mode
2146 string strWarning = GetWarnings("rpc");
2147 if (strWarning != "" && !GetBoolArg("-disablesafemode") && !setAllowInSafeMode.count(strMethod))
2148 throw JSONRPCError(-2, string("Safe mode: ") + strWarning);
2154 CRITICAL_BLOCK(cs_main)
2155 CRITICAL_BLOCK(pwalletMain->cs_wallet)
2156 result = (*(*mi).second)(params, false);
2159 string strReply = JSONRPCReply(result, Value::null, id);
2160 stream << HTTPReply(200, strReply) << std::flush;
2162 catch (std::exception& e)
2164 ErrorReply(stream, JSONRPCError(-1, e.what()), id);
2167 catch (Object& objError)
2169 ErrorReply(stream, objError, id);
2171 catch (std::exception& e)
2173 ErrorReply(stream, JSONRPCError(-32700, e.what()), id);
2181 Object CallRPC(const string& strMethod, const Array& params)
2183 if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
2184 throw runtime_error(strprintf(
2185 _("You must set rpcpassword=<password> in the configuration file:\n%s\n"
2186 "If the file does not exist, create it with owner-readable-only file permissions."),
2187 GetConfigFile().c_str()));
2189 // Connect to localhost
2190 bool fUseSSL = GetBoolArg("-rpcssl");
2192 asio::io_service io_service;
2193 ssl::context context(io_service, ssl::context::sslv23);
2194 context.set_options(ssl::context::no_sslv2);
2195 SSLStream sslStream(io_service, context);
2196 SSLIOStreamDevice d(sslStream, fUseSSL);
2197 iostreams::stream<SSLIOStreamDevice> stream(d);
2198 if (!d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332")))
2199 throw runtime_error("couldn't connect to server");
2202 throw runtime_error("-rpcssl=1, but bitcoin compiled without full openssl libraries.");
2204 ip::tcp::iostream stream(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332"));
2206 throw runtime_error("couldn't connect to server");
2210 // HTTP basic authentication
2211 string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
2212 map<string, string> mapRequestHeaders;
2213 mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64;
2216 string strRequest = JSONRPCRequest(strMethod, params, 1);
2217 string strPost = HTTPPost(strRequest, mapRequestHeaders);
2218 stream << strPost << std::flush;
2221 map<string, string> mapHeaders;
2223 int nStatus = ReadHTTP(stream, mapHeaders, strReply);
2225 throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
2226 else if (nStatus >= 400 && nStatus != 400 && nStatus != 404 && nStatus != 500)
2227 throw runtime_error(strprintf("server returned HTTP error %d", nStatus));
2228 else if (strReply.empty())
2229 throw runtime_error("no response from server");
2233 if (!read_string(strReply, valReply))
2234 throw runtime_error("couldn't parse reply from server");
2235 const Object& reply = valReply.get_obj();
2237 throw runtime_error("expected reply to have result, error and id properties");
2245 template<typename T>
2246 void ConvertTo(Value& value)
2248 if (value.type() == str_type)
2250 // reinterpret string as unquoted json value
2252 if (!read_string(value.get_str(), value2))
2253 throw runtime_error("type mismatch");
2254 value = value2.get_value<T>();
2258 value = value.get_value<T>();
2262 int CommandLineRPC(int argc, char *argv[])
2269 while (argc > 1 && IsSwitchChar(argv[1][0]))
2277 throw runtime_error("too few parameters");
2278 string strMethod = argv[1];
2280 // Parameters default to strings
2282 for (int i = 2; i < argc; i++)
2283 params.push_back(argv[i]);
2284 int n = params.size();
2287 // Special case non-string parameter types
2289 if (strMethod == "setgenerate" && n > 0) ConvertTo<bool>(params[0]);
2290 if (strMethod == "setgenerate" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2291 if (strMethod == "sendtoaddress" && n > 1) ConvertTo<double>(params[1]);
2292 if (strMethod == "settxfee" && n > 0) ConvertTo<double>(params[0]);
2293 if (strMethod == "getamountreceived" && n > 1) ConvertTo<boost::int64_t>(params[1]); // deprecated
2294 if (strMethod == "getreceivedbyaddress" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2295 if (strMethod == "getreceivedbyaccount" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2296 if (strMethod == "getreceivedbylabel" && n > 1) ConvertTo<boost::int64_t>(params[1]); // deprecated
2297 if (strMethod == "getallreceived" && n > 0) ConvertTo<boost::int64_t>(params[0]); // deprecated
2298 if (strMethod == "getallreceived" && n > 1) ConvertTo<bool>(params[1]); // deprecated
2299 if (strMethod == "listreceivedbyaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2300 if (strMethod == "listreceivedbyaddress" && n > 1) ConvertTo<bool>(params[1]);
2301 if (strMethod == "listreceivedbyaccount" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2302 if (strMethod == "listreceivedbyaccount" && n > 1) ConvertTo<bool>(params[1]);
2303 if (strMethod == "listreceivedbylabel" && n > 0) ConvertTo<boost::int64_t>(params[0]); // deprecated
2304 if (strMethod == "listreceivedbylabel" && n > 1) ConvertTo<bool>(params[1]); // deprecated
2305 if (strMethod == "getbalance" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2306 if (strMethod == "move" && n > 2) ConvertTo<double>(params[2]);
2307 if (strMethod == "move" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2308 if (strMethod == "sendfrom" && n > 2) ConvertTo<double>(params[2]);
2309 if (strMethod == "sendfrom" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2310 if (strMethod == "listtransactions" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2311 if (strMethod == "listtransactions" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2312 if (strMethod == "listaccounts" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2313 if (strMethod == "walletpassphrase" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2314 if (strMethod == "sendmany" && n > 1)
2316 string s = params[1].get_str();
2318 if (!read_string(s, v) || v.type() != obj_type)
2319 throw runtime_error("type mismatch");
2320 params[1] = v.get_obj();
2322 if (strMethod == "sendmany" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2325 Object reply = CallRPC(strMethod, params);
2328 const Value& result = find_value(reply, "result");
2329 const Value& error = find_value(reply, "error");
2331 if (error.type() != null_type)
2334 strPrint = "error: " + write_string(error, false);
2335 int code = find_value(error.get_obj(), "code").get_int();
2341 if (result.type() == null_type)
2343 else if (result.type() == str_type)
2344 strPrint = result.get_str();
2346 strPrint = write_string(result, true);
2349 catch (std::exception& e)
2351 strPrint = string("error: ") + e.what();
2356 PrintException(NULL, "CommandLineRPC()");
2361 #if defined(__WXMSW__) && defined(GUI)
2362 // Windows GUI apps can't print to command line,
2363 // so settle for a message box yuck
2364 MyMessageBox(strPrint, "Bitcoin", wxOK);
2366 fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
2376 int main(int argc, char *argv[])
2379 // Turn off microsoft heap dump noise
2380 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
2381 _CrtSetReportFile(_CRT_WARN, CreateFile("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0));
2383 setbuf(stdin, NULL);
2384 setbuf(stdout, NULL);
2385 setbuf(stderr, NULL);
2389 if (argc >= 2 && string(argv[1]) == "-server")
2391 printf("server ready\n");
2392 ThreadRPCServer(NULL);
2396 return CommandLineRPC(argc, argv);
2399 catch (std::exception& e) {
2400 PrintException(&e, "main()");
2402 PrintException(NULL, "main()");