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 bool HTTPAuthorized(map<string, string>& mapHeaders)
1816 string strAuth = mapHeaders["authorization"];
1817 if (strAuth.substr(0,6) != "Basic ")
1819 string strUserPass64 = strAuth.substr(6); boost::trim(strUserPass64);
1820 string strUserPass = DecodeBase64(strUserPass64);
1821 string::size_type nColon = strUserPass.find(":");
1822 if (nColon == string::npos)
1824 string strUser = strUserPass.substr(0, nColon);
1825 string strPassword = strUserPass.substr(nColon+1);
1826 return (strUser == mapArgs["-rpcuser"] && strPassword == mapArgs["-rpcpassword"]);
1830 // JSON-RPC protocol. Bitcoin speaks version 1.0 for maximum compatibility,
1831 // but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
1832 // unspecified (HTTP errors and contents of 'error').
1834 // 1.0 spec: http://json-rpc.org/wiki/specification
1835 // 1.2 spec: http://groups.google.com/group/json-rpc/web/json-rpc-over-http
1836 // http://www.codeproject.com/KB/recipes/JSON_Spirit.aspx
1839 string JSONRPCRequest(const string& strMethod, const Array& params, const Value& id)
1842 request.push_back(Pair("method", strMethod));
1843 request.push_back(Pair("params", params));
1844 request.push_back(Pair("id", id));
1845 return write_string(Value(request), false) + "\n";
1848 string JSONRPCReply(const Value& result, const Value& error, const Value& id)
1851 if (error.type() != null_type)
1852 reply.push_back(Pair("result", Value::null));
1854 reply.push_back(Pair("result", result));
1855 reply.push_back(Pair("error", error));
1856 reply.push_back(Pair("id", id));
1857 return write_string(Value(reply), false) + "\n";
1860 void ErrorReply(std::ostream& stream, const Object& objError, const Value& id)
1862 // Send error reply from json-rpc error object
1864 int code = find_value(objError, "code").get_int();
1865 if (code == -32600) nStatus = 400;
1866 else if (code == -32601) nStatus = 404;
1867 string strReply = JSONRPCReply(Value::null, objError, id);
1868 stream << HTTPReply(nStatus, strReply) << std::flush;
1871 bool ClientAllowed(const string& strAddress)
1873 if (strAddress == asio::ip::address_v4::loopback().to_string())
1875 const vector<string>& vAllow = mapMultiArgs["-rpcallowip"];
1876 BOOST_FOREACH(string strAllow, vAllow)
1877 if (WildcardMatch(strAddress, strAllow))
1884 // IOStream device that speaks SSL but can also speak non-SSL
1886 class SSLIOStreamDevice : public iostreams::device<iostreams::bidirectional> {
1888 SSLIOStreamDevice(SSLStream &streamIn, bool fUseSSLIn) : stream(streamIn)
1890 fUseSSL = fUseSSLIn;
1891 fNeedHandshake = fUseSSLIn;
1894 void handshake(ssl::stream_base::handshake_type role)
1896 if (!fNeedHandshake) return;
1897 fNeedHandshake = false;
1898 stream.handshake(role);
1900 std::streamsize read(char* s, std::streamsize n)
1902 handshake(ssl::stream_base::server); // HTTPS servers read first
1903 if (fUseSSL) return stream.read_some(asio::buffer(s, n));
1904 return stream.next_layer().read_some(asio::buffer(s, n));
1906 std::streamsize write(const char* s, std::streamsize n)
1908 handshake(ssl::stream_base::client); // HTTPS clients write first
1909 if (fUseSSL) return asio::write(stream, asio::buffer(s, n));
1910 return asio::write(stream.next_layer(), asio::buffer(s, n));
1912 bool connect(const std::string& server, const std::string& port)
1914 ip::tcp::resolver resolver(stream.get_io_service());
1915 ip::tcp::resolver::query query(server.c_str(), port.c_str());
1916 ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
1917 ip::tcp::resolver::iterator end;
1918 boost::system::error_code error = asio::error::host_not_found;
1919 while (error && endpoint_iterator != end)
1921 stream.lowest_layer().close();
1922 stream.lowest_layer().connect(*endpoint_iterator++, error);
1930 bool fNeedHandshake;
1936 void ThreadRPCServer(void* parg)
1938 IMPLEMENT_RANDOMIZE_STACK(ThreadRPCServer(parg));
1941 vnThreadsRunning[4]++;
1942 ThreadRPCServer2(parg);
1943 vnThreadsRunning[4]--;
1945 catch (std::exception& e) {
1946 vnThreadsRunning[4]--;
1947 PrintException(&e, "ThreadRPCServer()");
1949 vnThreadsRunning[4]--;
1950 PrintException(NULL, "ThreadRPCServer()");
1952 printf("ThreadRPCServer exiting\n");
1955 void ThreadRPCServer2(void* parg)
1957 printf("ThreadRPCServer started\n");
1959 if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
1961 string strWhatAmI = "To use bitcoind";
1962 if (mapArgs.count("-server"))
1963 strWhatAmI = strprintf(_("To use the %s option"), "\"-server\"");
1964 else if (mapArgs.count("-daemon"))
1965 strWhatAmI = strprintf(_("To use the %s option"), "\"-daemon\"");
1967 _("Warning: %s, you must set rpcpassword=<password>\nin the configuration file: %s\n"
1968 "If the file does not exist, create it with owner-readable-only file permissions.\n"),
1970 GetConfigFile().c_str());
1971 CreateThread(Shutdown, NULL);
1975 bool fUseSSL = GetBoolArg("-rpcssl");
1976 asio::ip::address bindAddress = mapArgs.count("-rpcallowip") ? asio::ip::address_v4::any() : asio::ip::address_v4::loopback();
1978 asio::io_service io_service;
1979 ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", 8332));
1980 ip::tcp::acceptor acceptor(io_service, endpoint);
1982 acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
1985 ssl::context context(io_service, ssl::context::sslv23);
1988 context.set_options(ssl::context::no_sslv2);
1989 filesystem::path certfile = GetArg("-rpcsslcertificatechainfile", "server.cert");
1990 if (!certfile.is_complete()) certfile = filesystem::path(GetDataDir()) / certfile;
1991 if (filesystem::exists(certfile)) context.use_certificate_chain_file(certfile.string().c_str());
1992 else printf("ThreadRPCServer ERROR: missing server certificate file %s\n", certfile.string().c_str());
1993 filesystem::path pkfile = GetArg("-rpcsslprivatekeyfile", "server.pem");
1994 if (!pkfile.is_complete()) pkfile = filesystem::path(GetDataDir()) / pkfile;
1995 if (filesystem::exists(pkfile)) context.use_private_key_file(pkfile.string().c_str(), ssl::context::pem);
1996 else printf("ThreadRPCServer ERROR: missing server private key file %s\n", pkfile.string().c_str());
1998 string ciphers = GetArg("-rpcsslciphers",
1999 "TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH");
2000 SSL_CTX_set_cipher_list(context.impl(), ciphers.c_str());
2004 throw runtime_error("-rpcssl=1, but bitcoin compiled without full openssl libraries.");
2009 // Accept connection
2011 SSLStream sslStream(io_service, context);
2012 SSLIOStreamDevice d(sslStream, fUseSSL);
2013 iostreams::stream<SSLIOStreamDevice> stream(d);
2015 ip::tcp::iostream stream;
2018 ip::tcp::endpoint peer;
2019 vnThreadsRunning[4]--;
2021 acceptor.accept(sslStream.lowest_layer(), peer);
2023 acceptor.accept(*stream.rdbuf(), peer);
2025 vnThreadsRunning[4]++;
2029 // Restrict callers by IP
2030 if (!ClientAllowed(peer.address().to_string()))
2032 // Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake.
2034 stream << HTTPReply(403, "") << std::flush;
2038 map<string, string> mapHeaders;
2041 boost::thread api_caller(ReadHTTP, boost::ref(stream), boost::ref(mapHeaders), boost::ref(strRequest));
2042 if (!api_caller.timed_join(boost::posix_time::seconds(GetArg("-rpctimeout", 30))))
2045 printf("ThreadRPCServer ReadHTTP timeout\n");
2049 // Check authorization
2050 if (mapHeaders.count("authorization") == 0)
2052 stream << HTTPReply(401, "") << std::flush;
2055 if (!HTTPAuthorized(mapHeaders))
2057 // Deter brute-forcing short passwords
2058 if (mapArgs["-rpcpassword"].size() < 15)
2061 stream << HTTPReply(401, "") << std::flush;
2062 printf("ThreadRPCServer incorrect password attempt\n");
2066 Value id = Value::null;
2071 if (!read_string(strRequest, valRequest) || valRequest.type() != obj_type)
2072 throw JSONRPCError(-32700, "Parse error");
2073 const Object& request = valRequest.get_obj();
2075 // Parse id now so errors from here on will have the id
2076 id = find_value(request, "id");
2079 Value valMethod = find_value(request, "method");
2080 if (valMethod.type() == null_type)
2081 throw JSONRPCError(-32600, "Missing method");
2082 if (valMethod.type() != str_type)
2083 throw JSONRPCError(-32600, "Method must be a string");
2084 string strMethod = valMethod.get_str();
2085 if (strMethod != "getwork")
2086 printf("ThreadRPCServer method=%s\n", strMethod.c_str());
2089 Value valParams = find_value(request, "params");
2091 if (valParams.type() == array_type)
2092 params = valParams.get_array();
2093 else if (valParams.type() == null_type)
2096 throw JSONRPCError(-32600, "Params must be an array");
2099 map<string, rpcfn_type>::iterator mi = mapCallTable.find(strMethod);
2100 if (mi == mapCallTable.end())
2101 throw JSONRPCError(-32601, "Method not found");
2103 // Observe safe mode
2104 string strWarning = GetWarnings("rpc");
2105 if (strWarning != "" && !GetBoolArg("-disablesafemode") && !setAllowInSafeMode.count(strMethod))
2106 throw JSONRPCError(-2, string("Safe mode: ") + strWarning);
2112 CRITICAL_BLOCK(cs_main)
2113 CRITICAL_BLOCK(pwalletMain->cs_wallet)
2114 result = (*(*mi).second)(params, false);
2117 string strReply = JSONRPCReply(result, Value::null, id);
2118 stream << HTTPReply(200, strReply) << std::flush;
2120 catch (std::exception& e)
2122 ErrorReply(stream, JSONRPCError(-1, e.what()), id);
2125 catch (Object& objError)
2127 ErrorReply(stream, objError, id);
2129 catch (std::exception& e)
2131 ErrorReply(stream, JSONRPCError(-32700, e.what()), id);
2139 Object CallRPC(const string& strMethod, const Array& params)
2141 if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
2142 throw runtime_error(strprintf(
2143 _("You must set rpcpassword=<password> in the configuration file:\n%s\n"
2144 "If the file does not exist, create it with owner-readable-only file permissions."),
2145 GetConfigFile().c_str()));
2147 // Connect to localhost
2148 bool fUseSSL = GetBoolArg("-rpcssl");
2150 asio::io_service io_service;
2151 ssl::context context(io_service, ssl::context::sslv23);
2152 context.set_options(ssl::context::no_sslv2);
2153 SSLStream sslStream(io_service, context);
2154 SSLIOStreamDevice d(sslStream, fUseSSL);
2155 iostreams::stream<SSLIOStreamDevice> stream(d);
2156 if (!d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332")))
2157 throw runtime_error("couldn't connect to server");
2160 throw runtime_error("-rpcssl=1, but bitcoin compiled without full openssl libraries.");
2162 ip::tcp::iostream stream(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332"));
2164 throw runtime_error("couldn't connect to server");
2168 // HTTP basic authentication
2169 string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
2170 map<string, string> mapRequestHeaders;
2171 mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64;
2174 string strRequest = JSONRPCRequest(strMethod, params, 1);
2175 string strPost = HTTPPost(strRequest, mapRequestHeaders);
2176 stream << strPost << std::flush;
2179 map<string, string> mapHeaders;
2181 int nStatus = ReadHTTP(stream, mapHeaders, strReply);
2183 throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
2184 else if (nStatus >= 400 && nStatus != 400 && nStatus != 404 && nStatus != 500)
2185 throw runtime_error(strprintf("server returned HTTP error %d", nStatus));
2186 else if (strReply.empty())
2187 throw runtime_error("no response from server");
2191 if (!read_string(strReply, valReply))
2192 throw runtime_error("couldn't parse reply from server");
2193 const Object& reply = valReply.get_obj();
2195 throw runtime_error("expected reply to have result, error and id properties");
2203 template<typename T>
2204 void ConvertTo(Value& value)
2206 if (value.type() == str_type)
2208 // reinterpret string as unquoted json value
2210 if (!read_string(value.get_str(), value2))
2211 throw runtime_error("type mismatch");
2212 value = value2.get_value<T>();
2216 value = value.get_value<T>();
2220 int CommandLineRPC(int argc, char *argv[])
2227 while (argc > 1 && IsSwitchChar(argv[1][0]))
2235 throw runtime_error("too few parameters");
2236 string strMethod = argv[1];
2238 // Parameters default to strings
2240 for (int i = 2; i < argc; i++)
2241 params.push_back(argv[i]);
2242 int n = params.size();
2245 // Special case non-string parameter types
2247 if (strMethod == "setgenerate" && n > 0) ConvertTo<bool>(params[0]);
2248 if (strMethod == "setgenerate" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2249 if (strMethod == "sendtoaddress" && n > 1) ConvertTo<double>(params[1]);
2250 if (strMethod == "settxfee" && n > 0) ConvertTo<double>(params[0]);
2251 if (strMethod == "getamountreceived" && n > 1) ConvertTo<boost::int64_t>(params[1]); // deprecated
2252 if (strMethod == "getreceivedbyaddress" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2253 if (strMethod == "getreceivedbyaccount" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2254 if (strMethod == "getreceivedbylabel" && n > 1) ConvertTo<boost::int64_t>(params[1]); // deprecated
2255 if (strMethod == "getallreceived" && n > 0) ConvertTo<boost::int64_t>(params[0]); // deprecated
2256 if (strMethod == "getallreceived" && n > 1) ConvertTo<bool>(params[1]); // deprecated
2257 if (strMethod == "listreceivedbyaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2258 if (strMethod == "listreceivedbyaddress" && n > 1) ConvertTo<bool>(params[1]);
2259 if (strMethod == "listreceivedbyaccount" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2260 if (strMethod == "listreceivedbyaccount" && n > 1) ConvertTo<bool>(params[1]);
2261 if (strMethod == "listreceivedbylabel" && n > 0) ConvertTo<boost::int64_t>(params[0]); // deprecated
2262 if (strMethod == "listreceivedbylabel" && n > 1) ConvertTo<bool>(params[1]); // deprecated
2263 if (strMethod == "getbalance" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2264 if (strMethod == "move" && n > 2) ConvertTo<double>(params[2]);
2265 if (strMethod == "move" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2266 if (strMethod == "sendfrom" && n > 2) ConvertTo<double>(params[2]);
2267 if (strMethod == "sendfrom" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2268 if (strMethod == "listtransactions" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2269 if (strMethod == "listtransactions" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2270 if (strMethod == "listaccounts" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2271 if (strMethod == "walletpassphrase" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2272 if (strMethod == "sendmany" && n > 1)
2274 string s = params[1].get_str();
2276 if (!read_string(s, v) || v.type() != obj_type)
2277 throw runtime_error("type mismatch");
2278 params[1] = v.get_obj();
2280 if (strMethod == "sendmany" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2283 Object reply = CallRPC(strMethod, params);
2286 const Value& result = find_value(reply, "result");
2287 const Value& error = find_value(reply, "error");
2289 if (error.type() != null_type)
2292 strPrint = "error: " + write_string(error, false);
2293 int code = find_value(error.get_obj(), "code").get_int();
2299 if (result.type() == null_type)
2301 else if (result.type() == str_type)
2302 strPrint = result.get_str();
2304 strPrint = write_string(result, true);
2307 catch (std::exception& e)
2309 strPrint = string("error: ") + e.what();
2314 PrintException(NULL, "CommandLineRPC()");
2319 fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
2328 int main(int argc, char *argv[])
2331 // Turn off microsoft heap dump noise
2332 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
2333 _CrtSetReportFile(_CRT_WARN, CreateFile("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0));
2335 setbuf(stdin, NULL);
2336 setbuf(stdout, NULL);
2337 setbuf(stderr, NULL);
2341 if (argc >= 2 && string(argv[1]) == "-server")
2343 printf("server ready\n");
2344 ThreadRPCServer(NULL);
2348 return CommandLineRPC(argc, argv);
2351 catch (std::exception& e) {
2352 PrintException(&e, "main()");
2354 PrintException(NULL, "main()");