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 std::string &format, ...)
56 int limit = sizeof(buffer);
58 va_start(arg_ptr, format);
59 int ret = _vsnprintf(buffer, limit, format.c_str(), arg_ptr);
61 if (ret < 0 || ret >= limit)
67 fprintf(stdout, "%s", buffer);
71 int64 AmountFromValue(const Value& value)
73 double dAmount = value.get_real();
74 if (dAmount <= 0.0 || dAmount > 21000000.0)
75 throw JSONRPCError(-3, "Invalid amount");
76 int64 nAmount = roundint64(dAmount * COIN);
77 if (!MoneyRange(nAmount))
78 throw JSONRPCError(-3, "Invalid amount");
82 Value ValueFromAmount(int64 amount)
84 return (double)amount / (double)COIN;
87 void WalletTxToJSON(const CWalletTx& wtx, Object& entry)
89 entry.push_back(Pair("confirmations", wtx.GetDepthInMainChain()));
90 entry.push_back(Pair("txid", wtx.GetHash().GetHex()));
91 entry.push_back(Pair("time", (boost::int64_t)wtx.GetTxTime()));
92 BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue)
93 entry.push_back(Pair(item.first, item.second));
96 string AccountFromValue(const Value& value)
98 string strAccount = value.get_str();
99 if (strAccount == "*")
100 throw JSONRPCError(-11, "Invalid account name");
107 /// Note: This interface may still be subject to change.
111 Value help(const Array& params, bool fHelp)
113 if (fHelp || params.size() > 1)
116 "List commands, or get help for a command.");
119 if (params.size() > 0)
120 strCommand = params[0].get_str();
123 set<rpcfn_type> setDone;
124 for (map<string, rpcfn_type>::iterator mi = mapCallTable.begin(); mi != mapCallTable.end(); ++mi)
126 string strMethod = (*mi).first;
127 // We already filter duplicates, but these deprecated screw up the sort order
128 if (strMethod == "getamountreceived" ||
129 strMethod == "getallreceived" ||
130 (strMethod.find("label") != string::npos))
132 if (strCommand != "" && strMethod != strCommand)
137 rpcfn_type pfn = (*mi).second;
138 if (setDone.insert(pfn).second)
139 (*pfn)(params, true);
141 catch (std::exception& e)
143 // Help text is returned in an exception
144 string strHelp = string(e.what());
145 if (strCommand == "")
146 if (strHelp.find('\n') != -1)
147 strHelp = strHelp.substr(0, strHelp.find('\n'));
148 strRet += strHelp + "\n";
152 strRet = strprintf("help: unknown command: %s\n", strCommand.c_str());
153 strRet = strRet.substr(0,strRet.size()-1);
158 Value stop(const Array& params, bool fHelp)
160 if (fHelp || params.size() != 0)
163 "Stop bitcoin server.");
165 // Shutdown will take long enough that the response should get back
166 CreateThread(Shutdown, NULL);
167 return "bitcoin server stopping";
171 Value getblockcount(const Array& params, bool fHelp)
173 if (fHelp || params.size() != 0)
176 "Returns the number of blocks in the longest block chain.");
182 Value getblocknumber(const Array& params, bool fHelp)
184 if (fHelp || params.size() != 0)
187 "Returns the block number of the latest block in the longest block chain.");
193 Value getconnectioncount(const Array& params, bool fHelp)
195 if (fHelp || params.size() != 0)
197 "getconnectioncount\n"
198 "Returns the number of connections to other nodes.");
200 return (int)vNodes.size();
204 double GetDifficulty()
206 // Floating point number that is a multiple of the minimum difficulty,
207 // minimum difficulty = 1.0.
209 if (pindexBest == NULL)
211 int nShift = (pindexBest->nBits >> 24) & 0xff;
214 (double)0x0000ffff / (double)(pindexBest->nBits & 0x00ffffff);
230 Value getdifficulty(const Array& params, bool fHelp)
232 if (fHelp || params.size() != 0)
235 "Returns the proof-of-work difficulty as a multiple of the minimum difficulty.");
237 return GetDifficulty();
241 Value getgenerate(const Array& params, bool fHelp)
243 if (fHelp || params.size() != 0)
246 "Returns true or false.");
248 return (bool)fGenerateBitcoins;
252 Value setgenerate(const Array& params, bool fHelp)
254 if (fHelp || params.size() < 1 || params.size() > 2)
256 "setgenerate <generate> [genproclimit]\n"
257 "<generate> is true or false to turn generation on or off.\n"
258 "Generation is limited to [genproclimit] processors, -1 is unlimited.");
260 bool fGenerate = true;
261 if (params.size() > 0)
262 fGenerate = params[0].get_bool();
264 if (params.size() > 1)
266 int nGenProcLimit = params[1].get_int();
267 fLimitProcessors = (nGenProcLimit != -1);
268 WriteSetting("fLimitProcessors", fLimitProcessors);
269 if (nGenProcLimit != -1)
270 WriteSetting("nLimitProcessors", nLimitProcessors = nGenProcLimit);
271 if (nGenProcLimit == 0)
275 GenerateBitcoins(fGenerate, pwalletMain);
280 Value gethashespersec(const Array& params, bool fHelp)
282 if (fHelp || params.size() != 0)
285 "Returns a recent hashes per second performance measurement while generating.");
287 if (GetTimeMillis() - nHPSTimerStart > 8000)
288 return (boost::int64_t)0;
289 return (boost::int64_t)dHashesPerSec;
293 Value getinfo(const Array& params, bool fHelp)
295 if (fHelp || params.size() != 0)
298 "Returns an object containing various state info.");
301 obj.push_back(Pair("version", (int)VERSION));
302 obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance())));
303 obj.push_back(Pair("blocks", (int)nBestHeight));
304 obj.push_back(Pair("connections", (int)vNodes.size()));
305 obj.push_back(Pair("proxy", (fUseProxy ? addrProxy.ToStringIPPort() : string())));
306 obj.push_back(Pair("generate", (bool)fGenerateBitcoins));
307 obj.push_back(Pair("genproclimit", (int)(fLimitProcessors ? nLimitProcessors : -1)));
308 obj.push_back(Pair("difficulty", (double)GetDifficulty()));
309 obj.push_back(Pair("hashespersec", gethashespersec(params, false)));
310 obj.push_back(Pair("testnet", fTestNet));
311 obj.push_back(Pair("keypoololdest", (boost::int64_t)pwalletMain->GetOldestKeyPoolTime()));
312 obj.push_back(Pair("keypoolsize", pwalletMain->GetKeyPoolSize()));
313 obj.push_back(Pair("paytxfee", ValueFromAmount(nTransactionFee)));
314 if (pwalletMain->IsCrypted())
315 obj.push_back(Pair("unlocked_until", (boost::int64_t)nWalletUnlockTime));
316 obj.push_back(Pair("errors", GetWarnings("statusbar")));
321 Value getnewaddress(const Array& params, bool fHelp)
323 if (fHelp || params.size() > 1)
325 "getnewaddress [account]\n"
326 "Returns a new bitcoin address for receiving payments. "
327 "If [account] is specified (recommended), it is added to the address book "
328 "so payments received with the address will be credited to [account].");
330 // Parse the account first so we don't generate a key if there's an error
332 if (params.size() > 0)
333 strAccount = AccountFromValue(params[0]);
335 if (!pwalletMain->IsLocked())
336 pwalletMain->TopUpKeyPool();
338 // Generate a new key that is added to wallet
339 std::vector<unsigned char> newKey;
340 if (!pwalletMain->GetKeyFromPool(newKey, false))
341 throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
342 CBitcoinAddress address(newKey);
344 pwalletMain->SetAddressBookName(address, strAccount);
346 return address.ToString();
350 CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false)
352 CWalletDB walletdb(pwalletMain->strWalletFile);
355 walletdb.ReadAccount(strAccount, account);
357 bool bKeyUsed = false;
359 // Check if the current key has been used
360 if (!account.vchPubKey.empty())
362 CScript scriptPubKey;
363 scriptPubKey.SetBitcoinAddress(account.vchPubKey);
364 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
365 it != pwalletMain->mapWallet.end() && !account.vchPubKey.empty();
368 const CWalletTx& wtx = (*it).second;
369 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
370 if (txout.scriptPubKey == scriptPubKey)
375 // Generate a new key
376 if (account.vchPubKey.empty() || bForceNew || bKeyUsed)
378 if (!pwalletMain->GetKeyFromPool(account.vchPubKey, false))
379 throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
381 pwalletMain->SetAddressBookName(CBitcoinAddress(account.vchPubKey), strAccount);
382 walletdb.WriteAccount(strAccount, account);
385 return CBitcoinAddress(account.vchPubKey);
388 Value getaccountaddress(const Array& params, bool fHelp)
390 if (fHelp || params.size() != 1)
392 "getaccountaddress <account>\n"
393 "Returns the current bitcoin address for receiving payments to this account.");
395 // Parse the account first so we don't generate a key if there's an error
396 string strAccount = AccountFromValue(params[0]);
400 ret = GetAccountAddress(strAccount).ToString();
407 Value setaccount(const Array& params, bool fHelp)
409 if (fHelp || params.size() < 1 || params.size() > 2)
411 "setaccount <bitcoinaddress> <account>\n"
412 "Sets the account associated with the given address.");
414 CBitcoinAddress address(params[0].get_str());
415 if (!address.IsValid())
416 throw JSONRPCError(-5, "Invalid bitcoin address");
420 if (params.size() > 1)
421 strAccount = AccountFromValue(params[1]);
423 // Detect when changing the account of an address that is the 'unused current key' of another account:
424 if (pwalletMain->mapAddressBook.count(address))
426 string strOldAccount = pwalletMain->mapAddressBook[address];
427 if (address == GetAccountAddress(strOldAccount))
428 GetAccountAddress(strOldAccount, true);
431 pwalletMain->SetAddressBookName(address, strAccount);
437 Value getaccount(const Array& params, bool fHelp)
439 if (fHelp || params.size() != 1)
441 "getaccount <bitcoinaddress>\n"
442 "Returns the account associated with the given address.");
444 CBitcoinAddress address(params[0].get_str());
445 if (!address.IsValid())
446 throw JSONRPCError(-5, "Invalid bitcoin address");
449 map<CBitcoinAddress, string>::iterator mi = pwalletMain->mapAddressBook.find(address);
450 if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.empty())
451 strAccount = (*mi).second;
456 Value getaddressesbyaccount(const Array& params, bool fHelp)
458 if (fHelp || params.size() != 1)
460 "getaddressesbyaccount <account>\n"
461 "Returns the list of addresses for the given account.");
463 string strAccount = AccountFromValue(params[0]);
465 // Find all addresses that have the given account
467 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
469 const CBitcoinAddress& address = item.first;
470 const string& strName = item.second;
471 if (strName == strAccount)
472 ret.push_back(address.ToString());
477 Value settxfee(const Array& params, bool fHelp)
479 if (fHelp || params.size() < 1 || params.size() > 1)
481 "settxfee <amount>\n"
482 "<amount> is a real and is rounded to the nearest 0.00000001");
486 if (params[0].get_real() != 0.0)
487 nAmount = AmountFromValue(params[0]); // rejects 0.0 amounts
489 nTransactionFee = nAmount;
493 Value sendtoaddress(const Array& params, bool fHelp)
495 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
497 "sendtoaddress <bitcoinaddress> <amount> [comment] [comment-to]\n"
498 "<amount> is a real and is rounded to the nearest 0.00000001\n"
499 "requires wallet passphrase to be set with walletpassphrase first");
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");
505 CBitcoinAddress address(params[0].get_str());
506 if (!address.IsValid())
507 throw JSONRPCError(-5, "Invalid bitcoin address");
510 int64 nAmount = AmountFromValue(params[1]);
514 if (params.size() > 2 && params[2].type() != null_type && !params[2].get_str().empty())
515 wtx.mapValue["comment"] = params[2].get_str();
516 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
517 wtx.mapValue["to"] = params[3].get_str();
519 if (pwalletMain->IsLocked())
520 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
522 string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
524 throw JSONRPCError(-4, strError);
526 return wtx.GetHash().GetHex();
530 Value getreceivedbyaddress(const Array& params, bool fHelp)
532 if (fHelp || params.size() < 1 || params.size() > 2)
534 "getreceivedbyaddress <bitcoinaddress> [minconf=1]\n"
535 "Returns the total amount received by <bitcoinaddress> in transactions with at least [minconf] confirmations.");
538 CBitcoinAddress address = CBitcoinAddress(params[0].get_str());
539 CScript scriptPubKey;
540 if (!address.IsValid())
541 throw JSONRPCError(-5, "Invalid bitcoin address");
542 scriptPubKey.SetBitcoinAddress(address);
543 if (!IsMine(*pwalletMain,scriptPubKey))
546 // Minimum confirmations
548 if (params.size() > 1)
549 nMinDepth = params[1].get_int();
553 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
555 const CWalletTx& wtx = (*it).second;
556 if (wtx.IsCoinBase() || !wtx.IsFinal())
559 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
560 if (txout.scriptPubKey == scriptPubKey)
561 if (wtx.GetDepthInMainChain() >= nMinDepth)
562 nAmount += txout.nValue;
565 return ValueFromAmount(nAmount);
569 void GetAccountAddresses(string strAccount, set<CBitcoinAddress>& setAddress)
571 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
573 const CBitcoinAddress& address = item.first;
574 const string& strName = item.second;
575 if (strName == strAccount)
576 setAddress.insert(address);
581 Value getreceivedbyaccount(const Array& params, bool fHelp)
583 if (fHelp || params.size() < 1 || params.size() > 2)
585 "getreceivedbyaccount <account> [minconf=1]\n"
586 "Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.");
588 // Minimum confirmations
590 if (params.size() > 1)
591 nMinDepth = params[1].get_int();
593 // Get the set of pub keys that have the label
594 string strAccount = AccountFromValue(params[0]);
595 set<CBitcoinAddress> setAddress;
596 GetAccountAddresses(strAccount, setAddress);
600 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
602 const CWalletTx& wtx = (*it).second;
603 if (wtx.IsCoinBase() || !wtx.IsFinal())
606 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
608 CBitcoinAddress address;
609 if (ExtractAddress(txout.scriptPubKey, pwalletMain, address) && setAddress.count(address))
610 if (wtx.GetDepthInMainChain() >= nMinDepth)
611 nAmount += txout.nValue;
615 return (double)nAmount / (double)COIN;
619 int64 GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth)
623 // Tally wallet transactions
624 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
626 const CWalletTx& wtx = (*it).second;
630 int64 nGenerated, nReceived, nSent, nFee;
631 wtx.GetAccountAmounts(strAccount, nGenerated, nReceived, nSent, nFee);
633 if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
634 nBalance += nReceived;
635 nBalance += nGenerated - nSent - nFee;
638 // Tally internal accounting entries
639 nBalance += walletdb.GetAccountCreditDebit(strAccount);
644 int64 GetAccountBalance(const string& strAccount, int nMinDepth)
646 CWalletDB walletdb(pwalletMain->strWalletFile);
647 return GetAccountBalance(walletdb, strAccount, nMinDepth);
651 Value getbalance(const Array& params, bool fHelp)
653 if (fHelp || params.size() > 2)
655 "getbalance [account] [minconf=1]\n"
656 "If [account] is not specified, returns the server's total available balance.\n"
657 "If [account] is specified, returns the balance in the account.");
659 if (params.size() == 0)
660 return ValueFromAmount(pwalletMain->GetBalance());
663 if (params.size() > 1)
664 nMinDepth = params[1].get_int();
666 if (params[0].get_str() == "*") {
667 // Calculate total balance a different way from GetBalance()
668 // (GetBalance() sums up all unspent TxOuts)
669 // getbalance and getbalance '*' should always return the same number.
671 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
673 const CWalletTx& wtx = (*it).second;
677 int64 allGeneratedImmature, allGeneratedMature, allFee;
678 allGeneratedImmature = allGeneratedMature = allFee = 0;
679 string strSentAccount;
680 list<pair<CBitcoinAddress, int64> > listReceived;
681 list<pair<CBitcoinAddress, int64> > listSent;
682 wtx.GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount);
683 if (wtx.GetDepthInMainChain() >= nMinDepth)
684 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listReceived)
685 nBalance += r.second;
686 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listSent)
687 nBalance -= r.second;
689 nBalance += allGeneratedMature;
691 return ValueFromAmount(nBalance);
694 string strAccount = AccountFromValue(params[0]);
696 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
698 return ValueFromAmount(nBalance);
702 Value movecmd(const Array& params, bool fHelp)
704 if (fHelp || params.size() < 3 || params.size() > 5)
706 "move <fromaccount> <toaccount> <amount> [minconf=1] [comment]\n"
707 "Move from one account in your wallet to another.");
709 string strFrom = AccountFromValue(params[0]);
710 string strTo = AccountFromValue(params[1]);
711 int64 nAmount = AmountFromValue(params[2]);
712 if (params.size() > 3)
713 // unused parameter, used to be nMinDepth, keep type-checking it though
714 (void)params[3].get_int();
716 if (params.size() > 4)
717 strComment = params[4].get_str();
719 CWalletDB walletdb(pwalletMain->strWalletFile);
722 int64 nNow = GetAdjustedTime();
725 CAccountingEntry debit;
726 debit.strAccount = strFrom;
727 debit.nCreditDebit = -nAmount;
729 debit.strOtherAccount = strTo;
730 debit.strComment = strComment;
731 walletdb.WriteAccountingEntry(debit);
734 CAccountingEntry credit;
735 credit.strAccount = strTo;
736 credit.nCreditDebit = nAmount;
738 credit.strOtherAccount = strFrom;
739 credit.strComment = strComment;
740 walletdb.WriteAccountingEntry(credit);
742 walletdb.TxnCommit();
748 Value sendfrom(const Array& params, bool fHelp)
750 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
752 "sendfrom <fromaccount> <tobitcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
753 "<amount> is a real and is rounded to the nearest 0.00000001\n"
754 "requires wallet passphrase to be set with walletpassphrase first");
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");
760 string strAccount = AccountFromValue(params[0]);
761 CBitcoinAddress address(params[1].get_str());
762 if (!address.IsValid())
763 throw JSONRPCError(-5, "Invalid bitcoin address");
764 int64 nAmount = AmountFromValue(params[2]);
766 if (params.size() > 3)
767 nMinDepth = params[3].get_int();
770 wtx.strFromAccount = strAccount;
771 if (params.size() > 4 && params[4].type() != null_type && !params[4].get_str().empty())
772 wtx.mapValue["comment"] = params[4].get_str();
773 if (params.size() > 5 && params[5].type() != null_type && !params[5].get_str().empty())
774 wtx.mapValue["to"] = params[5].get_str();
776 if (pwalletMain->IsLocked())
777 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
780 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
781 if (nAmount > nBalance)
782 throw JSONRPCError(-6, "Account has insufficient funds");
785 string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
787 throw JSONRPCError(-4, strError);
789 return wtx.GetHash().GetHex();
793 Value sendmany(const Array& params, bool fHelp)
795 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
797 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
798 "amounts are double-precision floating point numbers\n"
799 "requires wallet passphrase to be set with walletpassphrase first");
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");
805 string strAccount = AccountFromValue(params[0]);
806 Object sendTo = params[1].get_obj();
808 if (params.size() > 2)
809 nMinDepth = params[2].get_int();
812 wtx.strFromAccount = strAccount;
813 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
814 wtx.mapValue["comment"] = params[3].get_str();
816 set<CBitcoinAddress> setAddress;
817 vector<pair<CScript, int64> > vecSend;
819 int64 totalAmount = 0;
820 BOOST_FOREACH(const Pair& s, sendTo)
822 CBitcoinAddress address(s.name_);
823 if (!address.IsValid())
824 throw JSONRPCError(-5, string("Invalid bitcoin address:")+s.name_);
826 if (setAddress.count(address))
827 throw JSONRPCError(-8, string("Invalid parameter, duplicated address: ")+s.name_);
828 setAddress.insert(address);
830 CScript scriptPubKey;
831 scriptPubKey.SetBitcoinAddress(address);
832 int64 nAmount = AmountFromValue(s.value_);
833 totalAmount += nAmount;
835 vecSend.push_back(make_pair(scriptPubKey, nAmount));
838 if (pwalletMain->IsLocked())
839 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
842 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
843 if (totalAmount > nBalance)
844 throw JSONRPCError(-6, "Account has insufficient funds");
847 CReserveKey keyChange(pwalletMain);
848 int64 nFeeRequired = 0;
849 bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired);
852 if (totalAmount + nFeeRequired > pwalletMain->GetBalance())
853 throw JSONRPCError(-6, "Insufficient funds");
854 throw JSONRPCError(-4, "Transaction creation failed");
856 if (!pwalletMain->CommitTransaction(wtx, keyChange))
857 throw JSONRPCError(-4, "Transaction commit failed");
859 return wtx.GetHash().GetHex();
874 Value ListReceived(const Array& params, bool fByAccounts)
876 // Minimum confirmations
878 if (params.size() > 0)
879 nMinDepth = params[0].get_int();
881 // Whether to include empty accounts
882 bool fIncludeEmpty = false;
883 if (params.size() > 1)
884 fIncludeEmpty = params[1].get_bool();
887 map<CBitcoinAddress, tallyitem> mapTally;
888 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
890 const CWalletTx& wtx = (*it).second;
891 if (wtx.IsCoinBase() || !wtx.IsFinal())
894 int nDepth = wtx.GetDepthInMainChain();
895 if (nDepth < nMinDepth)
898 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
900 CBitcoinAddress address;
901 if (!ExtractAddress(txout.scriptPubKey, pwalletMain, address) || !address.IsValid())
904 tallyitem& item = mapTally[address];
905 item.nAmount += txout.nValue;
906 item.nConf = min(item.nConf, nDepth);
912 map<string, tallyitem> mapAccountTally;
913 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
915 const CBitcoinAddress& address = item.first;
916 const string& strAccount = item.second;
917 map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
918 if (it == mapTally.end() && !fIncludeEmpty)
923 if (it != mapTally.end())
925 nAmount = (*it).second.nAmount;
926 nConf = (*it).second.nConf;
931 tallyitem& item = mapAccountTally[strAccount];
932 item.nAmount += nAmount;
933 item.nConf = min(item.nConf, nConf);
938 obj.push_back(Pair("address", address.ToString()));
939 obj.push_back(Pair("account", strAccount));
940 obj.push_back(Pair("label", strAccount)); // deprecated
941 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
942 obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf)));
949 for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
951 int64 nAmount = (*it).second.nAmount;
952 int nConf = (*it).second.nConf;
954 obj.push_back(Pair("account", (*it).first));
955 obj.push_back(Pair("label", (*it).first)); // deprecated
956 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
957 obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf)));
965 Value listreceivedbyaddress(const Array& params, bool fHelp)
967 if (fHelp || params.size() > 2)
969 "listreceivedbyaddress [minconf=1] [includeempty=false]\n"
970 "[minconf] is the minimum number of confirmations before payments are included.\n"
971 "[includeempty] whether to include addresses that haven't received any payments.\n"
972 "Returns an array of objects containing:\n"
973 " \"address\" : receiving address\n"
974 " \"account\" : the account of the receiving address\n"
975 " \"amount\" : total amount received by the address\n"
976 " \"confirmations\" : number of confirmations of the most recent transaction included");
978 return ListReceived(params, false);
981 Value listreceivedbyaccount(const Array& params, bool fHelp)
983 if (fHelp || params.size() > 2)
985 "listreceivedbyaccount [minconf=1] [includeempty=false]\n"
986 "[minconf] is the minimum number of confirmations before payments are included.\n"
987 "[includeempty] whether to include accounts that haven't received any payments.\n"
988 "Returns an array of objects containing:\n"
989 " \"account\" : the account of the receiving addresses\n"
990 " \"amount\" : total amount received by addresses with this account\n"
991 " \"confirmations\" : number of confirmations of the most recent transaction included");
993 return ListReceived(params, true);
996 void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret)
998 int64 nGeneratedImmature, nGeneratedMature, nFee;
999 string strSentAccount;
1000 list<pair<CBitcoinAddress, int64> > listReceived;
1001 list<pair<CBitcoinAddress, int64> > listSent;
1002 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1004 bool fAllAccounts = (strAccount == string("*"));
1006 // Generated blocks assigned to account ""
1007 if ((nGeneratedMature+nGeneratedImmature) != 0 && (fAllAccounts || strAccount == ""))
1010 entry.push_back(Pair("account", string("")));
1011 if (nGeneratedImmature)
1013 entry.push_back(Pair("category", wtx.GetDepthInMainChain() ? "immature" : "orphan"));
1014 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedImmature)));
1018 entry.push_back(Pair("category", "generate"));
1019 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedMature)));
1022 WalletTxToJSON(wtx, entry);
1023 ret.push_back(entry);
1027 if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
1029 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1032 entry.push_back(Pair("account", strSentAccount));
1033 entry.push_back(Pair("address", s.first.ToString()));
1034 entry.push_back(Pair("category", "send"));
1035 entry.push_back(Pair("amount", ValueFromAmount(-s.second)));
1036 entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
1038 WalletTxToJSON(wtx, entry);
1039 ret.push_back(entry);
1044 if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
1045 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1048 if (pwalletMain->mapAddressBook.count(r.first))
1049 account = pwalletMain->mapAddressBook[r.first];
1050 if (fAllAccounts || (account == strAccount))
1053 entry.push_back(Pair("account", account));
1054 entry.push_back(Pair("address", r.first.ToString()));
1055 entry.push_back(Pair("category", "receive"));
1056 entry.push_back(Pair("amount", ValueFromAmount(r.second)));
1058 WalletTxToJSON(wtx, entry);
1059 ret.push_back(entry);
1064 void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret)
1066 bool fAllAccounts = (strAccount == string("*"));
1068 if (fAllAccounts || acentry.strAccount == strAccount)
1071 entry.push_back(Pair("account", acentry.strAccount));
1072 entry.push_back(Pair("category", "move"));
1073 entry.push_back(Pair("time", (boost::int64_t)acentry.nTime));
1074 entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
1075 entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
1076 entry.push_back(Pair("comment", acentry.strComment));
1077 ret.push_back(entry);
1081 Value listtransactions(const Array& params, bool fHelp)
1083 if (fHelp || params.size() > 3)
1084 throw runtime_error(
1085 "listtransactions [account] [count=10] [from=0]\n"
1086 "Returns up to [count] most recent transactions skipping the first [from] transactions for account [account].");
1088 string strAccount = "*";
1089 if (params.size() > 0)
1090 strAccount = params[0].get_str();
1092 if (params.size() > 1)
1093 nCount = params[1].get_int();
1095 if (params.size() > 2)
1096 nFrom = params[2].get_int();
1099 CWalletDB walletdb(pwalletMain->strWalletFile);
1101 // Firs: get all CWalletTx and CAccountingEntry into a sorted-by-time multimap:
1102 typedef pair<CWalletTx*, CAccountingEntry*> TxPair;
1103 typedef multimap<int64, TxPair > TxItems;
1106 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1108 CWalletTx* wtx = &((*it).second);
1109 txByTime.insert(make_pair(wtx->GetTxTime(), TxPair(wtx, (CAccountingEntry*)0)));
1111 list<CAccountingEntry> acentries;
1112 walletdb.ListAccountCreditDebit(strAccount, acentries);
1113 BOOST_FOREACH(CAccountingEntry& entry, acentries)
1115 txByTime.insert(make_pair(entry.nTime, TxPair((CWalletTx*)0, &entry)));
1118 // Now: iterate backwards until we have nCount items to return:
1119 TxItems::reverse_iterator it = txByTime.rbegin();
1120 if (txByTime.size() > nFrom) std::advance(it, nFrom);
1121 for (; it != txByTime.rend(); ++it)
1123 CWalletTx *const pwtx = (*it).second.first;
1125 ListTransactions(*pwtx, strAccount, 0, true, ret);
1126 CAccountingEntry *const pacentry = (*it).second.second;
1128 AcentryToJSON(*pacentry, strAccount, ret);
1130 if (ret.size() >= nCount) break;
1132 // ret is now newest to oldest
1134 // Make sure we return only last nCount items (sends-to-self might give us an extra):
1135 if (ret.size() > nCount)
1137 Array::iterator last = ret.begin();
1138 std::advance(last, nCount);
1139 ret.erase(last, ret.end());
1141 std::reverse(ret.begin(), ret.end()); // oldest to newest
1146 Value listaccounts(const Array& params, bool fHelp)
1148 if (fHelp || params.size() > 1)
1149 throw runtime_error(
1150 "listaccounts [minconf=1]\n"
1151 "Returns Object that has account names as keys, account balances as values.");
1154 if (params.size() > 0)
1155 nMinDepth = params[0].get_int();
1157 map<string, int64> mapAccountBalances;
1158 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& entry, pwalletMain->mapAddressBook) {
1159 if (pwalletMain->HaveKey(entry.first)) // This address belongs to me
1160 mapAccountBalances[entry.second] = 0;
1163 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1165 const CWalletTx& wtx = (*it).second;
1166 int64 nGeneratedImmature, nGeneratedMature, nFee;
1167 string strSentAccount;
1168 list<pair<CBitcoinAddress, int64> > listReceived;
1169 list<pair<CBitcoinAddress, int64> > listSent;
1170 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1171 mapAccountBalances[strSentAccount] -= nFee;
1172 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1173 mapAccountBalances[strSentAccount] -= s.second;
1174 if (wtx.GetDepthInMainChain() >= nMinDepth)
1176 mapAccountBalances[""] += nGeneratedMature;
1177 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1178 if (pwalletMain->mapAddressBook.count(r.first))
1179 mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second;
1181 mapAccountBalances[""] += r.second;
1185 list<CAccountingEntry> acentries;
1186 CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
1187 BOOST_FOREACH(const CAccountingEntry& entry, acentries)
1188 mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
1191 BOOST_FOREACH(const PAIRTYPE(string, int64)& accountBalance, mapAccountBalances) {
1192 ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
1197 Value gettransaction(const Array& params, bool fHelp)
1199 if (fHelp || params.size() != 1)
1200 throw runtime_error(
1201 "gettransaction <txid>\n"
1202 "Get detailed information about <txid>");
1205 hash.SetHex(params[0].get_str());
1209 if (!pwalletMain->mapWallet.count(hash))
1210 throw JSONRPCError(-5, "Invalid or non-wallet transaction id");
1211 const CWalletTx& wtx = pwalletMain->mapWallet[hash];
1213 int64 nCredit = wtx.GetCredit();
1214 int64 nDebit = wtx.GetDebit();
1215 int64 nNet = nCredit - nDebit;
1216 int64 nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0);
1218 entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
1220 entry.push_back(Pair("fee", ValueFromAmount(nFee)));
1222 WalletTxToJSON(pwalletMain->mapWallet[hash], entry);
1225 ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details);
1226 entry.push_back(Pair("details", details));
1232 Value backupwallet(const Array& params, bool fHelp)
1234 if (fHelp || params.size() != 1)
1235 throw runtime_error(
1236 "backupwallet <destination>\n"
1237 "Safely copies wallet.dat to destination, which can be a directory or a path with filename.");
1239 string strDest = params[0].get_str();
1240 BackupWallet(*pwalletMain, strDest);
1246 Value keypoolrefill(const Array& params, bool fHelp)
1248 if (pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1249 throw runtime_error(
1251 "Fills the keypool, requires wallet passphrase to be set.");
1252 if (!pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1253 throw runtime_error(
1255 "Fills the keypool.");
1257 if (pwalletMain->IsLocked())
1258 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
1260 pwalletMain->TopUpKeyPool();
1262 if (pwalletMain->GetKeyPoolSize() < GetArg("-keypool", 100))
1263 throw JSONRPCError(-4, "Error refreshing keypool.");
1269 void ThreadTopUpKeyPool(void* parg)
1271 pwalletMain->TopUpKeyPool();
1274 void ThreadCleanWalletPassphrase(void* parg)
1276 int64 nMyWakeTime = GetTime() + *((int*)parg);
1278 if (nWalletUnlockTime == 0)
1280 CRITICAL_BLOCK(cs_nWalletUnlockTime)
1282 nWalletUnlockTime = nMyWakeTime;
1285 while (GetTime() < nWalletUnlockTime)
1286 Sleep(GetTime() - nWalletUnlockTime);
1288 CRITICAL_BLOCK(cs_nWalletUnlockTime)
1290 nWalletUnlockTime = 0;
1295 CRITICAL_BLOCK(cs_nWalletUnlockTime)
1297 if (nWalletUnlockTime < nMyWakeTime)
1298 nWalletUnlockTime = nMyWakeTime;
1304 pwalletMain->Lock();
1309 Value walletpassphrase(const Array& params, bool fHelp)
1311 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1312 throw runtime_error(
1313 "walletpassphrase <passphrase> <timeout>\n"
1314 "Stores the wallet decryption key in memory for <timeout> seconds.");
1317 if (!pwalletMain->IsCrypted())
1318 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
1320 if (!pwalletMain->IsLocked())
1321 throw JSONRPCError(-17, "Error: Wallet is already unlocked.");
1323 // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
1324 string strWalletPass;
1325 strWalletPass.reserve(100);
1326 mlock(&strWalletPass[0], strWalletPass.capacity());
1327 strWalletPass = params[0].get_str();
1329 if (strWalletPass.length() > 0)
1331 if (!pwalletMain->Unlock(strWalletPass))
1333 fill(strWalletPass.begin(), strWalletPass.end(), '\0');
1334 munlock(&strWalletPass[0], strWalletPass.capacity());
1335 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1337 fill(strWalletPass.begin(), strWalletPass.end(), '\0');
1338 munlock(&strWalletPass[0], strWalletPass.capacity());
1341 throw runtime_error(
1342 "walletpassphrase <passphrase> <timeout>\n"
1343 "Stores the wallet decryption key in memory for <timeout> seconds.");
1345 CreateThread(ThreadTopUpKeyPool, NULL);
1346 int* pnSleepTime = new int(params[1].get_int());
1347 CreateThread(ThreadCleanWalletPassphrase, pnSleepTime);
1353 Value walletpassphrasechange(const Array& params, bool fHelp)
1355 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1356 throw runtime_error(
1357 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1358 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1361 if (!pwalletMain->IsCrypted())
1362 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
1364 string strOldWalletPass;
1365 strOldWalletPass.reserve(100);
1366 mlock(&strOldWalletPass[0], strOldWalletPass.capacity());
1367 strOldWalletPass = params[0].get_str();
1369 string strNewWalletPass;
1370 strNewWalletPass.reserve(100);
1371 mlock(&strNewWalletPass[0], strNewWalletPass.capacity());
1372 strNewWalletPass = params[1].get_str();
1374 if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
1375 throw runtime_error(
1376 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1377 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1379 if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
1381 fill(strOldWalletPass.begin(), strOldWalletPass.end(), '\0');
1382 fill(strNewWalletPass.begin(), strNewWalletPass.end(), '\0');
1383 munlock(&strOldWalletPass[0], strOldWalletPass.capacity());
1384 munlock(&strNewWalletPass[0], strNewWalletPass.capacity());
1385 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1387 fill(strNewWalletPass.begin(), strNewWalletPass.end(), '\0');
1388 fill(strOldWalletPass.begin(), strOldWalletPass.end(), '\0');
1389 munlock(&strOldWalletPass[0], strOldWalletPass.capacity());
1390 munlock(&strNewWalletPass[0], strNewWalletPass.capacity());
1396 Value walletlock(const Array& params, bool fHelp)
1398 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
1399 throw runtime_error(
1401 "Removes the wallet encryption key from memory, locking the wallet.\n"
1402 "After calling this method, you will need to call walletpassphrase again\n"
1403 "before being able to call any methods which require the wallet to be unlocked.");
1406 if (!pwalletMain->IsCrypted())
1407 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletlock was called.");
1409 pwalletMain->Lock();
1410 CRITICAL_BLOCK(cs_nWalletUnlockTime)
1412 nWalletUnlockTime = 0;
1419 Value encryptwallet(const Array& params, bool fHelp)
1421 if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
1422 throw runtime_error(
1423 "encryptwallet <passphrase>\n"
1424 "Encrypts the wallet with <passphrase>.");
1427 if (pwalletMain->IsCrypted())
1428 throw JSONRPCError(-15, "Error: running with an encrypted wallet, but encryptwallet was called.");
1430 string strWalletPass;
1431 strWalletPass.reserve(100);
1432 mlock(&strWalletPass[0], strWalletPass.capacity());
1433 strWalletPass = params[0].get_str();
1435 if (strWalletPass.length() < 1)
1436 throw runtime_error(
1437 "encryptwallet <passphrase>\n"
1438 "Encrypts the wallet with <passphrase>.");
1440 if (!pwalletMain->EncryptWallet(strWalletPass))
1442 fill(strWalletPass.begin(), strWalletPass.end(), '\0');
1443 munlock(&strWalletPass[0], strWalletPass.capacity());
1444 throw JSONRPCError(-16, "Error: Failed to encrypt the wallet.");
1446 fill(strWalletPass.begin(), strWalletPass.end(), '\0');
1447 munlock(&strWalletPass[0], strWalletPass.capacity());
1453 Value validateaddress(const Array& params, bool fHelp)
1455 if (fHelp || params.size() != 1)
1456 throw runtime_error(
1457 "validateaddress <bitcoinaddress>\n"
1458 "Return information about <bitcoinaddress>.");
1460 CBitcoinAddress address(params[0].get_str());
1461 bool isValid = address.IsValid();
1464 ret.push_back(Pair("isvalid", isValid));
1467 // Call Hash160ToAddress() so we always return current ADDRESSVERSION
1468 // version of the address:
1469 string currentAddress = address.ToString();
1470 ret.push_back(Pair("address", currentAddress));
1471 ret.push_back(Pair("ismine", (pwalletMain->HaveKey(address) > 0)));
1472 if (pwalletMain->mapAddressBook.count(address))
1473 ret.push_back(Pair("account", pwalletMain->mapAddressBook[address]));
1479 Value getwork(const Array& params, bool fHelp)
1481 if (fHelp || params.size() > 1)
1482 throw runtime_error(
1484 "If [data] is not specified, returns formatted hash data to work on:\n"
1485 " \"midstate\" : precomputed hash state after hashing the first half of the data\n"
1486 " \"data\" : block data\n"
1487 " \"hash1\" : formatted hash buffer for second hash\n"
1488 " \"target\" : little endian hash target\n"
1489 "If [data] is specified, tries to solve the block and returns true if it was successful.");
1492 throw JSONRPCError(-9, "Bitcoin is not connected!");
1494 if (IsInitialBlockDownload())
1495 throw JSONRPCError(-10, "Bitcoin is downloading blocks...");
1497 typedef map<uint256, pair<CBlock*, CScript> > mapNewBlock_t;
1498 static mapNewBlock_t mapNewBlock;
1499 static vector<CBlock*> vNewBlock;
1500 static CReserveKey reservekey(pwalletMain);
1502 if (params.size() == 0)
1505 static unsigned int nTransactionsUpdatedLast;
1506 static CBlockIndex* pindexPrev;
1507 static int64 nStart;
1508 static CBlock* pblock;
1509 if (pindexPrev != pindexBest ||
1510 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60))
1512 if (pindexPrev != pindexBest)
1514 // Deallocate old blocks since they're obsolete now
1515 mapNewBlock.clear();
1516 BOOST_FOREACH(CBlock* pblock, vNewBlock)
1520 nTransactionsUpdatedLast = nTransactionsUpdated;
1521 pindexPrev = pindexBest;
1525 pblock = CreateNewBlock(reservekey);
1527 throw JSONRPCError(-7, "Out of memory");
1528 vNewBlock.push_back(pblock);
1532 pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
1535 // Update nExtraNonce
1536 static unsigned int nExtraNonce = 0;
1537 IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
1540 mapNewBlock[pblock->hashMerkleRoot] = make_pair(pblock, pblock->vtx[0].vin[0].scriptSig);
1542 // Prebuild hash buffers
1546 FormatHashBuffers(pblock, pmidstate, pdata, phash1);
1548 uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
1551 result.push_back(Pair("midstate", HexStr(BEGIN(pmidstate), END(pmidstate))));
1552 result.push_back(Pair("data", HexStr(BEGIN(pdata), END(pdata))));
1553 result.push_back(Pair("hash1", HexStr(BEGIN(phash1), END(phash1))));
1554 result.push_back(Pair("target", HexStr(BEGIN(hashTarget), END(hashTarget))));
1560 vector<unsigned char> vchData = ParseHex(params[0].get_str());
1561 if (vchData.size() != 128)
1562 throw JSONRPCError(-8, "Invalid parameter");
1563 CBlock* pdata = (CBlock*)&vchData[0];
1566 for (int i = 0; i < 128/4; i++)
1567 ((unsigned int*)pdata)[i] = CryptoPP::ByteReverse(((unsigned int*)pdata)[i]);
1570 if (!mapNewBlock.count(pdata->hashMerkleRoot))
1572 CBlock* pblock = mapNewBlock[pdata->hashMerkleRoot].first;
1574 pblock->nTime = pdata->nTime;
1575 pblock->nNonce = pdata->nNonce;
1576 pblock->vtx[0].vin[0].scriptSig = mapNewBlock[pdata->hashMerkleRoot].second;
1577 pblock->hashMerkleRoot = pblock->BuildMerkleTree();
1579 return CheckWork(pblock, *pwalletMain, reservekey);
1597 pair<string, rpcfn_type> pCallTable[] =
1599 make_pair("help", &help),
1600 make_pair("stop", &stop),
1601 make_pair("getblockcount", &getblockcount),
1602 make_pair("getblocknumber", &getblocknumber),
1603 make_pair("getconnectioncount", &getconnectioncount),
1604 make_pair("getdifficulty", &getdifficulty),
1605 make_pair("getgenerate", &getgenerate),
1606 make_pair("setgenerate", &setgenerate),
1607 make_pair("gethashespersec", &gethashespersec),
1608 make_pair("getinfo", &getinfo),
1609 make_pair("getnewaddress", &getnewaddress),
1610 make_pair("getaccountaddress", &getaccountaddress),
1611 make_pair("setaccount", &setaccount),
1612 make_pair("setlabel", &setaccount), // deprecated
1613 make_pair("getaccount", &getaccount),
1614 make_pair("getlabel", &getaccount), // deprecated
1615 make_pair("getaddressesbyaccount", &getaddressesbyaccount),
1616 make_pair("getaddressesbylabel", &getaddressesbyaccount), // deprecated
1617 make_pair("sendtoaddress", &sendtoaddress),
1618 make_pair("getamountreceived", &getreceivedbyaddress), // deprecated, renamed to getreceivedbyaddress
1619 make_pair("getallreceived", &listreceivedbyaddress), // deprecated, renamed to listreceivedbyaddress
1620 make_pair("getreceivedbyaddress", &getreceivedbyaddress),
1621 make_pair("getreceivedbyaccount", &getreceivedbyaccount),
1622 make_pair("getreceivedbylabel", &getreceivedbyaccount), // deprecated
1623 make_pair("listreceivedbyaddress", &listreceivedbyaddress),
1624 make_pair("listreceivedbyaccount", &listreceivedbyaccount),
1625 make_pair("listreceivedbylabel", &listreceivedbyaccount), // deprecated
1626 make_pair("backupwallet", &backupwallet),
1627 make_pair("keypoolrefill", &keypoolrefill),
1628 make_pair("walletpassphrase", &walletpassphrase),
1629 make_pair("walletpassphrasechange", &walletpassphrasechange),
1630 make_pair("walletlock", &walletlock),
1631 make_pair("encryptwallet", &encryptwallet),
1632 make_pair("validateaddress", &validateaddress),
1633 make_pair("getbalance", &getbalance),
1634 make_pair("move", &movecmd),
1635 make_pair("sendfrom", &sendfrom),
1636 make_pair("sendmany", &sendmany),
1637 make_pair("gettransaction", &gettransaction),
1638 make_pair("listtransactions", &listtransactions),
1639 make_pair("getwork", &getwork),
1640 make_pair("listaccounts", &listaccounts),
1641 make_pair("settxfee", &settxfee),
1643 map<string, rpcfn_type> mapCallTable(pCallTable, pCallTable + sizeof(pCallTable)/sizeof(pCallTable[0]));
1645 string pAllowInSafeMode[] =
1651 "getconnectioncount",
1658 "getaccountaddress",
1659 "setlabel", // deprecated
1661 "getlabel", // deprecated
1662 "getaddressesbyaccount",
1663 "getaddressesbylabel", // deprecated
1671 set<string> setAllowInSafeMode(pAllowInSafeMode, pAllowInSafeMode + sizeof(pAllowInSafeMode)/sizeof(pAllowInSafeMode[0]));
1679 // This ain't Apache. We're just using HTTP header for the length field
1680 // and to be compatible with other JSON-RPC implementations.
1683 string HTTPPost(const string& strMsg, const map<string,string>& mapRequestHeaders)
1686 s << "POST / HTTP/1.1\r\n"
1687 << "User-Agent: bitcoin-json-rpc/" << FormatFullVersion() << "\r\n"
1688 << "Host: 127.0.0.1\r\n"
1689 << "Content-Type: application/json\r\n"
1690 << "Content-Length: " << strMsg.size() << "\r\n"
1691 << "Accept: application/json\r\n";
1692 BOOST_FOREACH(const PAIRTYPE(string, string)& item, mapRequestHeaders)
1693 s << item.first << ": " << item.second << "\r\n";
1694 s << "\r\n" << strMsg;
1699 string rfc1123Time()
1704 struct tm* now_gmt = gmtime(&now);
1705 string locale(setlocale(LC_TIME, NULL));
1706 setlocale(LC_TIME, "C"); // we want posix (aka "C") weekday/month strings
1707 strftime(buffer, sizeof(buffer), "%a, %d %b %Y %H:%M:%S +0000", now_gmt);
1708 setlocale(LC_TIME, locale.c_str());
1709 return string(buffer);
1712 static string HTTPReply(int nStatus, const string& strMsg)
1715 return strprintf("HTTP/1.0 401 Authorization Required\r\n"
1717 "Server: bitcoin-json-rpc/%s\r\n"
1718 "WWW-Authenticate: Basic realm=\"jsonrpc\"\r\n"
1719 "Content-Type: text/html\r\n"
1720 "Content-Length: 296\r\n"
1722 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\r\n"
1723 "\"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd\">\r\n"
1726 "<TITLE>Error</TITLE>\r\n"
1727 "<META HTTP-EQUIV='Content-Type' CONTENT='text/html; charset=ISO-8859-1'>\r\n"
1729 "<BODY><H1>401 Unauthorized.</H1></BODY>\r\n"
1730 "</HTML>\r\n", rfc1123Time().c_str(), FormatFullVersion().c_str());
1732 if (nStatus == 200) strStatus = "OK";
1733 else if (nStatus == 400) strStatus = "Bad Request";
1734 else if (nStatus == 403) strStatus = "Forbidden";
1735 else if (nStatus == 404) strStatus = "Not Found";
1736 else if (nStatus == 500) strStatus = "Internal Server Error";
1738 "HTTP/1.1 %d %s\r\n"
1740 "Connection: close\r\n"
1741 "Content-Length: %d\r\n"
1742 "Content-Type: application/json\r\n"
1743 "Server: bitcoin-json-rpc/%s\r\n"
1748 rfc1123Time().c_str(),
1750 FormatFullVersion().c_str(),
1754 int ReadHTTPStatus(std::basic_istream<char>& stream)
1757 getline(stream, str);
1758 vector<string> vWords;
1759 boost::split(vWords, str, boost::is_any_of(" "));
1760 if (vWords.size() < 2)
1762 return atoi(vWords[1].c_str());
1765 int ReadHTTPHeader(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet)
1771 std::getline(stream, str);
1772 if (str.empty() || str == "\r")
1774 string::size_type nColon = str.find(":");
1775 if (nColon != string::npos)
1777 string strHeader = str.substr(0, nColon);
1778 boost::trim(strHeader);
1779 boost::to_lower(strHeader);
1780 string strValue = str.substr(nColon+1);
1781 boost::trim(strValue);
1782 mapHeadersRet[strHeader] = strValue;
1783 if (strHeader == "content-length")
1784 nLen = atoi(strValue.c_str());
1790 int ReadHTTP(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet, string& strMessageRet)
1792 mapHeadersRet.clear();
1796 int nStatus = ReadHTTPStatus(stream);
1799 int nLen = ReadHTTPHeader(stream, mapHeadersRet);
1800 if (nLen < 0 || nLen > MAX_SIZE)
1806 vector<char> vch(nLen);
1807 stream.read(&vch[0], nLen);
1808 strMessageRet = string(vch.begin(), vch.end());
1814 string EncodeBase64(string s)
1819 b64 = BIO_new(BIO_f_base64());
1820 BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
1821 bmem = BIO_new(BIO_s_mem());
1822 b64 = BIO_push(b64, bmem);
1823 BIO_write(b64, s.c_str(), s.size());
1825 BIO_get_mem_ptr(b64, &bptr);
1827 string result(bptr->data, bptr->length);
1833 string DecodeBase64(string s)
1837 char* buffer = static_cast<char*>(calloc(s.size(), sizeof(char)));
1839 b64 = BIO_new(BIO_f_base64());
1840 BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
1841 bmem = BIO_new_mem_buf(const_cast<char*>(s.c_str()), s.size());
1842 bmem = BIO_push(b64, bmem);
1843 BIO_read(bmem, buffer, s.size());
1846 string result(buffer);
1851 bool HTTPAuthorized(map<string, string>& mapHeaders)
1853 string strAuth = mapHeaders["authorization"];
1854 if (strAuth.substr(0,6) != "Basic ")
1856 string strUserPass64 = strAuth.substr(6); boost::trim(strUserPass64);
1857 string strUserPass = DecodeBase64(strUserPass64);
1858 string::size_type nColon = strUserPass.find(":");
1859 if (nColon == string::npos)
1861 string strUser = strUserPass.substr(0, nColon);
1862 string strPassword = strUserPass.substr(nColon+1);
1863 return (strUser == mapArgs["-rpcuser"] && strPassword == mapArgs["-rpcpassword"]);
1867 // JSON-RPC protocol. Bitcoin speaks version 1.0 for maximum compatibility,
1868 // but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
1869 // unspecified (HTTP errors and contents of 'error').
1871 // 1.0 spec: http://json-rpc.org/wiki/specification
1872 // 1.2 spec: http://groups.google.com/group/json-rpc/web/json-rpc-over-http
1873 // http://www.codeproject.com/KB/recipes/JSON_Spirit.aspx
1876 string JSONRPCRequest(const string& strMethod, const Array& params, const Value& id)
1879 request.push_back(Pair("method", strMethod));
1880 request.push_back(Pair("params", params));
1881 request.push_back(Pair("id", id));
1882 return write_string(Value(request), false) + "\n";
1885 string JSONRPCReply(const Value& result, const Value& error, const Value& id)
1888 if (error.type() != null_type)
1889 reply.push_back(Pair("result", Value::null));
1891 reply.push_back(Pair("result", result));
1892 reply.push_back(Pair("error", error));
1893 reply.push_back(Pair("id", id));
1894 return write_string(Value(reply), false) + "\n";
1897 void ErrorReply(std::ostream& stream, const Object& objError, const Value& id)
1899 // Send error reply from json-rpc error object
1901 int code = find_value(objError, "code").get_int();
1902 if (code == -32600) nStatus = 400;
1903 else if (code == -32601) nStatus = 404;
1904 string strReply = JSONRPCReply(Value::null, objError, id);
1905 stream << HTTPReply(nStatus, strReply) << std::flush;
1908 bool ClientAllowed(const string& strAddress)
1910 if (strAddress == asio::ip::address_v4::loopback().to_string())
1912 const vector<string>& vAllow = mapMultiArgs["-rpcallowip"];
1913 BOOST_FOREACH(string strAllow, vAllow)
1914 if (WildcardMatch(strAddress, strAllow))
1921 // IOStream device that speaks SSL but can also speak non-SSL
1923 class SSLIOStreamDevice : public iostreams::device<iostreams::bidirectional> {
1925 SSLIOStreamDevice(SSLStream &streamIn, bool fUseSSLIn) : stream(streamIn)
1927 fUseSSL = fUseSSLIn;
1928 fNeedHandshake = fUseSSLIn;
1931 void handshake(ssl::stream_base::handshake_type role)
1933 if (!fNeedHandshake) return;
1934 fNeedHandshake = false;
1935 stream.handshake(role);
1937 std::streamsize read(char* s, std::streamsize n)
1939 handshake(ssl::stream_base::server); // HTTPS servers read first
1940 if (fUseSSL) return stream.read_some(asio::buffer(s, n));
1941 return stream.next_layer().read_some(asio::buffer(s, n));
1943 std::streamsize write(const char* s, std::streamsize n)
1945 handshake(ssl::stream_base::client); // HTTPS clients write first
1946 if (fUseSSL) return asio::write(stream, asio::buffer(s, n));
1947 return asio::write(stream.next_layer(), asio::buffer(s, n));
1949 bool connect(const std::string& server, const std::string& port)
1951 ip::tcp::resolver resolver(stream.get_io_service());
1952 ip::tcp::resolver::query query(server.c_str(), port.c_str());
1953 ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
1954 ip::tcp::resolver::iterator end;
1955 boost::system::error_code error = asio::error::host_not_found;
1956 while (error && endpoint_iterator != end)
1958 stream.lowest_layer().close();
1959 stream.lowest_layer().connect(*endpoint_iterator++, error);
1967 bool fNeedHandshake;
1973 void ThreadRPCServer(void* parg)
1975 IMPLEMENT_RANDOMIZE_STACK(ThreadRPCServer(parg));
1978 vnThreadsRunning[4]++;
1979 ThreadRPCServer2(parg);
1980 vnThreadsRunning[4]--;
1982 catch (std::exception& e) {
1983 vnThreadsRunning[4]--;
1984 PrintException(&e, "ThreadRPCServer()");
1986 vnThreadsRunning[4]--;
1987 PrintException(NULL, "ThreadRPCServer()");
1989 printf("ThreadRPCServer exiting\n");
1992 void ThreadRPCServer2(void* parg)
1994 printf("ThreadRPCServer started\n");
1996 if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
1998 string strWhatAmI = "To use bitcoind";
1999 if (mapArgs.count("-server"))
2000 strWhatAmI = strprintf(_("To use the %s option"), "\"-server\"");
2001 else if (mapArgs.count("-daemon"))
2002 strWhatAmI = strprintf(_("To use the %s option"), "\"-daemon\"");
2004 _("Warning: %s, you must set rpcpassword=<password>\nin the configuration file: %s\n"
2005 "If the file does not exist, create it with owner-readable-only file permissions.\n"),
2007 GetConfigFile().c_str());
2008 CreateThread(Shutdown, NULL);
2012 bool fUseSSL = GetBoolArg("-rpcssl");
2013 asio::ip::address bindAddress = mapArgs.count("-rpcallowip") ? asio::ip::address_v4::any() : asio::ip::address_v4::loopback();
2015 asio::io_service io_service;
2016 ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", 8332));
2017 ip::tcp::acceptor acceptor(io_service, endpoint);
2019 acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
2022 ssl::context context(io_service, ssl::context::sslv23);
2025 context.set_options(ssl::context::no_sslv2);
2026 filesystem::path certfile = GetArg("-rpcsslcertificatechainfile", "server.cert");
2027 if (!certfile.is_complete()) certfile = filesystem::path(GetDataDir()) / certfile;
2028 if (filesystem::exists(certfile)) context.use_certificate_chain_file(certfile.string().c_str());
2029 else printf("ThreadRPCServer ERROR: missing server certificate file %s\n", certfile.string().c_str());
2030 filesystem::path pkfile = GetArg("-rpcsslprivatekeyfile", "server.pem");
2031 if (!pkfile.is_complete()) pkfile = filesystem::path(GetDataDir()) / pkfile;
2032 if (filesystem::exists(pkfile)) context.use_private_key_file(pkfile.string().c_str(), ssl::context::pem);
2033 else printf("ThreadRPCServer ERROR: missing server private key file %s\n", pkfile.string().c_str());
2035 string ciphers = GetArg("-rpcsslciphers",
2036 "TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH");
2037 SSL_CTX_set_cipher_list(context.impl(), ciphers.c_str());
2041 throw runtime_error("-rpcssl=1, but bitcoin compiled without full openssl libraries.");
2046 // Accept connection
2048 SSLStream sslStream(io_service, context);
2049 SSLIOStreamDevice d(sslStream, fUseSSL);
2050 iostreams::stream<SSLIOStreamDevice> stream(d);
2052 ip::tcp::iostream stream;
2055 ip::tcp::endpoint peer;
2056 vnThreadsRunning[4]--;
2058 acceptor.accept(sslStream.lowest_layer(), peer);
2060 acceptor.accept(*stream.rdbuf(), peer);
2062 vnThreadsRunning[4]++;
2066 // Restrict callers by IP
2067 if (!ClientAllowed(peer.address().to_string()))
2069 // Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake.
2071 stream << HTTPReply(403, "") << std::flush;
2075 map<string, string> mapHeaders;
2078 boost::thread api_caller(ReadHTTP, boost::ref(stream), boost::ref(mapHeaders), boost::ref(strRequest));
2079 if (!api_caller.timed_join(boost::posix_time::seconds(GetArg("-rpctimeout", 30))))
2082 printf("ThreadRPCServer ReadHTTP timeout\n");
2086 // Check authorization
2087 if (mapHeaders.count("authorization") == 0)
2089 stream << HTTPReply(401, "") << std::flush;
2092 if (!HTTPAuthorized(mapHeaders))
2094 // Deter brute-forcing short passwords
2095 if (mapArgs["-rpcpassword"].size() < 15)
2098 stream << HTTPReply(401, "") << std::flush;
2099 printf("ThreadRPCServer incorrect password attempt\n");
2103 Value id = Value::null;
2108 if (!read_string(strRequest, valRequest) || valRequest.type() != obj_type)
2109 throw JSONRPCError(-32700, "Parse error");
2110 const Object& request = valRequest.get_obj();
2112 // Parse id now so errors from here on will have the id
2113 id = find_value(request, "id");
2116 Value valMethod = find_value(request, "method");
2117 if (valMethod.type() == null_type)
2118 throw JSONRPCError(-32600, "Missing method");
2119 if (valMethod.type() != str_type)
2120 throw JSONRPCError(-32600, "Method must be a string");
2121 string strMethod = valMethod.get_str();
2122 if (strMethod != "getwork")
2123 printf("ThreadRPCServer method=%s\n", strMethod.c_str());
2126 Value valParams = find_value(request, "params");
2128 if (valParams.type() == array_type)
2129 params = valParams.get_array();
2130 else if (valParams.type() == null_type)
2133 throw JSONRPCError(-32600, "Params must be an array");
2136 map<string, rpcfn_type>::iterator mi = mapCallTable.find(strMethod);
2137 if (mi == mapCallTable.end())
2138 throw JSONRPCError(-32601, "Method not found");
2140 // Observe safe mode
2141 string strWarning = GetWarnings("rpc");
2142 if (strWarning != "" && !GetBoolArg("-disablesafemode") && !setAllowInSafeMode.count(strMethod))
2143 throw JSONRPCError(-2, string("Safe mode: ") + strWarning);
2149 CRITICAL_BLOCK(cs_main)
2150 CRITICAL_BLOCK(pwalletMain->cs_wallet)
2151 result = (*(*mi).second)(params, false);
2154 string strReply = JSONRPCReply(result, Value::null, id);
2155 stream << HTTPReply(200, strReply) << std::flush;
2157 catch (std::exception& e)
2159 ErrorReply(stream, JSONRPCError(-1, e.what()), id);
2162 catch (Object& objError)
2164 ErrorReply(stream, objError, id);
2166 catch (std::exception& e)
2168 ErrorReply(stream, JSONRPCError(-32700, e.what()), id);
2176 Object CallRPC(const string& strMethod, const Array& params)
2178 if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
2179 throw runtime_error(strprintf(
2180 _("You must set rpcpassword=<password> in the configuration file:\n%s\n"
2181 "If the file does not exist, create it with owner-readable-only file permissions."),
2182 GetConfigFile().c_str()));
2184 // Connect to localhost
2185 bool fUseSSL = GetBoolArg("-rpcssl");
2187 asio::io_service io_service;
2188 ssl::context context(io_service, ssl::context::sslv23);
2189 context.set_options(ssl::context::no_sslv2);
2190 SSLStream sslStream(io_service, context);
2191 SSLIOStreamDevice d(sslStream, fUseSSL);
2192 iostreams::stream<SSLIOStreamDevice> stream(d);
2193 if (!d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332")))
2194 throw runtime_error("couldn't connect to server");
2197 throw runtime_error("-rpcssl=1, but bitcoin compiled without full openssl libraries.");
2199 ip::tcp::iostream stream(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332"));
2201 throw runtime_error("couldn't connect to server");
2205 // HTTP basic authentication
2206 string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
2207 map<string, string> mapRequestHeaders;
2208 mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64;
2211 string strRequest = JSONRPCRequest(strMethod, params, 1);
2212 string strPost = HTTPPost(strRequest, mapRequestHeaders);
2213 stream << strPost << std::flush;
2216 map<string, string> mapHeaders;
2218 int nStatus = ReadHTTP(stream, mapHeaders, strReply);
2220 throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
2221 else if (nStatus >= 400 && nStatus != 400 && nStatus != 404 && nStatus != 500)
2222 throw runtime_error(strprintf("server returned HTTP error %d", nStatus));
2223 else if (strReply.empty())
2224 throw runtime_error("no response from server");
2228 if (!read_string(strReply, valReply))
2229 throw runtime_error("couldn't parse reply from server");
2230 const Object& reply = valReply.get_obj();
2232 throw runtime_error("expected reply to have result, error and id properties");
2240 template<typename T>
2241 void ConvertTo(Value& value)
2243 if (value.type() == str_type)
2245 // reinterpret string as unquoted json value
2247 if (!read_string(value.get_str(), value2))
2248 throw runtime_error("type mismatch");
2249 value = value2.get_value<T>();
2253 value = value.get_value<T>();
2257 int CommandLineRPC(int argc, char *argv[])
2264 while (argc > 1 && IsSwitchChar(argv[1][0]))
2272 throw runtime_error("too few parameters");
2273 string strMethod = argv[1];
2275 // Parameters default to strings
2277 for (int i = 2; i < argc; i++)
2278 params.push_back(argv[i]);
2279 int n = params.size();
2282 // Special case non-string parameter types
2284 if (strMethod == "setgenerate" && n > 0) ConvertTo<bool>(params[0]);
2285 if (strMethod == "setgenerate" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2286 if (strMethod == "sendtoaddress" && n > 1) ConvertTo<double>(params[1]);
2287 if (strMethod == "settxfee" && n > 0) ConvertTo<double>(params[0]);
2288 if (strMethod == "getamountreceived" && n > 1) ConvertTo<boost::int64_t>(params[1]); // deprecated
2289 if (strMethod == "getreceivedbyaddress" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2290 if (strMethod == "getreceivedbyaccount" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2291 if (strMethod == "getreceivedbylabel" && n > 1) ConvertTo<boost::int64_t>(params[1]); // deprecated
2292 if (strMethod == "getallreceived" && n > 0) ConvertTo<boost::int64_t>(params[0]); // deprecated
2293 if (strMethod == "getallreceived" && n > 1) ConvertTo<bool>(params[1]); // deprecated
2294 if (strMethod == "listreceivedbyaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2295 if (strMethod == "listreceivedbyaddress" && n > 1) ConvertTo<bool>(params[1]);
2296 if (strMethod == "listreceivedbyaccount" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2297 if (strMethod == "listreceivedbyaccount" && n > 1) ConvertTo<bool>(params[1]);
2298 if (strMethod == "listreceivedbylabel" && n > 0) ConvertTo<boost::int64_t>(params[0]); // deprecated
2299 if (strMethod == "listreceivedbylabel" && n > 1) ConvertTo<bool>(params[1]); // deprecated
2300 if (strMethod == "getbalance" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2301 if (strMethod == "move" && n > 2) ConvertTo<double>(params[2]);
2302 if (strMethod == "move" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2303 if (strMethod == "sendfrom" && n > 2) ConvertTo<double>(params[2]);
2304 if (strMethod == "sendfrom" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2305 if (strMethod == "listtransactions" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2306 if (strMethod == "listtransactions" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2307 if (strMethod == "listaccounts" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2308 if (strMethod == "walletpassphrase" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2309 if (strMethod == "sendmany" && n > 1)
2311 string s = params[1].get_str();
2313 if (!read_string(s, v) || v.type() != obj_type)
2314 throw runtime_error("type mismatch");
2315 params[1] = v.get_obj();
2317 if (strMethod == "sendmany" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2320 Object reply = CallRPC(strMethod, params);
2323 const Value& result = find_value(reply, "result");
2324 const Value& error = find_value(reply, "error");
2326 if (error.type() != null_type)
2329 strPrint = "error: " + write_string(error, false);
2330 int code = find_value(error.get_obj(), "code").get_int();
2336 if (result.type() == null_type)
2338 else if (result.type() == str_type)
2339 strPrint = result.get_str();
2341 strPrint = write_string(result, true);
2344 catch (std::exception& e)
2346 strPrint = string("error: ") + e.what();
2351 PrintException(NULL, "CommandLineRPC()");
2356 fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
2365 int main(int argc, char *argv[])
2368 // Turn off microsoft heap dump noise
2369 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
2370 _CrtSetReportFile(_CRT_WARN, CreateFile("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0));
2372 setbuf(stdin, NULL);
2373 setbuf(stdout, NULL);
2374 setbuf(stderr, NULL);
2378 if (argc >= 2 && string(argv[1]) == "-server")
2380 printf("server ready\n");
2381 ThreadRPCServer(NULL);
2385 return CommandLineRPC(argc, argv);
2388 catch (std::exception& e) {
2389 PrintException(&e, "main()");
2391 PrintException(NULL, "main()");