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 bool HTTPAuthorized(map<string, string>& mapHeaders)
1835 string strAuth = mapHeaders["authorization"];
1836 if (strAuth.substr(0,6) != "Basic ")
1838 string strUserPass64 = strAuth.substr(6); boost::trim(strUserPass64);
1839 string strUserPass = DecodeBase64(strUserPass64);
1840 string::size_type nColon = strUserPass.find(":");
1841 if (nColon == string::npos)
1843 string strUser = strUserPass.substr(0, nColon);
1844 string strPassword = strUserPass.substr(nColon+1);
1845 return (strUser == mapArgs["-rpcuser"] && strPassword == mapArgs["-rpcpassword"]);
1849 // JSON-RPC protocol. Bitcoin speaks version 1.0 for maximum compatibility,
1850 // but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
1851 // unspecified (HTTP errors and contents of 'error').
1853 // 1.0 spec: http://json-rpc.org/wiki/specification
1854 // 1.2 spec: http://groups.google.com/group/json-rpc/web/json-rpc-over-http
1855 // http://www.codeproject.com/KB/recipes/JSON_Spirit.aspx
1858 string JSONRPCRequest(const string& strMethod, const Array& params, const Value& id)
1861 request.push_back(Pair("method", strMethod));
1862 request.push_back(Pair("params", params));
1863 request.push_back(Pair("id", id));
1864 return write_string(Value(request), false) + "\n";
1867 string JSONRPCReply(const Value& result, const Value& error, const Value& id)
1870 if (error.type() != null_type)
1871 reply.push_back(Pair("result", Value::null));
1873 reply.push_back(Pair("result", result));
1874 reply.push_back(Pair("error", error));
1875 reply.push_back(Pair("id", id));
1876 return write_string(Value(reply), false) + "\n";
1879 void ErrorReply(std::ostream& stream, const Object& objError, const Value& id)
1881 // Send error reply from json-rpc error object
1883 int code = find_value(objError, "code").get_int();
1884 if (code == -32600) nStatus = 400;
1885 else if (code == -32601) nStatus = 404;
1886 string strReply = JSONRPCReply(Value::null, objError, id);
1887 stream << HTTPReply(nStatus, strReply) << std::flush;
1890 bool ClientAllowed(const string& strAddress)
1892 if (strAddress == asio::ip::address_v4::loopback().to_string())
1894 const vector<string>& vAllow = mapMultiArgs["-rpcallowip"];
1895 BOOST_FOREACH(string strAllow, vAllow)
1896 if (WildcardMatch(strAddress, strAllow))
1903 // IOStream device that speaks SSL but can also speak non-SSL
1905 class SSLIOStreamDevice : public iostreams::device<iostreams::bidirectional> {
1907 SSLIOStreamDevice(SSLStream &streamIn, bool fUseSSLIn) : stream(streamIn)
1909 fUseSSL = fUseSSLIn;
1910 fNeedHandshake = fUseSSLIn;
1913 void handshake(ssl::stream_base::handshake_type role)
1915 if (!fNeedHandshake) return;
1916 fNeedHandshake = false;
1917 stream.handshake(role);
1919 std::streamsize read(char* s, std::streamsize n)
1921 handshake(ssl::stream_base::server); // HTTPS servers read first
1922 if (fUseSSL) return stream.read_some(asio::buffer(s, n));
1923 return stream.next_layer().read_some(asio::buffer(s, n));
1925 std::streamsize write(const char* s, std::streamsize n)
1927 handshake(ssl::stream_base::client); // HTTPS clients write first
1928 if (fUseSSL) return asio::write(stream, asio::buffer(s, n));
1929 return asio::write(stream.next_layer(), asio::buffer(s, n));
1931 bool connect(const std::string& server, const std::string& port)
1933 ip::tcp::resolver resolver(stream.get_io_service());
1934 ip::tcp::resolver::query query(server.c_str(), port.c_str());
1935 ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
1936 ip::tcp::resolver::iterator end;
1937 boost::system::error_code error = asio::error::host_not_found;
1938 while (error && endpoint_iterator != end)
1940 stream.lowest_layer().close();
1941 stream.lowest_layer().connect(*endpoint_iterator++, error);
1949 bool fNeedHandshake;
1955 void ThreadRPCServer(void* parg)
1957 IMPLEMENT_RANDOMIZE_STACK(ThreadRPCServer(parg));
1960 vnThreadsRunning[4]++;
1961 ThreadRPCServer2(parg);
1962 vnThreadsRunning[4]--;
1964 catch (std::exception& e) {
1965 vnThreadsRunning[4]--;
1966 PrintException(&e, "ThreadRPCServer()");
1968 vnThreadsRunning[4]--;
1969 PrintException(NULL, "ThreadRPCServer()");
1971 printf("ThreadRPCServer exiting\n");
1974 void ThreadRPCServer2(void* parg)
1976 printf("ThreadRPCServer started\n");
1978 if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
1980 string strWhatAmI = "To use bitcoind";
1981 if (mapArgs.count("-server"))
1982 strWhatAmI = strprintf(_("To use the %s option"), "\"-server\"");
1983 else if (mapArgs.count("-daemon"))
1984 strWhatAmI = strprintf(_("To use the %s option"), "\"-daemon\"");
1986 _("Warning: %s, you must set rpcpassword=<password>\nin the configuration file: %s\n"
1987 "If the file does not exist, create it with owner-readable-only file permissions.\n"),
1989 GetConfigFile().c_str());
1990 CreateThread(Shutdown, NULL);
1994 bool fUseSSL = GetBoolArg("-rpcssl");
1995 asio::ip::address bindAddress = mapArgs.count("-rpcallowip") ? asio::ip::address_v4::any() : asio::ip::address_v4::loopback();
1997 asio::io_service io_service;
1998 ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", 8332));
1999 ip::tcp::acceptor acceptor(io_service, endpoint);
2001 acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
2004 ssl::context context(io_service, ssl::context::sslv23);
2007 context.set_options(ssl::context::no_sslv2);
2008 filesystem::path certfile = GetArg("-rpcsslcertificatechainfile", "server.cert");
2009 if (!certfile.is_complete()) certfile = filesystem::path(GetDataDir()) / certfile;
2010 if (filesystem::exists(certfile)) context.use_certificate_chain_file(certfile.string().c_str());
2011 else printf("ThreadRPCServer ERROR: missing server certificate file %s\n", certfile.string().c_str());
2012 filesystem::path pkfile = GetArg("-rpcsslprivatekeyfile", "server.pem");
2013 if (!pkfile.is_complete()) pkfile = filesystem::path(GetDataDir()) / pkfile;
2014 if (filesystem::exists(pkfile)) context.use_private_key_file(pkfile.string().c_str(), ssl::context::pem);
2015 else printf("ThreadRPCServer ERROR: missing server private key file %s\n", pkfile.string().c_str());
2017 string ciphers = GetArg("-rpcsslciphers",
2018 "TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH");
2019 SSL_CTX_set_cipher_list(context.impl(), ciphers.c_str());
2023 throw runtime_error("-rpcssl=1, but bitcoin compiled without full openssl libraries.");
2028 // Accept connection
2030 SSLStream sslStream(io_service, context);
2031 SSLIOStreamDevice d(sslStream, fUseSSL);
2032 iostreams::stream<SSLIOStreamDevice> stream(d);
2034 ip::tcp::iostream stream;
2037 ip::tcp::endpoint peer;
2038 vnThreadsRunning[4]--;
2040 acceptor.accept(sslStream.lowest_layer(), peer);
2042 acceptor.accept(*stream.rdbuf(), peer);
2044 vnThreadsRunning[4]++;
2048 // Restrict callers by IP
2049 if (!ClientAllowed(peer.address().to_string()))
2051 // Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake.
2053 stream << HTTPReply(403, "") << std::flush;
2057 map<string, string> mapHeaders;
2060 boost::thread api_caller(ReadHTTP, boost::ref(stream), boost::ref(mapHeaders), boost::ref(strRequest));
2061 if (!api_caller.timed_join(boost::posix_time::seconds(GetArg("-rpctimeout", 30))))
2064 printf("ThreadRPCServer ReadHTTP timeout\n");
2068 // Check authorization
2069 if (mapHeaders.count("authorization") == 0)
2071 stream << HTTPReply(401, "") << std::flush;
2074 if (!HTTPAuthorized(mapHeaders))
2076 // Deter brute-forcing short passwords
2077 if (mapArgs["-rpcpassword"].size() < 15)
2080 stream << HTTPReply(401, "") << std::flush;
2081 printf("ThreadRPCServer incorrect password attempt\n");
2085 Value id = Value::null;
2090 if (!read_string(strRequest, valRequest) || valRequest.type() != obj_type)
2091 throw JSONRPCError(-32700, "Parse error");
2092 const Object& request = valRequest.get_obj();
2094 // Parse id now so errors from here on will have the id
2095 id = find_value(request, "id");
2098 Value valMethod = find_value(request, "method");
2099 if (valMethod.type() == null_type)
2100 throw JSONRPCError(-32600, "Missing method");
2101 if (valMethod.type() != str_type)
2102 throw JSONRPCError(-32600, "Method must be a string");
2103 string strMethod = valMethod.get_str();
2104 if (strMethod != "getwork")
2105 printf("ThreadRPCServer method=%s\n", strMethod.c_str());
2108 Value valParams = find_value(request, "params");
2110 if (valParams.type() == array_type)
2111 params = valParams.get_array();
2112 else if (valParams.type() == null_type)
2115 throw JSONRPCError(-32600, "Params must be an array");
2118 map<string, rpcfn_type>::iterator mi = mapCallTable.find(strMethod);
2119 if (mi == mapCallTable.end())
2120 throw JSONRPCError(-32601, "Method not found");
2122 // Observe safe mode
2123 string strWarning = GetWarnings("rpc");
2124 if (strWarning != "" && !GetBoolArg("-disablesafemode") && !setAllowInSafeMode.count(strMethod))
2125 throw JSONRPCError(-2, string("Safe mode: ") + strWarning);
2131 CRITICAL_BLOCK(cs_main)
2132 CRITICAL_BLOCK(pwalletMain->cs_wallet)
2133 result = (*(*mi).second)(params, false);
2136 string strReply = JSONRPCReply(result, Value::null, id);
2137 stream << HTTPReply(200, strReply) << std::flush;
2139 catch (std::exception& e)
2141 ErrorReply(stream, JSONRPCError(-1, e.what()), id);
2144 catch (Object& objError)
2146 ErrorReply(stream, objError, id);
2148 catch (std::exception& e)
2150 ErrorReply(stream, JSONRPCError(-32700, e.what()), id);
2158 Object CallRPC(const string& strMethod, const Array& params)
2160 if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
2161 throw runtime_error(strprintf(
2162 _("You must set rpcpassword=<password> in the configuration file:\n%s\n"
2163 "If the file does not exist, create it with owner-readable-only file permissions."),
2164 GetConfigFile().c_str()));
2166 // Connect to localhost
2167 bool fUseSSL = GetBoolArg("-rpcssl");
2169 asio::io_service io_service;
2170 ssl::context context(io_service, ssl::context::sslv23);
2171 context.set_options(ssl::context::no_sslv2);
2172 SSLStream sslStream(io_service, context);
2173 SSLIOStreamDevice d(sslStream, fUseSSL);
2174 iostreams::stream<SSLIOStreamDevice> stream(d);
2175 if (!d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332")))
2176 throw runtime_error("couldn't connect to server");
2179 throw runtime_error("-rpcssl=1, but bitcoin compiled without full openssl libraries.");
2181 ip::tcp::iostream stream(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332"));
2183 throw runtime_error("couldn't connect to server");
2187 // HTTP basic authentication
2188 string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
2189 map<string, string> mapRequestHeaders;
2190 mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64;
2193 string strRequest = JSONRPCRequest(strMethod, params, 1);
2194 string strPost = HTTPPost(strRequest, mapRequestHeaders);
2195 stream << strPost << std::flush;
2198 map<string, string> mapHeaders;
2200 int nStatus = ReadHTTP(stream, mapHeaders, strReply);
2202 throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
2203 else if (nStatus >= 400 && nStatus != 400 && nStatus != 404 && nStatus != 500)
2204 throw runtime_error(strprintf("server returned HTTP error %d", nStatus));
2205 else if (strReply.empty())
2206 throw runtime_error("no response from server");
2210 if (!read_string(strReply, valReply))
2211 throw runtime_error("couldn't parse reply from server");
2212 const Object& reply = valReply.get_obj();
2214 throw runtime_error("expected reply to have result, error and id properties");
2222 template<typename T>
2223 void ConvertTo(Value& value)
2225 if (value.type() == str_type)
2227 // reinterpret string as unquoted json value
2229 if (!read_string(value.get_str(), value2))
2230 throw runtime_error("type mismatch");
2231 value = value2.get_value<T>();
2235 value = value.get_value<T>();
2239 int CommandLineRPC(int argc, char *argv[])
2246 while (argc > 1 && IsSwitchChar(argv[1][0]))
2254 throw runtime_error("too few parameters");
2255 string strMethod = argv[1];
2257 // Parameters default to strings
2259 for (int i = 2; i < argc; i++)
2260 params.push_back(argv[i]);
2261 int n = params.size();
2264 // Special case non-string parameter types
2266 if (strMethod == "setgenerate" && n > 0) ConvertTo<bool>(params[0]);
2267 if (strMethod == "setgenerate" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2268 if (strMethod == "sendtoaddress" && n > 1) ConvertTo<double>(params[1]);
2269 if (strMethod == "settxfee" && n > 0) ConvertTo<double>(params[0]);
2270 if (strMethod == "getamountreceived" && n > 1) ConvertTo<boost::int64_t>(params[1]); // deprecated
2271 if (strMethod == "getreceivedbyaddress" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2272 if (strMethod == "getreceivedbyaccount" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2273 if (strMethod == "getreceivedbylabel" && n > 1) ConvertTo<boost::int64_t>(params[1]); // deprecated
2274 if (strMethod == "getallreceived" && n > 0) ConvertTo<boost::int64_t>(params[0]); // deprecated
2275 if (strMethod == "getallreceived" && n > 1) ConvertTo<bool>(params[1]); // deprecated
2276 if (strMethod == "listreceivedbyaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2277 if (strMethod == "listreceivedbyaddress" && n > 1) ConvertTo<bool>(params[1]);
2278 if (strMethod == "listreceivedbyaccount" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2279 if (strMethod == "listreceivedbyaccount" && n > 1) ConvertTo<bool>(params[1]);
2280 if (strMethod == "listreceivedbylabel" && n > 0) ConvertTo<boost::int64_t>(params[0]); // deprecated
2281 if (strMethod == "listreceivedbylabel" && n > 1) ConvertTo<bool>(params[1]); // deprecated
2282 if (strMethod == "getbalance" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2283 if (strMethod == "move" && n > 2) ConvertTo<double>(params[2]);
2284 if (strMethod == "move" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2285 if (strMethod == "sendfrom" && n > 2) ConvertTo<double>(params[2]);
2286 if (strMethod == "sendfrom" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2287 if (strMethod == "listtransactions" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2288 if (strMethod == "listtransactions" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2289 if (strMethod == "listaccounts" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2290 if (strMethod == "walletpassphrase" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2291 if (strMethod == "sendmany" && n > 1)
2293 string s = params[1].get_str();
2295 if (!read_string(s, v) || v.type() != obj_type)
2296 throw runtime_error("type mismatch");
2297 params[1] = v.get_obj();
2299 if (strMethod == "sendmany" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2302 Object reply = CallRPC(strMethod, params);
2305 const Value& result = find_value(reply, "result");
2306 const Value& error = find_value(reply, "error");
2308 if (error.type() != null_type)
2311 strPrint = "error: " + write_string(error, false);
2312 int code = find_value(error.get_obj(), "code").get_int();
2318 if (result.type() == null_type)
2320 else if (result.type() == str_type)
2321 strPrint = result.get_str();
2323 strPrint = write_string(result, true);
2326 catch (std::exception& e)
2328 strPrint = string("error: ") + e.what();
2333 PrintException(NULL, "CommandLineRPC()");
2338 fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
2347 int main(int argc, char *argv[])
2350 // Turn off microsoft heap dump noise
2351 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
2352 _CrtSetReportFile(_CRT_WARN, CreateFile("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0));
2354 setbuf(stdin, NULL);
2355 setbuf(stdout, NULL);
2356 setbuf(stderr, NULL);
2360 if (argc >= 2 && string(argv[1]) == "-server")
2362 printf("server ready\n");
2363 ThreadRPCServer(NULL);
2367 return CommandLineRPC(argc, argv);
2370 catch (std::exception& e) {
2371 PrintException(&e, "main()");
2373 PrintException(NULL, "main()");