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 > 21000000.0)
79 throw JSONRPCError(-3, "Invalid amount");
80 int64 nAmount = roundint64(dAmount * COIN);
81 if (!MoneyRange(nAmount))
82 throw JSONRPCError(-3, "Invalid amount");
86 Value ValueFromAmount(int64 amount)
88 return (double)amount / (double)COIN;
91 void WalletTxToJSON(const CWalletTx& wtx, Object& entry)
93 entry.push_back(Pair("confirmations", wtx.GetDepthInMainChain()));
94 entry.push_back(Pair("txid", wtx.GetHash().GetHex()));
95 entry.push_back(Pair("time", (boost::int64_t)wtx.GetTxTime()));
96 BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue)
97 entry.push_back(Pair(item.first, item.second));
100 string AccountFromValue(const Value& value)
102 string strAccount = value.get_str();
103 if (strAccount == "*")
104 throw JSONRPCError(-11, "Invalid account name");
111 /// Note: This interface may still be subject to change.
115 Value help(const Array& params, bool fHelp)
117 if (fHelp || params.size() > 1)
120 "List commands, or get help for a command.");
123 if (params.size() > 0)
124 strCommand = params[0].get_str();
127 set<rpcfn_type> setDone;
128 for (map<string, rpcfn_type>::iterator mi = mapCallTable.begin(); mi != mapCallTable.end(); ++mi)
130 string strMethod = (*mi).first;
131 // We already filter duplicates, but these deprecated screw up the sort order
132 if (strMethod == "getamountreceived" ||
133 strMethod == "getallreceived" ||
134 (strMethod.find("label") != string::npos))
136 if (strCommand != "" && strMethod != strCommand)
141 rpcfn_type pfn = (*mi).second;
142 if (setDone.insert(pfn).second)
143 (*pfn)(params, true);
145 catch (std::exception& e)
147 // Help text is returned in an exception
148 string strHelp = string(e.what());
149 if (strCommand == "")
150 if (strHelp.find('\n') != -1)
151 strHelp = strHelp.substr(0, strHelp.find('\n'));
152 strRet += strHelp + "\n";
156 strRet = strprintf("help: unknown command: %s\n", strCommand.c_str());
157 strRet = strRet.substr(0,strRet.size()-1);
162 Value stop(const Array& params, bool fHelp)
164 if (fHelp || params.size() != 0)
167 "Stop bitcoin server.");
169 // Shutdown will take long enough that the response should get back
170 CreateThread(Shutdown, NULL);
171 return "bitcoin server stopping";
175 Value getblockcount(const Array& params, bool fHelp)
177 if (fHelp || params.size() != 0)
180 "Returns the number of blocks in the longest block chain.");
186 Value getblocknumber(const Array& params, bool fHelp)
188 if (fHelp || params.size() != 0)
191 "Returns the block number of the latest block in the longest block chain.");
197 Value getconnectioncount(const Array& params, bool fHelp)
199 if (fHelp || params.size() != 0)
201 "getconnectioncount\n"
202 "Returns the number of connections to other nodes.");
204 return (int)vNodes.size();
208 double GetDifficulty()
210 // Floating point number that is a multiple of the minimum difficulty,
211 // minimum difficulty = 1.0.
213 if (pindexBest == NULL)
215 int nShift = (pindexBest->nBits >> 24) & 0xff;
218 (double)0x0000ffff / (double)(pindexBest->nBits & 0x00ffffff);
234 Value getdifficulty(const Array& params, bool fHelp)
236 if (fHelp || params.size() != 0)
239 "Returns the proof-of-work difficulty as a multiple of the minimum difficulty.");
241 return GetDifficulty();
245 Value getgenerate(const Array& params, bool fHelp)
247 if (fHelp || params.size() != 0)
250 "Returns true or false.");
252 return (bool)fGenerateBitcoins;
256 Value setgenerate(const Array& params, bool fHelp)
258 if (fHelp || params.size() < 1 || params.size() > 2)
260 "setgenerate <generate> [genproclimit]\n"
261 "<generate> is true or false to turn generation on or off.\n"
262 "Generation is limited to [genproclimit] processors, -1 is unlimited.");
264 bool fGenerate = true;
265 if (params.size() > 0)
266 fGenerate = params[0].get_bool();
268 if (params.size() > 1)
270 int nGenProcLimit = params[1].get_int();
271 fLimitProcessors = (nGenProcLimit != -1);
272 WriteSetting("fLimitProcessors", fLimitProcessors);
273 if (nGenProcLimit != -1)
274 WriteSetting("nLimitProcessors", nLimitProcessors = nGenProcLimit);
275 if (nGenProcLimit == 0)
279 GenerateBitcoins(fGenerate, pwalletMain);
284 Value gethashespersec(const Array& params, bool fHelp)
286 if (fHelp || params.size() != 0)
289 "Returns a recent hashes per second performance measurement while generating.");
291 if (GetTimeMillis() - nHPSTimerStart > 8000)
292 return (boost::int64_t)0;
293 return (boost::int64_t)dHashesPerSec;
297 Value getinfo(const Array& params, bool fHelp)
299 if (fHelp || params.size() != 0)
302 "Returns an object containing various state info.");
305 obj.push_back(Pair("version", (int)VERSION));
306 obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance())));
307 obj.push_back(Pair("blocks", (int)nBestHeight));
308 obj.push_back(Pair("connections", (int)vNodes.size()));
309 obj.push_back(Pair("proxy", (fUseProxy ? addrProxy.ToStringIPPort() : string())));
310 obj.push_back(Pair("generate", (bool)fGenerateBitcoins));
311 obj.push_back(Pair("genproclimit", (int)(fLimitProcessors ? nLimitProcessors : -1)));
312 obj.push_back(Pair("difficulty", (double)GetDifficulty()));
313 obj.push_back(Pair("hashespersec", gethashespersec(params, false)));
314 obj.push_back(Pair("testnet", fTestNet));
315 obj.push_back(Pair("keypoololdest", (boost::int64_t)pwalletMain->GetOldestKeyPoolTime()));
316 obj.push_back(Pair("keypoolsize", pwalletMain->GetKeyPoolSize()));
317 obj.push_back(Pair("paytxfee", ValueFromAmount(nTransactionFee)));
318 if (pwalletMain->IsCrypted())
319 obj.push_back(Pair("unlocked_until", (boost::int64_t)nWalletUnlockTime));
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 if (!pwalletMain->IsLocked())
335 pwalletMain->TopUpKeyPool();
337 if (pwalletMain->GetKeyPoolSize() < 1)
338 throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
340 // Parse the account first so we don't generate a key if there's an error
342 if (params.size() > 0)
343 strAccount = AccountFromValue(params[0]);
345 // Generate a new key that is added to wallet
346 CBitcoinAddress address(pwalletMain->GetOrReuseKeyFromPool());
348 // This could be done in the same main CS as GetKeyFromKeyPool.
349 pwalletMain->SetAddressBookName(address, strAccount);
351 return address.ToString();
355 CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false)
357 CWalletDB walletdb(pwalletMain->strWalletFile);
360 walletdb.ReadAccount(strAccount, account);
362 bool bKeyUsed = false;
364 // Check if the current key has been used
365 if (!account.vchPubKey.empty())
367 CScript scriptPubKey;
368 scriptPubKey.SetBitcoinAddress(account.vchPubKey);
369 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
370 it != pwalletMain->mapWallet.end() && !account.vchPubKey.empty();
373 const CWalletTx& wtx = (*it).second;
374 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
375 if (txout.scriptPubKey == scriptPubKey)
380 // Generate a new key
381 if (account.vchPubKey.empty() || bForceNew || bKeyUsed)
383 if (pwalletMain->GetKeyPoolSize() < 1)
385 if (bKeyUsed || bForceNew)
386 throw JSONRPCError(-12, "Error: Keypool ran out, please call topupkeypool first");
390 account.vchPubKey = pwalletMain->GetOrReuseKeyFromPool();
391 pwalletMain->SetAddressBookName(CBitcoinAddress(account.vchPubKey), strAccount);
392 walletdb.WriteAccount(strAccount, account);
396 return CBitcoinAddress(account.vchPubKey);
399 Value getaccountaddress(const Array& params, bool fHelp)
401 if (fHelp || params.size() != 1)
403 "getaccountaddress <account>\n"
404 "Returns the current bitcoin address for receiving payments to this account.");
406 // Parse the account first so we don't generate a key if there's an error
407 string strAccount = AccountFromValue(params[0]);
411 ret = GetAccountAddress(strAccount).ToString();
418 Value setaccount(const Array& params, bool fHelp)
420 if (fHelp || params.size() < 1 || params.size() > 2)
422 "setaccount <bitcoinaddress> <account>\n"
423 "Sets the account associated with the given address.");
425 CBitcoinAddress address(params[0].get_str());
426 if (!address.IsValid())
427 throw JSONRPCError(-5, "Invalid bitcoin address");
431 if (params.size() > 1)
432 strAccount = AccountFromValue(params[1]);
434 // Detect when changing the account of an address that is the 'unused current key' of another account:
435 if (pwalletMain->mapAddressBook.count(address))
437 string strOldAccount = pwalletMain->mapAddressBook[address];
438 if (address == GetAccountAddress(strOldAccount))
439 GetAccountAddress(strOldAccount, true);
442 pwalletMain->SetAddressBookName(address, strAccount);
448 Value getaccount(const Array& params, bool fHelp)
450 if (fHelp || params.size() != 1)
452 "getaccount <bitcoinaddress>\n"
453 "Returns the account associated with the given address.");
455 CBitcoinAddress address(params[0].get_str());
456 if (!address.IsValid())
457 throw JSONRPCError(-5, "Invalid bitcoin address");
460 map<CBitcoinAddress, string>::iterator mi = pwalletMain->mapAddressBook.find(address);
461 if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.empty())
462 strAccount = (*mi).second;
467 Value getaddressesbyaccount(const Array& params, bool fHelp)
469 if (fHelp || params.size() != 1)
471 "getaddressesbyaccount <account>\n"
472 "Returns the list of addresses for the given account.");
474 string strAccount = AccountFromValue(params[0]);
476 // Find all addresses that have the given account
478 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
480 const CBitcoinAddress& address = item.first;
481 const string& strName = item.second;
482 if (strName == strAccount)
483 ret.push_back(address.ToString());
488 Value settxfee(const Array& params, bool fHelp)
490 if (fHelp || params.size() < 1 || params.size() > 1)
492 "settxfee <amount>\n"
493 "<amount> is a real and is rounded to the nearest 0.00000001");
497 if (params[0].get_real() != 0.0)
498 nAmount = AmountFromValue(params[0]); // rejects 0.0 amounts
500 nTransactionFee = nAmount;
504 Value sendtoaddress(const Array& params, bool fHelp)
506 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
508 "sendtoaddress <bitcoinaddress> <amount> [comment] [comment-to]\n"
509 "<amount> is a real and is rounded to the nearest 0.00000001\n"
510 "requires wallet passphrase to be set with walletpassphrase first");
511 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
513 "sendtoaddress <bitcoinaddress> <amount> [comment] [comment-to]\n"
514 "<amount> is a real and is rounded to the nearest 0.00000001");
516 CBitcoinAddress address(params[0].get_str());
517 if (!address.IsValid())
518 throw JSONRPCError(-5, "Invalid bitcoin address");
521 int64 nAmount = AmountFromValue(params[1]);
525 if (params.size() > 2 && params[2].type() != null_type && !params[2].get_str().empty())
526 wtx.mapValue["comment"] = params[2].get_str();
527 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
528 wtx.mapValue["to"] = params[3].get_str();
530 if (pwalletMain->IsLocked())
531 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
533 string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
535 throw JSONRPCError(-4, strError);
537 return wtx.GetHash().GetHex();
541 Value getreceivedbyaddress(const Array& params, bool fHelp)
543 if (fHelp || params.size() < 1 || params.size() > 2)
545 "getreceivedbyaddress <bitcoinaddress> [minconf=1]\n"
546 "Returns the total amount received by <bitcoinaddress> in transactions with at least [minconf] confirmations.");
549 CBitcoinAddress address = CBitcoinAddress(params[0].get_str());
550 CScript scriptPubKey;
551 if (!address.IsValid())
552 throw JSONRPCError(-5, "Invalid bitcoin address");
553 scriptPubKey.SetBitcoinAddress(address);
554 if (!IsMine(*pwalletMain,scriptPubKey))
557 // Minimum confirmations
559 if (params.size() > 1)
560 nMinDepth = params[1].get_int();
564 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
566 const CWalletTx& wtx = (*it).second;
567 if (wtx.IsCoinBase() || !wtx.IsFinal())
570 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
571 if (txout.scriptPubKey == scriptPubKey)
572 if (wtx.GetDepthInMainChain() >= nMinDepth)
573 nAmount += txout.nValue;
576 return ValueFromAmount(nAmount);
580 void GetAccountAddresses(string strAccount, set<CBitcoinAddress>& setAddress)
582 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
584 const CBitcoinAddress& address = item.first;
585 const string& strName = item.second;
586 if (strName == strAccount)
587 setAddress.insert(address);
592 Value getreceivedbyaccount(const Array& params, bool fHelp)
594 if (fHelp || params.size() < 1 || params.size() > 2)
596 "getreceivedbyaccount <account> [minconf=1]\n"
597 "Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.");
599 // Minimum confirmations
601 if (params.size() > 1)
602 nMinDepth = params[1].get_int();
604 // Get the set of pub keys that have the label
605 string strAccount = AccountFromValue(params[0]);
606 set<CBitcoinAddress> setAddress;
607 GetAccountAddresses(strAccount, setAddress);
611 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
613 const CWalletTx& wtx = (*it).second;
614 if (wtx.IsCoinBase() || !wtx.IsFinal())
617 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
619 CBitcoinAddress address;
620 if (ExtractAddress(txout.scriptPubKey, pwalletMain, address) && setAddress.count(address))
621 if (wtx.GetDepthInMainChain() >= nMinDepth)
622 nAmount += txout.nValue;
626 return (double)nAmount / (double)COIN;
630 int64 GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth)
634 // Tally wallet transactions
635 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
637 const CWalletTx& wtx = (*it).second;
641 int64 nGenerated, nReceived, nSent, nFee;
642 wtx.GetAccountAmounts(strAccount, nGenerated, nReceived, nSent, nFee);
644 if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
645 nBalance += nReceived;
646 nBalance += nGenerated - nSent - nFee;
649 // Tally internal accounting entries
650 nBalance += walletdb.GetAccountCreditDebit(strAccount);
655 int64 GetAccountBalance(const string& strAccount, int nMinDepth)
657 CWalletDB walletdb(pwalletMain->strWalletFile);
658 return GetAccountBalance(walletdb, strAccount, nMinDepth);
662 Value getbalance(const Array& params, bool fHelp)
664 if (fHelp || params.size() > 2)
666 "getbalance [account] [minconf=1]\n"
667 "If [account] is not specified, returns the server's total available balance.\n"
668 "If [account] is specified, returns the balance in the account.");
670 if (params.size() == 0)
671 return ValueFromAmount(pwalletMain->GetBalance());
674 if (params.size() > 1)
675 nMinDepth = params[1].get_int();
677 if (params[0].get_str() == "*") {
678 // Calculate total balance a different way from GetBalance()
679 // (GetBalance() sums up all unspent TxOuts)
680 // getbalance and getbalance '*' should always return the same number.
682 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
684 const CWalletTx& wtx = (*it).second;
688 int64 allGeneratedImmature, allGeneratedMature, allFee;
689 allGeneratedImmature = allGeneratedMature = allFee = 0;
690 string strSentAccount;
691 list<pair<CBitcoinAddress, int64> > listReceived;
692 list<pair<CBitcoinAddress, int64> > listSent;
693 wtx.GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount);
694 if (wtx.GetDepthInMainChain() >= nMinDepth)
695 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listReceived)
696 nBalance += r.second;
697 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listSent)
698 nBalance -= r.second;
700 nBalance += allGeneratedMature;
702 return ValueFromAmount(nBalance);
705 string strAccount = AccountFromValue(params[0]);
707 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
709 return ValueFromAmount(nBalance);
713 Value movecmd(const Array& params, bool fHelp)
715 if (fHelp || params.size() < 3 || params.size() > 5)
717 "move <fromaccount> <toaccount> <amount> [minconf=1] [comment]\n"
718 "Move from one account in your wallet to another.");
720 string strFrom = AccountFromValue(params[0]);
721 string strTo = AccountFromValue(params[1]);
722 int64 nAmount = AmountFromValue(params[2]);
723 if (params.size() > 3)
724 // unused parameter, used to be nMinDepth, keep type-checking it though
725 (void)params[3].get_int();
727 if (params.size() > 4)
728 strComment = params[4].get_str();
730 CWalletDB walletdb(pwalletMain->strWalletFile);
733 int64 nNow = GetAdjustedTime();
736 CAccountingEntry debit;
737 debit.strAccount = strFrom;
738 debit.nCreditDebit = -nAmount;
740 debit.strOtherAccount = strTo;
741 debit.strComment = strComment;
742 walletdb.WriteAccountingEntry(debit);
745 CAccountingEntry credit;
746 credit.strAccount = strTo;
747 credit.nCreditDebit = nAmount;
749 credit.strOtherAccount = strFrom;
750 credit.strComment = strComment;
751 walletdb.WriteAccountingEntry(credit);
753 walletdb.TxnCommit();
759 Value sendfrom(const Array& params, bool fHelp)
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\n"
765 "requires wallet passphrase to be set with walletpassphrase first");
766 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
768 "sendfrom <fromaccount> <tobitcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
769 "<amount> is a real and is rounded to the nearest 0.00000001");
771 string strAccount = AccountFromValue(params[0]);
772 CBitcoinAddress address(params[1].get_str());
773 if (!address.IsValid())
774 throw JSONRPCError(-5, "Invalid bitcoin address");
775 int64 nAmount = AmountFromValue(params[2]);
777 if (params.size() > 3)
778 nMinDepth = params[3].get_int();
781 wtx.strFromAccount = strAccount;
782 if (params.size() > 4 && params[4].type() != null_type && !params[4].get_str().empty())
783 wtx.mapValue["comment"] = params[4].get_str();
784 if (params.size() > 5 && params[5].type() != null_type && !params[5].get_str().empty())
785 wtx.mapValue["to"] = params[5].get_str();
787 if (pwalletMain->IsLocked())
788 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
791 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
792 if (nAmount > nBalance)
793 throw JSONRPCError(-6, "Account has insufficient funds");
796 string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
798 throw JSONRPCError(-4, strError);
800 return wtx.GetHash().GetHex();
804 Value sendmany(const Array& params, bool fHelp)
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\n"
810 "requires wallet passphrase to be set with walletpassphrase first");
811 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
813 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
814 "amounts are double-precision floating point numbers");
816 string strAccount = AccountFromValue(params[0]);
817 Object sendTo = params[1].get_obj();
819 if (params.size() > 2)
820 nMinDepth = params[2].get_int();
823 wtx.strFromAccount = strAccount;
824 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
825 wtx.mapValue["comment"] = params[3].get_str();
827 set<CBitcoinAddress> setAddress;
828 vector<pair<CScript, int64> > vecSend;
830 int64 totalAmount = 0;
831 BOOST_FOREACH(const Pair& s, sendTo)
833 CBitcoinAddress address(s.name_);
834 if (!address.IsValid())
835 throw JSONRPCError(-5, string("Invalid bitcoin address:")+s.name_);
837 if (setAddress.count(address))
838 throw JSONRPCError(-8, string("Invalid parameter, duplicated address: ")+s.name_);
839 setAddress.insert(address);
841 CScript scriptPubKey;
842 scriptPubKey.SetBitcoinAddress(address);
843 int64 nAmount = AmountFromValue(s.value_);
844 totalAmount += nAmount;
846 vecSend.push_back(make_pair(scriptPubKey, nAmount));
849 if (pwalletMain->IsLocked())
850 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
853 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
854 if (totalAmount > nBalance)
855 throw JSONRPCError(-6, "Account has insufficient funds");
858 CReserveKey keyChange(pwalletMain);
859 int64 nFeeRequired = 0;
860 bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired);
863 if (totalAmount + nFeeRequired > pwalletMain->GetBalance())
864 throw JSONRPCError(-6, "Insufficient funds");
865 throw JSONRPCError(-4, "Transaction creation failed");
867 if (!pwalletMain->CommitTransaction(wtx, keyChange))
868 throw JSONRPCError(-4, "Transaction commit failed");
870 return wtx.GetHash().GetHex();
885 Value ListReceived(const Array& params, bool fByAccounts)
887 // Minimum confirmations
889 if (params.size() > 0)
890 nMinDepth = params[0].get_int();
892 // Whether to include empty accounts
893 bool fIncludeEmpty = false;
894 if (params.size() > 1)
895 fIncludeEmpty = params[1].get_bool();
898 map<CBitcoinAddress, tallyitem> mapTally;
899 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
901 const CWalletTx& wtx = (*it).second;
902 if (wtx.IsCoinBase() || !wtx.IsFinal())
905 int nDepth = wtx.GetDepthInMainChain();
906 if (nDepth < nMinDepth)
909 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
911 CBitcoinAddress address;
912 if (!ExtractAddress(txout.scriptPubKey, pwalletMain, address) || !address.IsValid())
915 tallyitem& item = mapTally[address];
916 item.nAmount += txout.nValue;
917 item.nConf = min(item.nConf, nDepth);
923 map<string, tallyitem> mapAccountTally;
924 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
926 const CBitcoinAddress& address = item.first;
927 const string& strAccount = item.second;
928 map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
929 if (it == mapTally.end() && !fIncludeEmpty)
934 if (it != mapTally.end())
936 nAmount = (*it).second.nAmount;
937 nConf = (*it).second.nConf;
942 tallyitem& item = mapAccountTally[strAccount];
943 item.nAmount += nAmount;
944 item.nConf = min(item.nConf, nConf);
949 obj.push_back(Pair("address", address.ToString()));
950 obj.push_back(Pair("account", strAccount));
951 obj.push_back(Pair("label", strAccount)); // deprecated
952 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
953 obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf)));
960 for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
962 int64 nAmount = (*it).second.nAmount;
963 int nConf = (*it).second.nConf;
965 obj.push_back(Pair("account", (*it).first));
966 obj.push_back(Pair("label", (*it).first)); // deprecated
967 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
968 obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf)));
976 Value listreceivedbyaddress(const Array& params, bool fHelp)
978 if (fHelp || params.size() > 2)
980 "listreceivedbyaddress [minconf=1] [includeempty=false]\n"
981 "[minconf] is the minimum number of confirmations before payments are included.\n"
982 "[includeempty] whether to include addresses that haven't received any payments.\n"
983 "Returns an array of objects containing:\n"
984 " \"address\" : receiving address\n"
985 " \"account\" : the account of the receiving address\n"
986 " \"amount\" : total amount received by the address\n"
987 " \"confirmations\" : number of confirmations of the most recent transaction included");
989 return ListReceived(params, false);
992 Value listreceivedbyaccount(const Array& params, bool fHelp)
994 if (fHelp || params.size() > 2)
996 "listreceivedbyaccount [minconf=1] [includeempty=false]\n"
997 "[minconf] is the minimum number of confirmations before payments are included.\n"
998 "[includeempty] whether to include accounts that haven't received any payments.\n"
999 "Returns an array of objects containing:\n"
1000 " \"account\" : the account of the receiving addresses\n"
1001 " \"amount\" : total amount received by addresses with this account\n"
1002 " \"confirmations\" : number of confirmations of the most recent transaction included");
1004 return ListReceived(params, true);
1007 void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret)
1009 int64 nGeneratedImmature, nGeneratedMature, nFee;
1010 string strSentAccount;
1011 list<pair<CBitcoinAddress, int64> > listReceived;
1012 list<pair<CBitcoinAddress, int64> > listSent;
1013 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1015 bool fAllAccounts = (strAccount == string("*"));
1017 // Generated blocks assigned to account ""
1018 if ((nGeneratedMature+nGeneratedImmature) != 0 && (fAllAccounts || strAccount == ""))
1021 entry.push_back(Pair("account", string("")));
1022 if (nGeneratedImmature)
1024 entry.push_back(Pair("category", wtx.GetDepthInMainChain() ? "immature" : "orphan"));
1025 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedImmature)));
1029 entry.push_back(Pair("category", "generate"));
1030 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedMature)));
1033 WalletTxToJSON(wtx, entry);
1034 ret.push_back(entry);
1038 if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
1040 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1043 entry.push_back(Pair("account", strSentAccount));
1044 entry.push_back(Pair("address", s.first.ToString()));
1045 entry.push_back(Pair("category", "send"));
1046 entry.push_back(Pair("amount", ValueFromAmount(-s.second)));
1047 entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
1049 WalletTxToJSON(wtx, entry);
1050 ret.push_back(entry);
1055 if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
1056 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1059 if (pwalletMain->mapAddressBook.count(r.first))
1060 account = pwalletMain->mapAddressBook[r.first];
1061 if (fAllAccounts || (account == strAccount))
1064 entry.push_back(Pair("account", account));
1065 entry.push_back(Pair("address", r.first.ToString()));
1066 entry.push_back(Pair("category", "receive"));
1067 entry.push_back(Pair("amount", ValueFromAmount(r.second)));
1069 WalletTxToJSON(wtx, entry);
1070 ret.push_back(entry);
1075 void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret)
1077 bool fAllAccounts = (strAccount == string("*"));
1079 if (fAllAccounts || acentry.strAccount == strAccount)
1082 entry.push_back(Pair("account", acentry.strAccount));
1083 entry.push_back(Pair("category", "move"));
1084 entry.push_back(Pair("time", (boost::int64_t)acentry.nTime));
1085 entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
1086 entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
1087 entry.push_back(Pair("comment", acentry.strComment));
1088 ret.push_back(entry);
1092 Value listtransactions(const Array& params, bool fHelp)
1094 if (fHelp || params.size() > 3)
1095 throw runtime_error(
1096 "listtransactions [account] [count=10] [from=0]\n"
1097 "Returns up to [count] most recent transactions skipping the first [from] transactions for account [account].");
1099 string strAccount = "*";
1100 if (params.size() > 0)
1101 strAccount = params[0].get_str();
1103 if (params.size() > 1)
1104 nCount = params[1].get_int();
1106 if (params.size() > 2)
1107 nFrom = params[2].get_int();
1110 CWalletDB walletdb(pwalletMain->strWalletFile);
1112 // Firs: get all CWalletTx and CAccountingEntry into a sorted-by-time multimap:
1113 typedef pair<CWalletTx*, CAccountingEntry*> TxPair;
1114 typedef multimap<int64, TxPair > TxItems;
1117 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1119 CWalletTx* wtx = &((*it).second);
1120 txByTime.insert(make_pair(wtx->GetTxTime(), TxPair(wtx, (CAccountingEntry*)0)));
1122 list<CAccountingEntry> acentries;
1123 walletdb.ListAccountCreditDebit(strAccount, acentries);
1124 BOOST_FOREACH(CAccountingEntry& entry, acentries)
1126 txByTime.insert(make_pair(entry.nTime, TxPair((CWalletTx*)0, &entry)));
1129 // Now: iterate backwards until we have nCount items to return:
1130 TxItems::reverse_iterator it = txByTime.rbegin();
1131 if (txByTime.size() > nFrom) std::advance(it, nFrom);
1132 for (; it != txByTime.rend(); ++it)
1134 CWalletTx *const pwtx = (*it).second.first;
1136 ListTransactions(*pwtx, strAccount, 0, true, ret);
1137 CAccountingEntry *const pacentry = (*it).second.second;
1139 AcentryToJSON(*pacentry, strAccount, ret);
1141 if (ret.size() >= nCount) break;
1143 // ret is now newest to oldest
1145 // Make sure we return only last nCount items (sends-to-self might give us an extra):
1146 if (ret.size() > nCount)
1148 Array::iterator last = ret.begin();
1149 std::advance(last, nCount);
1150 ret.erase(last, ret.end());
1152 std::reverse(ret.begin(), ret.end()); // oldest to newest
1157 Value listaccounts(const Array& params, bool fHelp)
1159 if (fHelp || params.size() > 1)
1160 throw runtime_error(
1161 "listaccounts [minconf=1]\n"
1162 "Returns Object that has account names as keys, account balances as values.");
1165 if (params.size() > 0)
1166 nMinDepth = params[0].get_int();
1168 map<string, int64> mapAccountBalances;
1169 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& entry, pwalletMain->mapAddressBook) {
1170 if (pwalletMain->HaveKey(entry.first)) // This address belongs to me
1171 mapAccountBalances[entry.second] = 0;
1174 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1176 const CWalletTx& wtx = (*it).second;
1177 int64 nGeneratedImmature, nGeneratedMature, nFee;
1178 string strSentAccount;
1179 list<pair<CBitcoinAddress, int64> > listReceived;
1180 list<pair<CBitcoinAddress, int64> > listSent;
1181 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1182 mapAccountBalances[strSentAccount] -= nFee;
1183 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1184 mapAccountBalances[strSentAccount] -= s.second;
1185 if (wtx.GetDepthInMainChain() >= nMinDepth)
1187 mapAccountBalances[""] += nGeneratedMature;
1188 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1189 if (pwalletMain->mapAddressBook.count(r.first))
1190 mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second;
1192 mapAccountBalances[""] += r.second;
1196 list<CAccountingEntry> acentries;
1197 CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
1198 BOOST_FOREACH(const CAccountingEntry& entry, acentries)
1199 mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
1202 BOOST_FOREACH(const PAIRTYPE(string, int64)& accountBalance, mapAccountBalances) {
1203 ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
1208 Value gettransaction(const Array& params, bool fHelp)
1210 if (fHelp || params.size() != 1)
1211 throw runtime_error(
1212 "gettransaction <txid>\n"
1213 "Get detailed information about <txid>");
1216 hash.SetHex(params[0].get_str());
1220 if (!pwalletMain->mapWallet.count(hash))
1221 throw JSONRPCError(-5, "Invalid or non-wallet transaction id");
1222 const CWalletTx& wtx = pwalletMain->mapWallet[hash];
1224 int64 nCredit = wtx.GetCredit();
1225 int64 nDebit = wtx.GetDebit();
1226 int64 nNet = nCredit - nDebit;
1227 int64 nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0);
1229 entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
1231 entry.push_back(Pair("fee", ValueFromAmount(nFee)));
1233 WalletTxToJSON(pwalletMain->mapWallet[hash], entry);
1236 ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details);
1237 entry.push_back(Pair("details", details));
1243 Value backupwallet(const Array& params, bool fHelp)
1245 if (fHelp || params.size() != 1)
1246 throw runtime_error(
1247 "backupwallet <destination>\n"
1248 "Safely copies wallet.dat to destination, which can be a directory or a path with filename.");
1250 string strDest = params[0].get_str();
1251 BackupWallet(*pwalletMain, strDest);
1257 Value keypoolrefill(const Array& params, bool fHelp)
1259 if (pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1260 throw runtime_error(
1262 "Fills the keypool, requires wallet passphrase to be set.");
1263 if (!pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1264 throw runtime_error(
1266 "Fills the keypool.");
1268 if (pwalletMain->IsLocked())
1269 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
1271 pwalletMain->TopUpKeyPool();
1273 if (pwalletMain->GetKeyPoolSize() < GetArg("-keypool", 100))
1274 throw JSONRPCError(-4, "Error refreshing keypool.");
1280 void ThreadTopUpKeyPool(void* parg)
1282 pwalletMain->TopUpKeyPool();
1285 void ThreadCleanWalletPassphrase(void* parg)
1287 int64 nMyWakeTime = GetTime() + *((int*)parg);
1289 if (nWalletUnlockTime == 0)
1291 CRITICAL_BLOCK(cs_nWalletUnlockTime)
1293 nWalletUnlockTime = nMyWakeTime;
1296 while (GetTime() < nWalletUnlockTime)
1297 Sleep(GetTime() - nWalletUnlockTime);
1299 CRITICAL_BLOCK(cs_nWalletUnlockTime)
1301 nWalletUnlockTime = 0;
1306 CRITICAL_BLOCK(cs_nWalletUnlockTime)
1308 if (nWalletUnlockTime < nMyWakeTime)
1309 nWalletUnlockTime = nMyWakeTime;
1315 pwalletMain->Lock();
1320 Value walletpassphrase(const Array& params, bool fHelp)
1322 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1323 throw runtime_error(
1324 "walletpassphrase <passphrase> <timeout>\n"
1325 "Stores the wallet decryption key in memory for <timeout> seconds.");
1328 if (!pwalletMain->IsCrypted())
1329 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
1331 if (!pwalletMain->IsLocked())
1332 throw JSONRPCError(-17, "Error: Wallet is already unlocked.");
1334 // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
1335 string strWalletPass;
1336 strWalletPass.reserve(100);
1337 mlock(&strWalletPass[0], strWalletPass.capacity());
1338 strWalletPass = params[0].get_str();
1340 if (strWalletPass.length() > 0)
1342 if (!pwalletMain->Unlock(strWalletPass))
1344 fill(strWalletPass.begin(), strWalletPass.end(), '\0');
1345 munlock(&strWalletPass[0], strWalletPass.capacity());
1346 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1348 fill(strWalletPass.begin(), strWalletPass.end(), '\0');
1349 munlock(&strWalletPass[0], strWalletPass.capacity());
1352 throw runtime_error(
1353 "walletpassphrase <passphrase> <timeout>\n"
1354 "Stores the wallet decryption key in memory for <timeout> seconds.");
1356 CreateThread(ThreadTopUpKeyPool, NULL);
1357 int* pnSleepTime = new int(params[1].get_int());
1358 CreateThread(ThreadCleanWalletPassphrase, pnSleepTime);
1364 Value walletpassphrasechange(const Array& params, bool fHelp)
1366 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1367 throw runtime_error(
1368 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1369 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1372 if (!pwalletMain->IsCrypted())
1373 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
1375 string strOldWalletPass;
1376 strOldWalletPass.reserve(100);
1377 mlock(&strOldWalletPass[0], strOldWalletPass.capacity());
1378 strOldWalletPass = params[0].get_str();
1380 string strNewWalletPass;
1381 strNewWalletPass.reserve(100);
1382 mlock(&strNewWalletPass[0], strNewWalletPass.capacity());
1383 strNewWalletPass = params[1].get_str();
1385 if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
1386 throw runtime_error(
1387 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1388 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1390 if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
1392 fill(strOldWalletPass.begin(), strOldWalletPass.end(), '\0');
1393 fill(strNewWalletPass.begin(), strNewWalletPass.end(), '\0');
1394 munlock(&strOldWalletPass[0], strOldWalletPass.capacity());
1395 munlock(&strNewWalletPass[0], strNewWalletPass.capacity());
1396 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1398 fill(strNewWalletPass.begin(), strNewWalletPass.end(), '\0');
1399 fill(strOldWalletPass.begin(), strOldWalletPass.end(), '\0');
1400 munlock(&strOldWalletPass[0], strOldWalletPass.capacity());
1401 munlock(&strNewWalletPass[0], strNewWalletPass.capacity());
1407 Value walletlock(const Array& params, bool fHelp)
1409 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
1410 throw runtime_error(
1412 "Removes the wallet encryption key from memory, locking the wallet.\n"
1413 "After calling this method, you will need to call walletpassphrase again\n"
1414 "before being able to call any methods which require the wallet to be unlocked.");
1417 if (!pwalletMain->IsCrypted())
1418 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletlock was called.");
1420 pwalletMain->Lock();
1421 CRITICAL_BLOCK(cs_nWalletUnlockTime)
1423 nWalletUnlockTime = 0;
1430 Value encryptwallet(const Array& params, bool fHelp)
1432 if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
1433 throw runtime_error(
1434 "encryptwallet <passphrase>\n"
1435 "Encrypts the wallet with <passphrase>.");
1438 if (pwalletMain->IsCrypted())
1439 throw JSONRPCError(-15, "Error: running with an encrypted wallet, but encryptwallet was called.");
1441 string strWalletPass;
1442 strWalletPass.reserve(100);
1443 mlock(&strWalletPass[0], strWalletPass.capacity());
1444 strWalletPass = params[0].get_str();
1446 if (strWalletPass.length() < 1)
1447 throw runtime_error(
1448 "encryptwallet <passphrase>\n"
1449 "Encrypts the wallet with <passphrase>.");
1451 if (!pwalletMain->EncryptWallet(strWalletPass))
1453 fill(strWalletPass.begin(), strWalletPass.end(), '\0');
1454 munlock(&strWalletPass[0], strWalletPass.capacity());
1455 throw JSONRPCError(-16, "Error: Failed to encrypt the wallet.");
1457 fill(strWalletPass.begin(), strWalletPass.end(), '\0');
1458 munlock(&strWalletPass[0], strWalletPass.capacity());
1464 Value validateaddress(const Array& params, bool fHelp)
1466 if (fHelp || params.size() != 1)
1467 throw runtime_error(
1468 "validateaddress <bitcoinaddress>\n"
1469 "Return information about <bitcoinaddress>.");
1471 CBitcoinAddress address(params[0].get_str());
1472 bool isValid = address.IsValid();
1475 ret.push_back(Pair("isvalid", isValid));
1478 // Call Hash160ToAddress() so we always return current ADDRESSVERSION
1479 // version of the address:
1480 string currentAddress = address.ToString();
1481 ret.push_back(Pair("address", currentAddress));
1482 ret.push_back(Pair("ismine", (pwalletMain->HaveKey(address) > 0)));
1483 if (pwalletMain->mapAddressBook.count(address))
1484 ret.push_back(Pair("account", pwalletMain->mapAddressBook[address]));
1490 Value getwork(const Array& params, bool fHelp)
1492 if (fHelp || params.size() > 1)
1493 throw runtime_error(
1495 "If [data] is not specified, returns formatted hash data to work on:\n"
1496 " \"midstate\" : precomputed hash state after hashing the first half of the data\n"
1497 " \"data\" : block data\n"
1498 " \"hash1\" : formatted hash buffer for second hash\n"
1499 " \"target\" : little endian hash target\n"
1500 "If [data] is specified, tries to solve the block and returns true if it was successful.");
1503 throw JSONRPCError(-9, "Bitcoin is not connected!");
1505 if (IsInitialBlockDownload())
1506 throw JSONRPCError(-10, "Bitcoin is downloading blocks...");
1508 static map<uint256, pair<CBlock*, unsigned int> > mapNewBlock;
1509 static vector<CBlock*> vNewBlock;
1510 static CReserveKey reservekey(pwalletMain);
1512 if (params.size() == 0)
1515 static unsigned int nTransactionsUpdatedLast;
1516 static CBlockIndex* pindexPrev;
1517 static int64 nStart;
1518 static CBlock* pblock;
1519 if (pindexPrev != pindexBest ||
1520 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60))
1522 if (pindexPrev != pindexBest)
1524 // Deallocate old blocks since they're obsolete now
1525 mapNewBlock.clear();
1526 BOOST_FOREACH(CBlock* pblock, vNewBlock)
1530 nTransactionsUpdatedLast = nTransactionsUpdated;
1531 pindexPrev = pindexBest;
1535 pblock = CreateNewBlock(reservekey);
1537 throw JSONRPCError(-7, "Out of memory");
1538 vNewBlock.push_back(pblock);
1542 pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
1545 // Update nExtraNonce
1546 static unsigned int nExtraNonce = 0;
1547 static int64 nPrevTime = 0;
1548 IncrementExtraNonce(pblock, pindexPrev, nExtraNonce, nPrevTime);
1551 mapNewBlock[pblock->hashMerkleRoot] = make_pair(pblock, nExtraNonce);
1553 // Prebuild hash buffers
1557 FormatHashBuffers(pblock, pmidstate, pdata, phash1);
1559 uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
1562 result.push_back(Pair("midstate", HexStr(BEGIN(pmidstate), END(pmidstate))));
1563 result.push_back(Pair("data", HexStr(BEGIN(pdata), END(pdata))));
1564 result.push_back(Pair("hash1", HexStr(BEGIN(phash1), END(phash1))));
1565 result.push_back(Pair("target", HexStr(BEGIN(hashTarget), END(hashTarget))));
1571 vector<unsigned char> vchData = ParseHex(params[0].get_str());
1572 if (vchData.size() != 128)
1573 throw JSONRPCError(-8, "Invalid parameter");
1574 CBlock* pdata = (CBlock*)&vchData[0];
1577 for (int i = 0; i < 128/4; i++)
1578 ((unsigned int*)pdata)[i] = CryptoPP::ByteReverse(((unsigned int*)pdata)[i]);
1581 if (!mapNewBlock.count(pdata->hashMerkleRoot))
1583 CBlock* pblock = mapNewBlock[pdata->hashMerkleRoot].first;
1584 unsigned int nExtraNonce = mapNewBlock[pdata->hashMerkleRoot].second;
1586 pblock->nTime = pdata->nTime;
1587 pblock->nNonce = pdata->nNonce;
1588 pblock->vtx[0].vin[0].scriptSig = CScript() << pblock->nBits << CBigNum(nExtraNonce);
1589 pblock->hashMerkleRoot = pblock->BuildMerkleTree();
1591 return CheckWork(pblock, *pwalletMain, reservekey);
1609 pair<string, rpcfn_type> pCallTable[] =
1611 make_pair("help", &help),
1612 make_pair("stop", &stop),
1613 make_pair("getblockcount", &getblockcount),
1614 make_pair("getblocknumber", &getblocknumber),
1615 make_pair("getconnectioncount", &getconnectioncount),
1616 make_pair("getdifficulty", &getdifficulty),
1617 make_pair("getgenerate", &getgenerate),
1618 make_pair("setgenerate", &setgenerate),
1619 make_pair("gethashespersec", &gethashespersec),
1620 make_pair("getinfo", &getinfo),
1621 make_pair("getnewaddress", &getnewaddress),
1622 make_pair("getaccountaddress", &getaccountaddress),
1623 make_pair("setaccount", &setaccount),
1624 make_pair("setlabel", &setaccount), // deprecated
1625 make_pair("getaccount", &getaccount),
1626 make_pair("getlabel", &getaccount), // deprecated
1627 make_pair("getaddressesbyaccount", &getaddressesbyaccount),
1628 make_pair("getaddressesbylabel", &getaddressesbyaccount), // deprecated
1629 make_pair("sendtoaddress", &sendtoaddress),
1630 make_pair("getamountreceived", &getreceivedbyaddress), // deprecated, renamed to getreceivedbyaddress
1631 make_pair("getallreceived", &listreceivedbyaddress), // deprecated, renamed to listreceivedbyaddress
1632 make_pair("getreceivedbyaddress", &getreceivedbyaddress),
1633 make_pair("getreceivedbyaccount", &getreceivedbyaccount),
1634 make_pair("getreceivedbylabel", &getreceivedbyaccount), // deprecated
1635 make_pair("listreceivedbyaddress", &listreceivedbyaddress),
1636 make_pair("listreceivedbyaccount", &listreceivedbyaccount),
1637 make_pair("listreceivedbylabel", &listreceivedbyaccount), // deprecated
1638 make_pair("backupwallet", &backupwallet),
1639 make_pair("keypoolrefill", &keypoolrefill),
1640 make_pair("walletpassphrase", &walletpassphrase),
1641 make_pair("walletpassphrasechange", &walletpassphrasechange),
1642 make_pair("walletlock", &walletlock),
1643 make_pair("encryptwallet", &encryptwallet),
1644 make_pair("validateaddress", &validateaddress),
1645 make_pair("getbalance", &getbalance),
1646 make_pair("move", &movecmd),
1647 make_pair("sendfrom", &sendfrom),
1648 make_pair("sendmany", &sendmany),
1649 make_pair("gettransaction", &gettransaction),
1650 make_pair("listtransactions", &listtransactions),
1651 make_pair("getwork", &getwork),
1652 make_pair("listaccounts", &listaccounts),
1653 make_pair("settxfee", &settxfee),
1655 map<string, rpcfn_type> mapCallTable(pCallTable, pCallTable + sizeof(pCallTable)/sizeof(pCallTable[0]));
1657 string pAllowInSafeMode[] =
1663 "getconnectioncount",
1670 "getaccountaddress",
1671 "setlabel", // deprecated
1673 "getlabel", // deprecated
1674 "getaddressesbyaccount",
1675 "getaddressesbylabel", // deprecated
1683 set<string> setAllowInSafeMode(pAllowInSafeMode, pAllowInSafeMode + sizeof(pAllowInSafeMode)/sizeof(pAllowInSafeMode[0]));
1691 // This ain't Apache. We're just using HTTP header for the length field
1692 // and to be compatible with other JSON-RPC implementations.
1695 string HTTPPost(const string& strMsg, const map<string,string>& mapRequestHeaders)
1698 s << "POST / HTTP/1.1\r\n"
1699 << "User-Agent: bitcoin-json-rpc/" << FormatFullVersion() << "\r\n"
1700 << "Host: 127.0.0.1\r\n"
1701 << "Content-Type: application/json\r\n"
1702 << "Content-Length: " << strMsg.size() << "\r\n"
1703 << "Accept: application/json\r\n";
1704 BOOST_FOREACH(const PAIRTYPE(string, string)& item, mapRequestHeaders)
1705 s << item.first << ": " << item.second << "\r\n";
1706 s << "\r\n" << strMsg;
1711 string rfc1123Time()
1716 struct tm* now_gmt = gmtime(&now);
1717 string locale(setlocale(LC_TIME, NULL));
1718 setlocale(LC_TIME, "C"); // we want posix (aka "C") weekday/month strings
1719 strftime(buffer, sizeof(buffer), "%a, %d %b %Y %H:%M:%S +0000", now_gmt);
1720 setlocale(LC_TIME, locale.c_str());
1721 return string(buffer);
1724 static string HTTPReply(int nStatus, const string& strMsg)
1727 return strprintf("HTTP/1.0 401 Authorization Required\r\n"
1729 "Server: bitcoin-json-rpc/%s\r\n"
1730 "WWW-Authenticate: Basic realm=\"jsonrpc\"\r\n"
1731 "Content-Type: text/html\r\n"
1732 "Content-Length: 296\r\n"
1734 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\r\n"
1735 "\"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd\">\r\n"
1738 "<TITLE>Error</TITLE>\r\n"
1739 "<META HTTP-EQUIV='Content-Type' CONTENT='text/html; charset=ISO-8859-1'>\r\n"
1741 "<BODY><H1>401 Unauthorized.</H1></BODY>\r\n"
1742 "</HTML>\r\n", rfc1123Time().c_str(), FormatFullVersion().c_str());
1744 if (nStatus == 200) strStatus = "OK";
1745 else if (nStatus == 400) strStatus = "Bad Request";
1746 else if (nStatus == 403) strStatus = "Forbidden";
1747 else if (nStatus == 404) strStatus = "Not Found";
1748 else if (nStatus == 500) strStatus = "Internal Server Error";
1750 "HTTP/1.1 %d %s\r\n"
1752 "Connection: close\r\n"
1753 "Content-Length: %d\r\n"
1754 "Content-Type: application/json\r\n"
1755 "Server: bitcoin-json-rpc/%s\r\n"
1760 rfc1123Time().c_str(),
1762 FormatFullVersion().c_str(),
1766 int ReadHTTPStatus(std::basic_istream<char>& stream)
1769 getline(stream, str);
1770 vector<string> vWords;
1771 boost::split(vWords, str, boost::is_any_of(" "));
1772 if (vWords.size() < 2)
1774 return atoi(vWords[1].c_str());
1777 int ReadHTTPHeader(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet)
1783 std::getline(stream, str);
1784 if (str.empty() || str == "\r")
1786 string::size_type nColon = str.find(":");
1787 if (nColon != string::npos)
1789 string strHeader = str.substr(0, nColon);
1790 boost::trim(strHeader);
1791 boost::to_lower(strHeader);
1792 string strValue = str.substr(nColon+1);
1793 boost::trim(strValue);
1794 mapHeadersRet[strHeader] = strValue;
1795 if (strHeader == "content-length")
1796 nLen = atoi(strValue.c_str());
1802 int ReadHTTP(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet, string& strMessageRet)
1804 mapHeadersRet.clear();
1808 int nStatus = ReadHTTPStatus(stream);
1811 int nLen = ReadHTTPHeader(stream, mapHeadersRet);
1812 if (nLen < 0 || nLen > MAX_SIZE)
1818 vector<char> vch(nLen);
1819 stream.read(&vch[0], nLen);
1820 strMessageRet = string(vch.begin(), vch.end());
1826 string EncodeBase64(string s)
1831 b64 = BIO_new(BIO_f_base64());
1832 BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
1833 bmem = BIO_new(BIO_s_mem());
1834 b64 = BIO_push(b64, bmem);
1835 BIO_write(b64, s.c_str(), s.size());
1837 BIO_get_mem_ptr(b64, &bptr);
1839 string result(bptr->data, bptr->length);
1845 string DecodeBase64(string s)
1849 char* buffer = static_cast<char*>(calloc(s.size(), sizeof(char)));
1851 b64 = BIO_new(BIO_f_base64());
1852 BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
1853 bmem = BIO_new_mem_buf(const_cast<char*>(s.c_str()), s.size());
1854 bmem = BIO_push(b64, bmem);
1855 BIO_read(bmem, buffer, s.size());
1858 string result(buffer);
1863 bool HTTPAuthorized(map<string, string>& mapHeaders)
1865 string strAuth = mapHeaders["authorization"];
1866 if (strAuth.substr(0,6) != "Basic ")
1868 string strUserPass64 = strAuth.substr(6); boost::trim(strUserPass64);
1869 string strUserPass = DecodeBase64(strUserPass64);
1870 string::size_type nColon = strUserPass.find(":");
1871 if (nColon == string::npos)
1873 string strUser = strUserPass.substr(0, nColon);
1874 string strPassword = strUserPass.substr(nColon+1);
1875 return (strUser == mapArgs["-rpcuser"] && strPassword == mapArgs["-rpcpassword"]);
1879 // JSON-RPC protocol. Bitcoin speaks version 1.0 for maximum compatibility,
1880 // but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
1881 // unspecified (HTTP errors and contents of 'error').
1883 // 1.0 spec: http://json-rpc.org/wiki/specification
1884 // 1.2 spec: http://groups.google.com/group/json-rpc/web/json-rpc-over-http
1885 // http://www.codeproject.com/KB/recipes/JSON_Spirit.aspx
1888 string JSONRPCRequest(const string& strMethod, const Array& params, const Value& id)
1891 request.push_back(Pair("method", strMethod));
1892 request.push_back(Pair("params", params));
1893 request.push_back(Pair("id", id));
1894 return write_string(Value(request), false) + "\n";
1897 string JSONRPCReply(const Value& result, const Value& error, const Value& id)
1900 if (error.type() != null_type)
1901 reply.push_back(Pair("result", Value::null));
1903 reply.push_back(Pair("result", result));
1904 reply.push_back(Pair("error", error));
1905 reply.push_back(Pair("id", id));
1906 return write_string(Value(reply), false) + "\n";
1909 void ErrorReply(std::ostream& stream, const Object& objError, const Value& id)
1911 // Send error reply from json-rpc error object
1913 int code = find_value(objError, "code").get_int();
1914 if (code == -32600) nStatus = 400;
1915 else if (code == -32601) nStatus = 404;
1916 string strReply = JSONRPCReply(Value::null, objError, id);
1917 stream << HTTPReply(nStatus, strReply) << std::flush;
1920 bool ClientAllowed(const string& strAddress)
1922 if (strAddress == asio::ip::address_v4::loopback().to_string())
1924 const vector<string>& vAllow = mapMultiArgs["-rpcallowip"];
1925 BOOST_FOREACH(string strAllow, vAllow)
1926 if (WildcardMatch(strAddress, strAllow))
1933 // IOStream device that speaks SSL but can also speak non-SSL
1935 class SSLIOStreamDevice : public iostreams::device<iostreams::bidirectional> {
1937 SSLIOStreamDevice(SSLStream &streamIn, bool fUseSSLIn) : stream(streamIn)
1939 fUseSSL = fUseSSLIn;
1940 fNeedHandshake = fUseSSLIn;
1943 void handshake(ssl::stream_base::handshake_type role)
1945 if (!fNeedHandshake) return;
1946 fNeedHandshake = false;
1947 stream.handshake(role);
1949 std::streamsize read(char* s, std::streamsize n)
1951 handshake(ssl::stream_base::server); // HTTPS servers read first
1952 if (fUseSSL) return stream.read_some(asio::buffer(s, n));
1953 return stream.next_layer().read_some(asio::buffer(s, n));
1955 std::streamsize write(const char* s, std::streamsize n)
1957 handshake(ssl::stream_base::client); // HTTPS clients write first
1958 if (fUseSSL) return asio::write(stream, asio::buffer(s, n));
1959 return asio::write(stream.next_layer(), asio::buffer(s, n));
1961 bool connect(const std::string& server, const std::string& port)
1963 ip::tcp::resolver resolver(stream.get_io_service());
1964 ip::tcp::resolver::query query(server.c_str(), port.c_str());
1965 ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
1966 ip::tcp::resolver::iterator end;
1967 boost::system::error_code error = asio::error::host_not_found;
1968 while (error && endpoint_iterator != end)
1970 stream.lowest_layer().close();
1971 stream.lowest_layer().connect(*endpoint_iterator++, error);
1979 bool fNeedHandshake;
1985 void ThreadRPCServer(void* parg)
1987 IMPLEMENT_RANDOMIZE_STACK(ThreadRPCServer(parg));
1990 vnThreadsRunning[4]++;
1991 ThreadRPCServer2(parg);
1992 vnThreadsRunning[4]--;
1994 catch (std::exception& e) {
1995 vnThreadsRunning[4]--;
1996 PrintException(&e, "ThreadRPCServer()");
1998 vnThreadsRunning[4]--;
1999 PrintException(NULL, "ThreadRPCServer()");
2001 printf("ThreadRPCServer exiting\n");
2004 void ThreadRPCServer2(void* parg)
2006 printf("ThreadRPCServer started\n");
2008 if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
2010 string strWhatAmI = "To use bitcoind";
2011 if (mapArgs.count("-server"))
2012 strWhatAmI = strprintf(_("To use the %s option"), "\"-server\"");
2013 else if (mapArgs.count("-daemon"))
2014 strWhatAmI = strprintf(_("To use the %s option"), "\"-daemon\"");
2016 _("Warning: %s, you must set rpcpassword=<password>\nin the configuration file: %s\n"
2017 "If the file does not exist, create it with owner-readable-only file permissions.\n"),
2019 GetConfigFile().c_str());
2020 CreateThread(Shutdown, NULL);
2024 bool fUseSSL = GetBoolArg("-rpcssl");
2025 asio::ip::address bindAddress = mapArgs.count("-rpcallowip") ? asio::ip::address_v4::any() : asio::ip::address_v4::loopback();
2027 asio::io_service io_service;
2028 ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", 8332));
2029 ip::tcp::acceptor acceptor(io_service, endpoint);
2031 acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
2034 ssl::context context(io_service, ssl::context::sslv23);
2037 context.set_options(ssl::context::no_sslv2);
2038 filesystem::path certfile = GetArg("-rpcsslcertificatechainfile", "server.cert");
2039 if (!certfile.is_complete()) certfile = filesystem::path(GetDataDir()) / certfile;
2040 if (filesystem::exists(certfile)) context.use_certificate_chain_file(certfile.string().c_str());
2041 else printf("ThreadRPCServer ERROR: missing server certificate file %s\n", certfile.string().c_str());
2042 filesystem::path pkfile = GetArg("-rpcsslprivatekeyfile", "server.pem");
2043 if (!pkfile.is_complete()) pkfile = filesystem::path(GetDataDir()) / pkfile;
2044 if (filesystem::exists(pkfile)) context.use_private_key_file(pkfile.string().c_str(), ssl::context::pem);
2045 else printf("ThreadRPCServer ERROR: missing server private key file %s\n", pkfile.string().c_str());
2047 string ciphers = GetArg("-rpcsslciphers",
2048 "TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH");
2049 SSL_CTX_set_cipher_list(context.impl(), ciphers.c_str());
2053 throw runtime_error("-rpcssl=1, but bitcoin compiled without full openssl libraries.");
2058 // Accept connection
2060 SSLStream sslStream(io_service, context);
2061 SSLIOStreamDevice d(sslStream, fUseSSL);
2062 iostreams::stream<SSLIOStreamDevice> stream(d);
2064 ip::tcp::iostream stream;
2067 ip::tcp::endpoint peer;
2068 vnThreadsRunning[4]--;
2070 acceptor.accept(sslStream.lowest_layer(), peer);
2072 acceptor.accept(*stream.rdbuf(), peer);
2074 vnThreadsRunning[4]++;
2078 // Restrict callers by IP
2079 if (!ClientAllowed(peer.address().to_string()))
2081 // Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake.
2083 stream << HTTPReply(403, "") << std::flush;
2087 map<string, string> mapHeaders;
2090 boost::thread api_caller(ReadHTTP, boost::ref(stream), boost::ref(mapHeaders), boost::ref(strRequest));
2091 if (!api_caller.timed_join(boost::posix_time::seconds(GetArg("-rpctimeout", 30))))
2094 printf("ThreadRPCServer ReadHTTP timeout\n");
2098 // Check authorization
2099 if (mapHeaders.count("authorization") == 0)
2101 stream << HTTPReply(401, "") << std::flush;
2104 if (!HTTPAuthorized(mapHeaders))
2106 // Deter brute-forcing short passwords
2107 if (mapArgs["-rpcpassword"].size() < 15)
2110 stream << HTTPReply(401, "") << std::flush;
2111 printf("ThreadRPCServer incorrect password attempt\n");
2115 Value id = Value::null;
2120 if (!read_string(strRequest, valRequest) || valRequest.type() != obj_type)
2121 throw JSONRPCError(-32700, "Parse error");
2122 const Object& request = valRequest.get_obj();
2124 // Parse id now so errors from here on will have the id
2125 id = find_value(request, "id");
2128 Value valMethod = find_value(request, "method");
2129 if (valMethod.type() == null_type)
2130 throw JSONRPCError(-32600, "Missing method");
2131 if (valMethod.type() != str_type)
2132 throw JSONRPCError(-32600, "Method must be a string");
2133 string strMethod = valMethod.get_str();
2134 if (strMethod != "getwork")
2135 printf("ThreadRPCServer method=%s\n", strMethod.c_str());
2138 Value valParams = find_value(request, "params");
2140 if (valParams.type() == array_type)
2141 params = valParams.get_array();
2142 else if (valParams.type() == null_type)
2145 throw JSONRPCError(-32600, "Params must be an array");
2148 map<string, rpcfn_type>::iterator mi = mapCallTable.find(strMethod);
2149 if (mi == mapCallTable.end())
2150 throw JSONRPCError(-32601, "Method not found");
2152 // Observe safe mode
2153 string strWarning = GetWarnings("rpc");
2154 if (strWarning != "" && !GetBoolArg("-disablesafemode") && !setAllowInSafeMode.count(strMethod))
2155 throw JSONRPCError(-2, string("Safe mode: ") + strWarning);
2161 CRITICAL_BLOCK(cs_main)
2162 CRITICAL_BLOCK(pwalletMain->cs_wallet)
2163 result = (*(*mi).second)(params, false);
2166 string strReply = JSONRPCReply(result, Value::null, id);
2167 stream << HTTPReply(200, strReply) << std::flush;
2169 catch (std::exception& e)
2171 ErrorReply(stream, JSONRPCError(-1, e.what()), id);
2174 catch (Object& objError)
2176 ErrorReply(stream, objError, id);
2178 catch (std::exception& e)
2180 ErrorReply(stream, JSONRPCError(-32700, e.what()), id);
2188 Object CallRPC(const string& strMethod, const Array& params)
2190 if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
2191 throw runtime_error(strprintf(
2192 _("You must set rpcpassword=<password> in the configuration file:\n%s\n"
2193 "If the file does not exist, create it with owner-readable-only file permissions."),
2194 GetConfigFile().c_str()));
2196 // Connect to localhost
2197 bool fUseSSL = GetBoolArg("-rpcssl");
2199 asio::io_service io_service;
2200 ssl::context context(io_service, ssl::context::sslv23);
2201 context.set_options(ssl::context::no_sslv2);
2202 SSLStream sslStream(io_service, context);
2203 SSLIOStreamDevice d(sslStream, fUseSSL);
2204 iostreams::stream<SSLIOStreamDevice> stream(d);
2205 if (!d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332")))
2206 throw runtime_error("couldn't connect to server");
2209 throw runtime_error("-rpcssl=1, but bitcoin compiled without full openssl libraries.");
2211 ip::tcp::iostream stream(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332"));
2213 throw runtime_error("couldn't connect to server");
2217 // HTTP basic authentication
2218 string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
2219 map<string, string> mapRequestHeaders;
2220 mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64;
2223 string strRequest = JSONRPCRequest(strMethod, params, 1);
2224 string strPost = HTTPPost(strRequest, mapRequestHeaders);
2225 stream << strPost << std::flush;
2228 map<string, string> mapHeaders;
2230 int nStatus = ReadHTTP(stream, mapHeaders, strReply);
2232 throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
2233 else if (nStatus >= 400 && nStatus != 400 && nStatus != 404 && nStatus != 500)
2234 throw runtime_error(strprintf("server returned HTTP error %d", nStatus));
2235 else if (strReply.empty())
2236 throw runtime_error("no response from server");
2240 if (!read_string(strReply, valReply))
2241 throw runtime_error("couldn't parse reply from server");
2242 const Object& reply = valReply.get_obj();
2244 throw runtime_error("expected reply to have result, error and id properties");
2252 template<typename T>
2253 void ConvertTo(Value& value)
2255 if (value.type() == str_type)
2257 // reinterpret string as unquoted json value
2259 if (!read_string(value.get_str(), value2))
2260 throw runtime_error("type mismatch");
2261 value = value2.get_value<T>();
2265 value = value.get_value<T>();
2269 int CommandLineRPC(int argc, char *argv[])
2276 while (argc > 1 && IsSwitchChar(argv[1][0]))
2284 throw runtime_error("too few parameters");
2285 string strMethod = argv[1];
2287 // Parameters default to strings
2289 for (int i = 2; i < argc; i++)
2290 params.push_back(argv[i]);
2291 int n = params.size();
2294 // Special case non-string parameter types
2296 if (strMethod == "setgenerate" && n > 0) ConvertTo<bool>(params[0]);
2297 if (strMethod == "setgenerate" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2298 if (strMethod == "sendtoaddress" && n > 1) ConvertTo<double>(params[1]);
2299 if (strMethod == "settxfee" && n > 0) ConvertTo<double>(params[0]);
2300 if (strMethod == "getamountreceived" && n > 1) ConvertTo<boost::int64_t>(params[1]); // deprecated
2301 if (strMethod == "getreceivedbyaddress" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2302 if (strMethod == "getreceivedbyaccount" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2303 if (strMethod == "getreceivedbylabel" && n > 1) ConvertTo<boost::int64_t>(params[1]); // deprecated
2304 if (strMethod == "getallreceived" && n > 0) ConvertTo<boost::int64_t>(params[0]); // deprecated
2305 if (strMethod == "getallreceived" && n > 1) ConvertTo<bool>(params[1]); // deprecated
2306 if (strMethod == "listreceivedbyaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2307 if (strMethod == "listreceivedbyaddress" && n > 1) ConvertTo<bool>(params[1]);
2308 if (strMethod == "listreceivedbyaccount" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2309 if (strMethod == "listreceivedbyaccount" && n > 1) ConvertTo<bool>(params[1]);
2310 if (strMethod == "listreceivedbylabel" && n > 0) ConvertTo<boost::int64_t>(params[0]); // deprecated
2311 if (strMethod == "listreceivedbylabel" && n > 1) ConvertTo<bool>(params[1]); // deprecated
2312 if (strMethod == "getbalance" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2313 if (strMethod == "move" && n > 2) ConvertTo<double>(params[2]);
2314 if (strMethod == "move" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2315 if (strMethod == "sendfrom" && n > 2) ConvertTo<double>(params[2]);
2316 if (strMethod == "sendfrom" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2317 if (strMethod == "listtransactions" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2318 if (strMethod == "listtransactions" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2319 if (strMethod == "listaccounts" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2320 if (strMethod == "walletpassphrase" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2321 if (strMethod == "sendmany" && n > 1)
2323 string s = params[1].get_str();
2325 if (!read_string(s, v) || v.type() != obj_type)
2326 throw runtime_error("type mismatch");
2327 params[1] = v.get_obj();
2329 if (strMethod == "sendmany" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2332 Object reply = CallRPC(strMethod, params);
2335 const Value& result = find_value(reply, "result");
2336 const Value& error = find_value(reply, "error");
2338 if (error.type() != null_type)
2341 strPrint = "error: " + write_string(error, false);
2342 int code = find_value(error.get_obj(), "code").get_int();
2348 if (result.type() == null_type)
2350 else if (result.type() == str_type)
2351 strPrint = result.get_str();
2353 strPrint = write_string(result, true);
2356 catch (std::exception& e)
2358 strPrint = string("error: ") + e.what();
2363 PrintException(NULL, "CommandLineRPC()");
2368 #if defined(__WXMSW__) && defined(GUI)
2369 // Windows GUI apps can't print to command line,
2370 // so settle for a message box yuck
2371 MyMessageBox(strPrint, "Bitcoin", wxOK);
2373 fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
2383 int main(int argc, char *argv[])
2386 // Turn off microsoft heap dump noise
2387 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
2388 _CrtSetReportFile(_CRT_WARN, CreateFile("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0));
2390 setbuf(stdin, NULL);
2391 setbuf(stdout, NULL);
2392 setbuf(stderr, NULL);
2396 if (argc >= 2 && string(argv[1]) == "-server")
2398 printf("server ready\n");
2399 ThreadRPCServer(NULL);
2403 return CommandLineRPC(argc, argv);
2406 catch (std::exception& e) {
2407 PrintException(&e, "main()");
2409 PrintException(NULL, "main()");