1 // Copyright (c) 2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2012 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.
11 #include <boost/asio.hpp>
12 #include <boost/iostreams/concepts.hpp>
13 #include <boost/iostreams/stream.hpp>
14 #include <boost/algorithm/string.hpp>
16 #include <boost/asio/ssl.hpp>
17 #include <boost/filesystem.hpp>
18 #include <boost/filesystem/fstream.hpp>
19 typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> SSLStream;
21 #include "json/json_spirit_reader_template.h"
22 #include "json/json_spirit_writer_template.h"
23 #include "json/json_spirit_utils.h"
24 #define printf OutputDebugStringF
25 // MinGW 3.4.5 gets "fatal error: had to relocate PCH" if the json headers are
26 // precompiled in headers.h. The problem might be when the pch file goes over
27 // a certain size around 145MB. If we need access to json_spirit outside this
28 // file, we could use the compiled json_spirit option.
31 using namespace boost;
32 using namespace boost::asio;
33 using namespace json_spirit;
35 void ThreadRPCServer2(void* parg);
36 typedef Value(*rpcfn_type)(const Array& params, bool fHelp);
37 extern map<string, rpcfn_type> mapCallTable;
39 static int64 nWalletUnlockTime;
40 static CCriticalSection cs_nWalletUnlockTime;
43 Object JSONRPCError(int code, const string& message)
46 error.push_back(Pair("code", code));
47 error.push_back(Pair("message", message));
52 void PrintConsole(const std::string &format, ...)
55 int limit = sizeof(buffer);
57 va_start(arg_ptr, format);
58 int ret = _vsnprintf(buffer, limit, format.c_str(), arg_ptr);
60 if (ret < 0 || ret >= limit)
66 fprintf(stdout, "%s", buffer);
70 int64 AmountFromValue(const Value& value)
72 double dAmount = value.get_real();
73 if (dAmount <= 0.0 || dAmount > 21000000.0)
74 throw JSONRPCError(-3, "Invalid amount");
75 int64 nAmount = roundint64(dAmount * COIN);
76 if (!MoneyRange(nAmount))
77 throw JSONRPCError(-3, "Invalid amount");
81 Value ValueFromAmount(int64 amount)
83 return (double)amount / (double)COIN;
86 void WalletTxToJSON(const CWalletTx& wtx, Object& entry)
88 entry.push_back(Pair("confirmations", wtx.GetDepthInMainChain()));
89 entry.push_back(Pair("txid", wtx.GetHash().GetHex()));
90 entry.push_back(Pair("time", (boost::int64_t)wtx.GetTxTime()));
91 BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue)
92 entry.push_back(Pair(item.first, item.second));
95 string AccountFromValue(const Value& value)
97 string strAccount = value.get_str();
98 if (strAccount == "*")
99 throw JSONRPCError(-11, "Invalid account name");
106 /// Note: This interface may still be subject to change.
110 Value help(const Array& params, bool fHelp)
112 if (fHelp || params.size() > 1)
115 "List commands, or get help for a command.");
118 if (params.size() > 0)
119 strCommand = params[0].get_str();
122 set<rpcfn_type> setDone;
123 for (map<string, rpcfn_type>::iterator mi = mapCallTable.begin(); mi != mapCallTable.end(); ++mi)
125 string strMethod = (*mi).first;
126 // We already filter duplicates, but these deprecated screw up the sort order
127 if (strMethod == "getamountreceived" ||
128 strMethod == "getallreceived" ||
129 (strMethod.find("label") != string::npos))
131 if (strCommand != "" && strMethod != strCommand)
136 rpcfn_type pfn = (*mi).second;
137 if (setDone.insert(pfn).second)
138 (*pfn)(params, true);
140 catch (std::exception& e)
142 // Help text is returned in an exception
143 string strHelp = string(e.what());
144 if (strCommand == "")
145 if (strHelp.find('\n') != -1)
146 strHelp = strHelp.substr(0, strHelp.find('\n'));
147 strRet += strHelp + "\n";
151 strRet = strprintf("help: unknown command: %s\n", strCommand.c_str());
152 strRet = strRet.substr(0,strRet.size()-1);
157 Value stop(const Array& params, bool fHelp)
159 if (fHelp || params.size() != 0)
162 "Stop bitcoin server.");
164 // Shutdown will take long enough that the response should get back
165 CreateThread(Shutdown, NULL);
166 return "bitcoin server stopping";
168 throw runtime_error("NYI: cannot shut down GUI with RPC command");
173 Value getblockcount(const Array& params, bool fHelp)
175 if (fHelp || params.size() != 0)
178 "Returns the number of blocks in the longest block chain.");
184 Value getblocknumber(const Array& params, bool fHelp)
186 if (fHelp || params.size() != 0)
189 "Returns the block number of the latest block in the longest block chain.");
195 Value getconnectioncount(const Array& params, bool fHelp)
197 if (fHelp || params.size() != 0)
199 "getconnectioncount\n"
200 "Returns the number of connections to other nodes.");
202 return (int)vNodes.size();
206 double GetDifficulty()
208 // Floating point number that is a multiple of the minimum difficulty,
209 // minimum difficulty = 1.0.
211 if (pindexBest == NULL)
213 int nShift = (pindexBest->nBits >> 24) & 0xff;
216 (double)0x0000ffff / (double)(pindexBest->nBits & 0x00ffffff);
232 Value getdifficulty(const Array& params, bool fHelp)
234 if (fHelp || params.size() != 0)
237 "Returns the proof-of-work difficulty as a multiple of the minimum difficulty.");
239 return GetDifficulty();
243 Value getgenerate(const Array& params, bool fHelp)
245 if (fHelp || params.size() != 0)
248 "Returns true or false.");
250 return (bool)fGenerateBitcoins;
254 Value setgenerate(const Array& params, bool fHelp)
256 if (fHelp || params.size() < 1 || params.size() > 2)
258 "setgenerate <generate> [genproclimit]\n"
259 "<generate> is true or false to turn generation on or off.\n"
260 "Generation is limited to [genproclimit] processors, -1 is unlimited.");
262 bool fGenerate = true;
263 if (params.size() > 0)
264 fGenerate = params[0].get_bool();
266 if (params.size() > 1)
268 int nGenProcLimit = params[1].get_int();
269 fLimitProcessors = (nGenProcLimit != -1);
270 WriteSetting("fLimitProcessors", fLimitProcessors);
271 if (nGenProcLimit != -1)
272 WriteSetting("nLimitProcessors", nLimitProcessors = nGenProcLimit);
273 if (nGenProcLimit == 0)
277 GenerateBitcoins(fGenerate, pwalletMain);
282 Value gethashespersec(const Array& params, bool fHelp)
284 if (fHelp || params.size() != 0)
287 "Returns a recent hashes per second performance measurement while generating.");
289 if (GetTimeMillis() - nHPSTimerStart > 8000)
290 return (boost::int64_t)0;
291 return (boost::int64_t)dHashesPerSec;
295 Value getinfo(const Array& params, bool fHelp)
297 if (fHelp || params.size() != 0)
300 "Returns an object containing various state info.");
303 obj.push_back(Pair("version", (int)VERSION));
304 obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance())));
305 obj.push_back(Pair("blocks", (int)nBestHeight));
306 obj.push_back(Pair("connections", (int)vNodes.size()));
307 obj.push_back(Pair("proxy", (fUseProxy ? addrProxy.ToStringIPPort() : string())));
308 obj.push_back(Pair("generate", (bool)fGenerateBitcoins));
309 obj.push_back(Pair("genproclimit", (int)(fLimitProcessors ? nLimitProcessors : -1)));
310 obj.push_back(Pair("difficulty", (double)GetDifficulty()));
311 obj.push_back(Pair("hashespersec", gethashespersec(params, false)));
312 obj.push_back(Pair("testnet", fTestNet));
313 obj.push_back(Pair("keypoololdest", (boost::int64_t)pwalletMain->GetOldestKeyPoolTime()));
314 obj.push_back(Pair("keypoolsize", pwalletMain->GetKeyPoolSize()));
315 obj.push_back(Pair("paytxfee", ValueFromAmount(nTransactionFee)));
316 if (pwalletMain->IsCrypted())
317 obj.push_back(Pair("unlocked_until", (boost::int64_t)nWalletUnlockTime / 1000));
318 obj.push_back(Pair("errors", GetWarnings("statusbar")));
323 Value getnewaddress(const Array& params, bool fHelp)
325 if (fHelp || params.size() > 1)
327 "getnewaddress [account]\n"
328 "Returns a new bitcoin address for receiving payments. "
329 "If [account] is specified (recommended), it is added to the address book "
330 "so payments received with the address will be credited to [account].");
332 // Parse the account first so we don't generate a key if there's an error
334 if (params.size() > 0)
335 strAccount = AccountFromValue(params[0]);
337 if (!pwalletMain->IsLocked())
338 pwalletMain->TopUpKeyPool();
340 // Generate a new key that is added to wallet
341 std::vector<unsigned char> newKey;
342 if (!pwalletMain->GetKeyFromPool(newKey, false))
343 throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
344 CBitcoinAddress address(newKey);
346 pwalletMain->SetAddressBookName(address, strAccount);
348 return address.ToString();
352 CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false)
354 CWalletDB walletdb(pwalletMain->strWalletFile);
357 walletdb.ReadAccount(strAccount, account);
359 bool bKeyUsed = false;
361 // Check if the current key has been used
362 if (!account.vchPubKey.empty())
364 CScript scriptPubKey;
365 scriptPubKey.SetBitcoinAddress(account.vchPubKey);
366 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
367 it != pwalletMain->mapWallet.end() && !account.vchPubKey.empty();
370 const CWalletTx& wtx = (*it).second;
371 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
372 if (txout.scriptPubKey == scriptPubKey)
377 // Generate a new key
378 if (account.vchPubKey.empty() || bForceNew || bKeyUsed)
380 if (!pwalletMain->GetKeyFromPool(account.vchPubKey, false))
381 throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
383 pwalletMain->SetAddressBookName(CBitcoinAddress(account.vchPubKey), strAccount);
384 walletdb.WriteAccount(strAccount, account);
387 return CBitcoinAddress(account.vchPubKey);
390 Value getaccountaddress(const Array& params, bool fHelp)
392 if (fHelp || params.size() != 1)
394 "getaccountaddress <account>\n"
395 "Returns the current bitcoin address for receiving payments to this account.");
397 // Parse the account first so we don't generate a key if there's an error
398 string strAccount = AccountFromValue(params[0]);
402 ret = GetAccountAddress(strAccount).ToString();
409 Value setaccount(const Array& params, bool fHelp)
411 if (fHelp || params.size() < 1 || params.size() > 2)
413 "setaccount <bitcoinaddress> <account>\n"
414 "Sets the account associated with the given address.");
416 CBitcoinAddress address(params[0].get_str());
417 if (!address.IsValid())
418 throw JSONRPCError(-5, "Invalid bitcoin address");
422 if (params.size() > 1)
423 strAccount = AccountFromValue(params[1]);
425 // Detect when changing the account of an address that is the 'unused current key' of another account:
426 if (pwalletMain->mapAddressBook.count(address))
428 string strOldAccount = pwalletMain->mapAddressBook[address];
429 if (address == GetAccountAddress(strOldAccount))
430 GetAccountAddress(strOldAccount, true);
433 pwalletMain->SetAddressBookName(address, strAccount);
439 Value getaccount(const Array& params, bool fHelp)
441 if (fHelp || params.size() != 1)
443 "getaccount <bitcoinaddress>\n"
444 "Returns the account associated with the given address.");
446 CBitcoinAddress address(params[0].get_str());
447 if (!address.IsValid())
448 throw JSONRPCError(-5, "Invalid bitcoin address");
451 map<CBitcoinAddress, string>::iterator mi = pwalletMain->mapAddressBook.find(address);
452 if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.empty())
453 strAccount = (*mi).second;
458 Value getaddressesbyaccount(const Array& params, bool fHelp)
460 if (fHelp || params.size() != 1)
462 "getaddressesbyaccount <account>\n"
463 "Returns the list of addresses for the given account.");
465 string strAccount = AccountFromValue(params[0]);
467 // Find all addresses that have the given account
469 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
471 const CBitcoinAddress& address = item.first;
472 const string& strName = item.second;
473 if (strName == strAccount)
474 ret.push_back(address.ToString());
479 Value settxfee(const Array& params, bool fHelp)
481 if (fHelp || params.size() < 1 || params.size() > 1)
483 "settxfee <amount>\n"
484 "<amount> is a real and is rounded to the nearest 0.00000001");
488 if (params[0].get_real() != 0.0)
489 nAmount = AmountFromValue(params[0]); // rejects 0.0 amounts
491 nTransactionFee = nAmount;
495 Value sendtoaddress(const Array& params, bool fHelp)
497 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
499 "sendtoaddress <bitcoinaddress> <amount> [comment] [comment-to]\n"
500 "<amount> is a real and is rounded to the nearest 0.00000001\n"
501 "requires wallet passphrase to be set with walletpassphrase first");
502 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
504 "sendtoaddress <bitcoinaddress> <amount> [comment] [comment-to]\n"
505 "<amount> is a real and is rounded to the nearest 0.00000001");
507 CBitcoinAddress address(params[0].get_str());
508 if (!address.IsValid())
509 throw JSONRPCError(-5, "Invalid bitcoin address");
512 int64 nAmount = AmountFromValue(params[1]);
516 if (params.size() > 2 && params[2].type() != null_type && !params[2].get_str().empty())
517 wtx.mapValue["comment"] = params[2].get_str();
518 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
519 wtx.mapValue["to"] = params[3].get_str();
521 if (pwalletMain->IsLocked())
522 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
524 string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
526 throw JSONRPCError(-4, strError);
528 return wtx.GetHash().GetHex();
531 static const string strMessageMagic = "Bitcoin Signed Message:\n";
533 Value signmessage(const Array& params, bool fHelp)
535 if (fHelp || params.size() != 2)
537 "signmessage <bitcoinaddress> <message>\n"
538 "Sign a message with the private key of an address");
540 if (pwalletMain->IsLocked())
541 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
543 string strAddress = params[0].get_str();
544 string strMessage = params[1].get_str();
546 CBitcoinAddress addr(strAddress);
548 throw JSONRPCError(-3, "Invalid address");
551 if (!pwalletMain->GetKey(addr, key))
552 throw JSONRPCError(-4, "Private key not available");
554 CDataStream ss(SER_GETHASH);
555 ss << strMessageMagic;
558 vector<unsigned char> vchSig;
559 if (!key.SignCompact(Hash(ss.begin(), ss.end()), vchSig))
560 throw JSONRPCError(-5, "Sign failed");
562 return EncodeBase64(&vchSig[0], vchSig.size());
565 Value verifymessage(const Array& params, bool fHelp)
567 if (fHelp || params.size() != 3)
569 "verifymessage <bitcoinaddress> <signature> <message>\n"
570 "Verify a signed message");
572 string strAddress = params[0].get_str();
573 string strSign = params[1].get_str();
574 string strMessage = params[2].get_str();
576 CBitcoinAddress addr(strAddress);
578 throw JSONRPCError(-3, "Invalid address");
580 bool fInvalid = false;
581 vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid);
584 throw JSONRPCError(-5, "Malformed base64 encoding");
586 CDataStream ss(SER_GETHASH);
587 ss << strMessageMagic;
591 if (!key.SetCompactSignature(Hash(ss.begin(), ss.end()), vchSig))
594 return (key.GetAddress() == addr);
598 Value getreceivedbyaddress(const Array& params, bool fHelp)
600 if (fHelp || params.size() < 1 || params.size() > 2)
602 "getreceivedbyaddress <bitcoinaddress> [minconf=1]\n"
603 "Returns the total amount received by <bitcoinaddress> in transactions with at least [minconf] confirmations.");
606 CBitcoinAddress address = CBitcoinAddress(params[0].get_str());
607 CScript scriptPubKey;
608 if (!address.IsValid())
609 throw JSONRPCError(-5, "Invalid bitcoin address");
610 scriptPubKey.SetBitcoinAddress(address);
611 if (!IsMine(*pwalletMain,scriptPubKey))
614 // Minimum confirmations
616 if (params.size() > 1)
617 nMinDepth = params[1].get_int();
621 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
623 const CWalletTx& wtx = (*it).second;
624 if (wtx.IsCoinBase() || !wtx.IsFinal())
627 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
628 if (txout.scriptPubKey == scriptPubKey)
629 if (wtx.GetDepthInMainChain() >= nMinDepth)
630 nAmount += txout.nValue;
633 return ValueFromAmount(nAmount);
637 void GetAccountAddresses(string strAccount, set<CBitcoinAddress>& setAddress)
639 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
641 const CBitcoinAddress& address = item.first;
642 const string& strName = item.second;
643 if (strName == strAccount)
644 setAddress.insert(address);
649 Value getreceivedbyaccount(const Array& params, bool fHelp)
651 if (fHelp || params.size() < 1 || params.size() > 2)
653 "getreceivedbyaccount <account> [minconf=1]\n"
654 "Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.");
656 // Minimum confirmations
658 if (params.size() > 1)
659 nMinDepth = params[1].get_int();
661 // Get the set of pub keys that have the label
662 string strAccount = AccountFromValue(params[0]);
663 set<CBitcoinAddress> setAddress;
664 GetAccountAddresses(strAccount, setAddress);
668 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
670 const CWalletTx& wtx = (*it).second;
671 if (wtx.IsCoinBase() || !wtx.IsFinal())
674 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
676 CBitcoinAddress address;
677 if (ExtractAddress(txout.scriptPubKey, pwalletMain, address) && setAddress.count(address))
678 if (wtx.GetDepthInMainChain() >= nMinDepth)
679 nAmount += txout.nValue;
683 return (double)nAmount / (double)COIN;
687 int64 GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth)
691 // Tally wallet transactions
692 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
694 const CWalletTx& wtx = (*it).second;
698 int64 nGenerated, nReceived, nSent, nFee;
699 wtx.GetAccountAmounts(strAccount, nGenerated, nReceived, nSent, nFee);
701 if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
702 nBalance += nReceived;
703 nBalance += nGenerated - nSent - nFee;
706 // Tally internal accounting entries
707 nBalance += walletdb.GetAccountCreditDebit(strAccount);
712 int64 GetAccountBalance(const string& strAccount, int nMinDepth)
714 CWalletDB walletdb(pwalletMain->strWalletFile);
715 return GetAccountBalance(walletdb, strAccount, nMinDepth);
719 Value getbalance(const Array& params, bool fHelp)
721 if (fHelp || params.size() > 2)
723 "getbalance [account] [minconf=1]\n"
724 "If [account] is not specified, returns the server's total available balance.\n"
725 "If [account] is specified, returns the balance in the account.");
727 if (params.size() == 0)
728 return ValueFromAmount(pwalletMain->GetBalance());
731 if (params.size() > 1)
732 nMinDepth = params[1].get_int();
734 if (params[0].get_str() == "*") {
735 // Calculate total balance a different way from GetBalance()
736 // (GetBalance() sums up all unspent TxOuts)
737 // getbalance and getbalance '*' should always return the same number.
739 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
741 const CWalletTx& wtx = (*it).second;
745 int64 allGeneratedImmature, allGeneratedMature, allFee;
746 allGeneratedImmature = allGeneratedMature = allFee = 0;
747 string strSentAccount;
748 list<pair<CBitcoinAddress, int64> > listReceived;
749 list<pair<CBitcoinAddress, int64> > listSent;
750 wtx.GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount);
751 if (wtx.GetDepthInMainChain() >= nMinDepth)
753 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listReceived)
754 nBalance += r.second;
756 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listSent)
757 nBalance -= r.second;
759 nBalance += allGeneratedMature;
761 return ValueFromAmount(nBalance);
764 string strAccount = AccountFromValue(params[0]);
766 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
768 return ValueFromAmount(nBalance);
772 Value movecmd(const Array& params, bool fHelp)
774 if (fHelp || params.size() < 3 || params.size() > 5)
776 "move <fromaccount> <toaccount> <amount> [minconf=1] [comment]\n"
777 "Move from one account in your wallet to another.");
779 string strFrom = AccountFromValue(params[0]);
780 string strTo = AccountFromValue(params[1]);
781 int64 nAmount = AmountFromValue(params[2]);
782 if (params.size() > 3)
783 // unused parameter, used to be nMinDepth, keep type-checking it though
784 (void)params[3].get_int();
786 if (params.size() > 4)
787 strComment = params[4].get_str();
789 CWalletDB walletdb(pwalletMain->strWalletFile);
792 int64 nNow = GetAdjustedTime();
795 CAccountingEntry debit;
796 debit.strAccount = strFrom;
797 debit.nCreditDebit = -nAmount;
799 debit.strOtherAccount = strTo;
800 debit.strComment = strComment;
801 walletdb.WriteAccountingEntry(debit);
804 CAccountingEntry credit;
805 credit.strAccount = strTo;
806 credit.nCreditDebit = nAmount;
808 credit.strOtherAccount = strFrom;
809 credit.strComment = strComment;
810 walletdb.WriteAccountingEntry(credit);
812 walletdb.TxnCommit();
818 Value sendfrom(const Array& params, bool fHelp)
820 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
822 "sendfrom <fromaccount> <tobitcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
823 "<amount> is a real and is rounded to the nearest 0.00000001\n"
824 "requires wallet passphrase to be set with walletpassphrase first");
825 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
827 "sendfrom <fromaccount> <tobitcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
828 "<amount> is a real and is rounded to the nearest 0.00000001");
830 string strAccount = AccountFromValue(params[0]);
831 CBitcoinAddress address(params[1].get_str());
832 if (!address.IsValid())
833 throw JSONRPCError(-5, "Invalid bitcoin address");
834 int64 nAmount = AmountFromValue(params[2]);
836 if (params.size() > 3)
837 nMinDepth = params[3].get_int();
840 wtx.strFromAccount = strAccount;
841 if (params.size() > 4 && params[4].type() != null_type && !params[4].get_str().empty())
842 wtx.mapValue["comment"] = params[4].get_str();
843 if (params.size() > 5 && params[5].type() != null_type && !params[5].get_str().empty())
844 wtx.mapValue["to"] = params[5].get_str();
846 if (pwalletMain->IsLocked())
847 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
850 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
851 if (nAmount > nBalance)
852 throw JSONRPCError(-6, "Account has insufficient funds");
855 string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
857 throw JSONRPCError(-4, strError);
859 return wtx.GetHash().GetHex();
863 Value sendmany(const Array& params, bool fHelp)
865 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
867 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
868 "amounts are double-precision floating point numbers\n"
869 "requires wallet passphrase to be set with walletpassphrase first");
870 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
872 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
873 "amounts are double-precision floating point numbers");
875 string strAccount = AccountFromValue(params[0]);
876 Object sendTo = params[1].get_obj();
878 if (params.size() > 2)
879 nMinDepth = params[2].get_int();
882 wtx.strFromAccount = strAccount;
883 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
884 wtx.mapValue["comment"] = params[3].get_str();
886 set<CBitcoinAddress> setAddress;
887 vector<pair<CScript, int64> > vecSend;
889 int64 totalAmount = 0;
890 BOOST_FOREACH(const Pair& s, sendTo)
892 CBitcoinAddress address(s.name_);
893 if (!address.IsValid())
894 throw JSONRPCError(-5, string("Invalid bitcoin address:")+s.name_);
896 if (setAddress.count(address))
897 throw JSONRPCError(-8, string("Invalid parameter, duplicated address: ")+s.name_);
898 setAddress.insert(address);
900 CScript scriptPubKey;
901 scriptPubKey.SetBitcoinAddress(address);
902 int64 nAmount = AmountFromValue(s.value_);
903 totalAmount += nAmount;
905 vecSend.push_back(make_pair(scriptPubKey, nAmount));
908 if (pwalletMain->IsLocked())
909 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
912 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
913 if (totalAmount > nBalance)
914 throw JSONRPCError(-6, "Account has insufficient funds");
917 CReserveKey keyChange(pwalletMain);
918 int64 nFeeRequired = 0;
919 bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired);
922 if (totalAmount + nFeeRequired > pwalletMain->GetBalance())
923 throw JSONRPCError(-6, "Insufficient funds");
924 throw JSONRPCError(-4, "Transaction creation failed");
926 if (!pwalletMain->CommitTransaction(wtx, keyChange))
927 throw JSONRPCError(-4, "Transaction commit failed");
929 return wtx.GetHash().GetHex();
944 Value ListReceived(const Array& params, bool fByAccounts)
946 // Minimum confirmations
948 if (params.size() > 0)
949 nMinDepth = params[0].get_int();
951 // Whether to include empty accounts
952 bool fIncludeEmpty = false;
953 if (params.size() > 1)
954 fIncludeEmpty = params[1].get_bool();
957 map<CBitcoinAddress, tallyitem> mapTally;
958 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
960 const CWalletTx& wtx = (*it).second;
961 if (wtx.IsCoinBase() || !wtx.IsFinal())
964 int nDepth = wtx.GetDepthInMainChain();
965 if (nDepth < nMinDepth)
968 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
970 CBitcoinAddress address;
971 if (!ExtractAddress(txout.scriptPubKey, pwalletMain, address) || !address.IsValid())
974 tallyitem& item = mapTally[address];
975 item.nAmount += txout.nValue;
976 item.nConf = min(item.nConf, nDepth);
982 map<string, tallyitem> mapAccountTally;
983 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
985 const CBitcoinAddress& address = item.first;
986 const string& strAccount = item.second;
987 map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
988 if (it == mapTally.end() && !fIncludeEmpty)
993 if (it != mapTally.end())
995 nAmount = (*it).second.nAmount;
996 nConf = (*it).second.nConf;
1001 tallyitem& item = mapAccountTally[strAccount];
1002 item.nAmount += nAmount;
1003 item.nConf = min(item.nConf, nConf);
1008 obj.push_back(Pair("address", address.ToString()));
1009 obj.push_back(Pair("account", strAccount));
1010 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1011 obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf)));
1018 for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
1020 int64 nAmount = (*it).second.nAmount;
1021 int nConf = (*it).second.nConf;
1023 obj.push_back(Pair("account", (*it).first));
1024 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1025 obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf)));
1033 Value listreceivedbyaddress(const Array& params, bool fHelp)
1035 if (fHelp || params.size() > 2)
1036 throw runtime_error(
1037 "listreceivedbyaddress [minconf=1] [includeempty=false]\n"
1038 "[minconf] is the minimum number of confirmations before payments are included.\n"
1039 "[includeempty] whether to include addresses that haven't received any payments.\n"
1040 "Returns an array of objects containing:\n"
1041 " \"address\" : receiving address\n"
1042 " \"account\" : the account of the receiving address\n"
1043 " \"amount\" : total amount received by the address\n"
1044 " \"confirmations\" : number of confirmations of the most recent transaction included");
1046 return ListReceived(params, false);
1049 Value listreceivedbyaccount(const Array& params, bool fHelp)
1051 if (fHelp || params.size() > 2)
1052 throw runtime_error(
1053 "listreceivedbyaccount [minconf=1] [includeempty=false]\n"
1054 "[minconf] is the minimum number of confirmations before payments are included.\n"
1055 "[includeempty] whether to include accounts that haven't received any payments.\n"
1056 "Returns an array of objects containing:\n"
1057 " \"account\" : the account of the receiving addresses\n"
1058 " \"amount\" : total amount received by addresses with this account\n"
1059 " \"confirmations\" : number of confirmations of the most recent transaction included");
1061 return ListReceived(params, true);
1064 void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret)
1066 int64 nGeneratedImmature, nGeneratedMature, nFee;
1067 string strSentAccount;
1068 list<pair<CBitcoinAddress, int64> > listReceived;
1069 list<pair<CBitcoinAddress, int64> > listSent;
1070 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1072 bool fAllAccounts = (strAccount == string("*"));
1074 // Generated blocks assigned to account ""
1075 if ((nGeneratedMature+nGeneratedImmature) != 0 && (fAllAccounts || strAccount == ""))
1078 entry.push_back(Pair("account", string("")));
1079 if (nGeneratedImmature)
1081 entry.push_back(Pair("category", wtx.GetDepthInMainChain() ? "immature" : "orphan"));
1082 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedImmature)));
1086 entry.push_back(Pair("category", "generate"));
1087 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedMature)));
1090 WalletTxToJSON(wtx, entry);
1091 ret.push_back(entry);
1095 if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
1097 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1100 entry.push_back(Pair("account", strSentAccount));
1101 entry.push_back(Pair("address", s.first.ToString()));
1102 entry.push_back(Pair("category", "send"));
1103 entry.push_back(Pair("amount", ValueFromAmount(-s.second)));
1104 entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
1106 WalletTxToJSON(wtx, entry);
1107 ret.push_back(entry);
1112 if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
1114 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1117 if (pwalletMain->mapAddressBook.count(r.first))
1118 account = pwalletMain->mapAddressBook[r.first];
1119 if (fAllAccounts || (account == strAccount))
1122 entry.push_back(Pair("account", account));
1123 entry.push_back(Pair("address", r.first.ToString()));
1124 entry.push_back(Pair("category", "receive"));
1125 entry.push_back(Pair("amount", ValueFromAmount(r.second)));
1127 WalletTxToJSON(wtx, entry);
1128 ret.push_back(entry);
1134 void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret)
1136 bool fAllAccounts = (strAccount == string("*"));
1138 if (fAllAccounts || acentry.strAccount == strAccount)
1141 entry.push_back(Pair("account", acentry.strAccount));
1142 entry.push_back(Pair("category", "move"));
1143 entry.push_back(Pair("time", (boost::int64_t)acentry.nTime));
1144 entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
1145 entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
1146 entry.push_back(Pair("comment", acentry.strComment));
1147 ret.push_back(entry);
1151 Value listtransactions(const Array& params, bool fHelp)
1153 if (fHelp || params.size() > 3)
1154 throw runtime_error(
1155 "listtransactions [account] [count=10] [from=0]\n"
1156 "Returns up to [count] most recent transactions skipping the first [from] transactions for account [account].");
1158 string strAccount = "*";
1159 if (params.size() > 0)
1160 strAccount = params[0].get_str();
1162 if (params.size() > 1)
1163 nCount = params[1].get_int();
1165 if (params.size() > 2)
1166 nFrom = params[2].get_int();
1169 throw JSONRPCError(-8, "Negative count");
1171 throw JSONRPCError(-8, "Negative from");
1174 CWalletDB walletdb(pwalletMain->strWalletFile);
1176 // First: get all CWalletTx and CAccountingEntry into a sorted-by-time multimap.
1177 typedef pair<CWalletTx*, CAccountingEntry*> TxPair;
1178 typedef multimap<int64, TxPair > TxItems;
1181 // Note: maintaining indices in the database of (account,time) --> txid and (account, time) --> acentry
1182 // would make this much faster for applications that do this a lot.
1183 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1185 CWalletTx* wtx = &((*it).second);
1186 txByTime.insert(make_pair(wtx->GetTxTime(), TxPair(wtx, (CAccountingEntry*)0)));
1188 list<CAccountingEntry> acentries;
1189 walletdb.ListAccountCreditDebit(strAccount, acentries);
1190 BOOST_FOREACH(CAccountingEntry& entry, acentries)
1192 txByTime.insert(make_pair(entry.nTime, TxPair((CWalletTx*)0, &entry)));
1195 // iterate backwards until we have nCount items to return:
1196 for (TxItems::reverse_iterator it = txByTime.rbegin(); it != txByTime.rend(); ++it)
1198 CWalletTx *const pwtx = (*it).second.first;
1200 ListTransactions(*pwtx, strAccount, 0, true, ret);
1201 CAccountingEntry *const pacentry = (*it).second.second;
1203 AcentryToJSON(*pacentry, strAccount, ret);
1205 if (ret.size() >= (nCount+nFrom)) break;
1207 // ret is newest to oldest
1209 if (nFrom > ret.size()) nFrom = ret.size();
1210 if (nFrom+nCount > ret.size()) nCount = ret.size()-nFrom;
1211 Array::iterator first = ret.begin();
1212 std::advance(first, nFrom);
1213 Array::iterator last = ret.begin();
1214 std::advance(last, nFrom+nCount);
1216 if (last != ret.end()) ret.erase(last, ret.end());
1217 if (first != ret.begin()) ret.erase(ret.begin(), first);
1219 std::reverse(ret.begin(), ret.end()); // Return oldest to newest
1224 Value listaccounts(const Array& params, bool fHelp)
1226 if (fHelp || params.size() > 1)
1227 throw runtime_error(
1228 "listaccounts [minconf=1]\n"
1229 "Returns Object that has account names as keys, account balances as values.");
1232 if (params.size() > 0)
1233 nMinDepth = params[0].get_int();
1235 map<string, int64> mapAccountBalances;
1236 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& entry, pwalletMain->mapAddressBook) {
1237 if (pwalletMain->HaveKey(entry.first)) // This address belongs to me
1238 mapAccountBalances[entry.second] = 0;
1241 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1243 const CWalletTx& wtx = (*it).second;
1244 int64 nGeneratedImmature, nGeneratedMature, nFee;
1245 string strSentAccount;
1246 list<pair<CBitcoinAddress, int64> > listReceived;
1247 list<pair<CBitcoinAddress, int64> > listSent;
1248 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1249 mapAccountBalances[strSentAccount] -= nFee;
1250 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1251 mapAccountBalances[strSentAccount] -= s.second;
1252 if (wtx.GetDepthInMainChain() >= nMinDepth)
1254 mapAccountBalances[""] += nGeneratedMature;
1255 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1256 if (pwalletMain->mapAddressBook.count(r.first))
1257 mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second;
1259 mapAccountBalances[""] += r.second;
1263 list<CAccountingEntry> acentries;
1264 CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
1265 BOOST_FOREACH(const CAccountingEntry& entry, acentries)
1266 mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
1269 BOOST_FOREACH(const PAIRTYPE(string, int64)& accountBalance, mapAccountBalances) {
1270 ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
1275 Value listsinceblock(const Array& params, bool fHelp)
1278 throw runtime_error(
1279 "listsinceblock [blockid] [target-confirmations]\n"
1280 "Get all transactions in blocks since block [blockid], or all transactions if omitted");
1282 CBlockIndex *pindex = NULL;
1283 int target_confirms = 1;
1285 if (params.size() > 0)
1287 uint256 blockId = 0;
1289 blockId.SetHex(params[0].get_str());
1290 pindex = CBlockLocator(blockId).GetBlockIndex();
1293 if (params.size() > 1)
1295 target_confirms = params[1].get_int();
1297 if (target_confirms < 1)
1298 throw JSONRPCError(-8, "Invalid parameter");
1301 int depth = pindex ? (1 + nBestHeight - pindex->nHeight) : -1;
1305 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++)
1307 CWalletTx tx = (*it).second;
1309 if (depth == -1 || tx.GetDepthInMainChain() < depth)
1310 ListTransactions(tx, "*", 0, true, transactions);
1315 if (target_confirms == 1)
1318 lastblock = hashBestChain;
1322 int target_height = pindexBest->nHeight + 1 - target_confirms;
1325 for (block = pindexBest;
1326 block && block->nHeight > target_height;
1327 block = block->pprev) { }
1329 lastblock = block ? block->GetBlockHash() : 0;
1333 ret.push_back(Pair("transactions", transactions));
1334 ret.push_back(Pair("lastblock", lastblock.GetHex()));
1339 Value gettransaction(const Array& params, bool fHelp)
1341 if (fHelp || params.size() != 1)
1342 throw runtime_error(
1343 "gettransaction <txid>\n"
1344 "Get detailed information about <txid>");
1347 hash.SetHex(params[0].get_str());
1351 if (!pwalletMain->mapWallet.count(hash))
1352 throw JSONRPCError(-5, "Invalid or non-wallet transaction id");
1353 const CWalletTx& wtx = pwalletMain->mapWallet[hash];
1355 int64 nCredit = wtx.GetCredit();
1356 int64 nDebit = wtx.GetDebit();
1357 int64 nNet = nCredit - nDebit;
1358 int64 nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0);
1360 entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
1362 entry.push_back(Pair("fee", ValueFromAmount(nFee)));
1364 WalletTxToJSON(pwalletMain->mapWallet[hash], entry);
1367 ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details);
1368 entry.push_back(Pair("details", details));
1374 Value backupwallet(const Array& params, bool fHelp)
1376 if (fHelp || params.size() != 1)
1377 throw runtime_error(
1378 "backupwallet <destination>\n"
1379 "Safely copies wallet.dat to destination, which can be a directory or a path with filename.");
1381 string strDest = params[0].get_str();
1382 BackupWallet(*pwalletMain, strDest);
1388 Value keypoolrefill(const Array& params, bool fHelp)
1390 if (pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1391 throw runtime_error(
1393 "Fills the keypool, requires wallet passphrase to be set.");
1394 if (!pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1395 throw runtime_error(
1397 "Fills the keypool.");
1399 if (pwalletMain->IsLocked())
1400 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
1402 pwalletMain->TopUpKeyPool();
1404 if (pwalletMain->GetKeyPoolSize() < GetArg("-keypool", 100))
1405 throw JSONRPCError(-4, "Error refreshing keypool.");
1411 void ThreadTopUpKeyPool(void* parg)
1413 pwalletMain->TopUpKeyPool();
1416 void ThreadCleanWalletPassphrase(void* parg)
1418 int64 nMyWakeTime = GetTimeMillis() + *((int64*)parg) * 1000;
1420 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1422 if (nWalletUnlockTime == 0)
1424 nWalletUnlockTime = nMyWakeTime;
1428 if (nWalletUnlockTime==0)
1430 int64 nToSleep = nWalletUnlockTime - GetTimeMillis();
1434 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1436 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1440 if (nWalletUnlockTime)
1442 nWalletUnlockTime = 0;
1443 pwalletMain->Lock();
1448 if (nWalletUnlockTime < nMyWakeTime)
1449 nWalletUnlockTime = nMyWakeTime;
1452 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1454 delete (int64*)parg;
1457 Value walletpassphrase(const Array& params, bool fHelp)
1459 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1460 throw runtime_error(
1461 "walletpassphrase <passphrase> <timeout>\n"
1462 "Stores the wallet decryption key in memory for <timeout> seconds.");
1465 if (!pwalletMain->IsCrypted())
1466 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
1468 if (!pwalletMain->IsLocked())
1469 throw JSONRPCError(-17, "Error: Wallet is already unlocked.");
1471 // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
1472 SecureString strWalletPass;
1473 strWalletPass.reserve(100);
1474 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1475 // Alternately, find a way to make params[0] mlock()'d to begin with.
1476 strWalletPass = params[0].get_str().c_str();
1478 if (strWalletPass.length() > 0)
1480 if (!pwalletMain->Unlock(strWalletPass))
1481 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1484 throw runtime_error(
1485 "walletpassphrase <passphrase> <timeout>\n"
1486 "Stores the wallet decryption key in memory for <timeout> seconds.");
1488 CreateThread(ThreadTopUpKeyPool, NULL);
1489 int64* pnSleepTime = new int64(params[1].get_int64());
1490 CreateThread(ThreadCleanWalletPassphrase, pnSleepTime);
1496 Value walletpassphrasechange(const Array& params, bool fHelp)
1498 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1499 throw runtime_error(
1500 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1501 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1504 if (!pwalletMain->IsCrypted())
1505 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
1507 // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
1508 // Alternately, find a way to make params[0] mlock()'d to begin with.
1509 SecureString strOldWalletPass;
1510 strOldWalletPass.reserve(100);
1511 strOldWalletPass = params[0].get_str().c_str();
1513 SecureString strNewWalletPass;
1514 strNewWalletPass.reserve(100);
1515 strNewWalletPass = params[1].get_str().c_str();
1517 if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
1518 throw runtime_error(
1519 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1520 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1522 if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
1523 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1529 Value walletlock(const Array& params, bool fHelp)
1531 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
1532 throw runtime_error(
1534 "Removes the wallet encryption key from memory, locking the wallet.\n"
1535 "After calling this method, you will need to call walletpassphrase again\n"
1536 "before being able to call any methods which require the wallet to be unlocked.");
1539 if (!pwalletMain->IsCrypted())
1540 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletlock was called.");
1542 CRITICAL_BLOCK(cs_nWalletUnlockTime)
1544 pwalletMain->Lock();
1545 nWalletUnlockTime = 0;
1552 Value encryptwallet(const Array& params, bool fHelp)
1554 if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
1555 throw runtime_error(
1556 "encryptwallet <passphrase>\n"
1557 "Encrypts the wallet with <passphrase>.");
1560 if (pwalletMain->IsCrypted())
1561 throw JSONRPCError(-15, "Error: running with an encrypted wallet, but encryptwallet was called.");
1564 // shutting down via RPC while the GUI is running does not work (yet):
1565 throw runtime_error("Not Yet Implemented: use GUI to encrypt wallet, not RPC command");
1568 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1569 // Alternately, find a way to make params[0] mlock()'d to begin with.
1570 SecureString strWalletPass;
1571 strWalletPass.reserve(100);
1572 strWalletPass = params[0].get_str().c_str();
1574 if (strWalletPass.length() < 1)
1575 throw runtime_error(
1576 "encryptwallet <passphrase>\n"
1577 "Encrypts the wallet with <passphrase>.");
1579 if (!pwalletMain->EncryptWallet(strWalletPass))
1580 throw JSONRPCError(-16, "Error: Failed to encrypt the wallet.");
1582 // BDB seems to have a bad habit of writing old data into
1583 // slack space in .dat files; that is bad if the old data is
1584 // unencrypted private keys. So:
1585 CreateThread(Shutdown, NULL);
1586 return "wallet encrypted; bitcoin server stopping, restart to run with encrypted wallet";
1590 Value validateaddress(const Array& params, bool fHelp)
1592 if (fHelp || params.size() != 1)
1593 throw runtime_error(
1594 "validateaddress <bitcoinaddress>\n"
1595 "Return information about <bitcoinaddress>.");
1597 CBitcoinAddress address(params[0].get_str());
1598 bool isValid = address.IsValid();
1601 ret.push_back(Pair("isvalid", isValid));
1604 // Call Hash160ToAddress() so we always return current ADDRESSVERSION
1605 // version of the address:
1606 string currentAddress = address.ToString();
1607 ret.push_back(Pair("address", currentAddress));
1608 ret.push_back(Pair("ismine", (pwalletMain->HaveKey(address) > 0)));
1609 if (pwalletMain->mapAddressBook.count(address))
1610 ret.push_back(Pair("account", pwalletMain->mapAddressBook[address]));
1616 Value getwork(const Array& params, bool fHelp)
1618 if (fHelp || params.size() > 1)
1619 throw runtime_error(
1621 "If [data] is not specified, returns formatted hash data to work on:\n"
1622 " \"midstate\" : precomputed hash state after hashing the first half of the data (DEPRECATED)\n" // deprecated
1623 " \"data\" : block data\n"
1624 " \"hash1\" : formatted hash buffer for second hash (DEPRECATED)\n" // deprecated
1625 " \"target\" : little endian hash target\n"
1626 "If [data] is specified, tries to solve the block and returns true if it was successful.");
1629 throw JSONRPCError(-9, "Bitcoin is not connected!");
1631 if (IsInitialBlockDownload())
1632 throw JSONRPCError(-10, "Bitcoin is downloading blocks...");
1634 typedef map<uint256, pair<CBlock*, CScript> > mapNewBlock_t;
1635 static mapNewBlock_t mapNewBlock;
1636 static vector<CBlock*> vNewBlock;
1637 static CReserveKey reservekey(pwalletMain);
1639 if (params.size() == 0)
1642 static unsigned int nTransactionsUpdatedLast;
1643 static CBlockIndex* pindexPrev;
1644 static int64 nStart;
1645 static CBlock* pblock;
1646 if (pindexPrev != pindexBest ||
1647 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60))
1649 if (pindexPrev != pindexBest)
1651 // Deallocate old blocks since they're obsolete now
1652 mapNewBlock.clear();
1653 BOOST_FOREACH(CBlock* pblock, vNewBlock)
1657 nTransactionsUpdatedLast = nTransactionsUpdated;
1658 pindexPrev = pindexBest;
1662 pblock = CreateNewBlock(reservekey);
1664 throw JSONRPCError(-7, "Out of memory");
1665 vNewBlock.push_back(pblock);
1669 pblock->UpdateTime(pindexPrev);
1672 // Update nExtraNonce
1673 static unsigned int nExtraNonce = 0;
1674 IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
1677 mapNewBlock[pblock->hashMerkleRoot] = make_pair(pblock, pblock->vtx[0].vin[0].scriptSig);
1679 // Prebuild hash buffers
1683 FormatHashBuffers(pblock, pmidstate, pdata, phash1);
1685 uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
1688 result.push_back(Pair("midstate", HexStr(BEGIN(pmidstate), END(pmidstate)))); // deprecated
1689 result.push_back(Pair("data", HexStr(BEGIN(pdata), END(pdata))));
1690 result.push_back(Pair("hash1", HexStr(BEGIN(phash1), END(phash1)))); // deprecated
1691 result.push_back(Pair("target", HexStr(BEGIN(hashTarget), END(hashTarget))));
1697 vector<unsigned char> vchData = ParseHex(params[0].get_str());
1698 if (vchData.size() != 128)
1699 throw JSONRPCError(-8, "Invalid parameter");
1700 CBlock* pdata = (CBlock*)&vchData[0];
1703 for (int i = 0; i < 128/4; i++)
1704 ((unsigned int*)pdata)[i] = ByteReverse(((unsigned int*)pdata)[i]);
1707 if (!mapNewBlock.count(pdata->hashMerkleRoot))
1709 CBlock* pblock = mapNewBlock[pdata->hashMerkleRoot].first;
1711 pblock->nTime = pdata->nTime;
1712 pblock->nNonce = pdata->nNonce;
1713 pblock->vtx[0].vin[0].scriptSig = mapNewBlock[pdata->hashMerkleRoot].second;
1714 pblock->hashMerkleRoot = pblock->BuildMerkleTree();
1716 return CheckWork(pblock, *pwalletMain, reservekey);
1721 Value getmemorypool(const Array& params, bool fHelp)
1723 if (fHelp || params.size() > 1)
1724 throw runtime_error(
1725 "getmemorypool [data]\n"
1726 "If [data] is not specified, returns data needed to construct a block to work on:\n"
1727 " \"version\" : block version\n"
1728 " \"previousblockhash\" : hash of current highest block\n"
1729 " \"transactions\" : contents of non-coinbase transactions that should be included in the next block\n"
1730 " \"coinbasevalue\" : maximum allowable input to coinbase transaction, including the generation award and transaction fees\n"
1731 " \"time\" : timestamp appropriate for next block\n"
1732 " \"bits\" : compressed target of next block\n"
1733 "If [data] is specified, tries to solve the block and returns true if it was successful.");
1735 if (params.size() == 0)
1738 throw JSONRPCError(-9, "Bitcoin is not connected!");
1740 if (IsInitialBlockDownload())
1741 throw JSONRPCError(-10, "Bitcoin is downloading blocks...");
1743 static CReserveKey reservekey(pwalletMain);
1746 static unsigned int nTransactionsUpdatedLast;
1747 static CBlockIndex* pindexPrev;
1748 static int64 nStart;
1749 static CBlock* pblock;
1750 if (pindexPrev != pindexBest ||
1751 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 5))
1753 nTransactionsUpdatedLast = nTransactionsUpdated;
1754 pindexPrev = pindexBest;
1760 pblock = CreateNewBlock(reservekey);
1762 throw JSONRPCError(-7, "Out of memory");
1766 pblock->UpdateTime(pindexPrev);
1770 BOOST_FOREACH(CTransaction tx, pblock->vtx) {
1777 transactions.push_back(HexStr(ssTx.begin(), ssTx.end()));
1781 result.push_back(Pair("version", pblock->nVersion));
1782 result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex()));
1783 result.push_back(Pair("transactions", transactions));
1784 result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue));
1785 result.push_back(Pair("time", (int64_t)pblock->nTime));
1791 uBits.nBits = htonl((int32_t)pblock->nBits);
1792 result.push_back(Pair("bits", HexStr(BEGIN(uBits.cBits), END(uBits.cBits))));
1799 CDataStream ssBlock(ParseHex(params[0].get_str()));
1803 return ProcessBlock(NULL, &pblock);
1821 pair<string, rpcfn_type> pCallTable[] =
1823 make_pair("help", &help),
1824 make_pair("stop", &stop),
1825 make_pair("getblockcount", &getblockcount),
1826 make_pair("getblocknumber", &getblocknumber),
1827 make_pair("getconnectioncount", &getconnectioncount),
1828 make_pair("getdifficulty", &getdifficulty),
1829 make_pair("getgenerate", &getgenerate),
1830 make_pair("setgenerate", &setgenerate),
1831 make_pair("gethashespersec", &gethashespersec),
1832 make_pair("getinfo", &getinfo),
1833 make_pair("getnewaddress", &getnewaddress),
1834 make_pair("getaccountaddress", &getaccountaddress),
1835 make_pair("setaccount", &setaccount),
1836 make_pair("getaccount", &getaccount),
1837 make_pair("getaddressesbyaccount", &getaddressesbyaccount),
1838 make_pair("sendtoaddress", &sendtoaddress),
1839 make_pair("getreceivedbyaddress", &getreceivedbyaddress),
1840 make_pair("getreceivedbyaccount", &getreceivedbyaccount),
1841 make_pair("listreceivedbyaddress", &listreceivedbyaddress),
1842 make_pair("listreceivedbyaccount", &listreceivedbyaccount),
1843 make_pair("backupwallet", &backupwallet),
1844 make_pair("keypoolrefill", &keypoolrefill),
1845 make_pair("walletpassphrase", &walletpassphrase),
1846 make_pair("walletpassphrasechange", &walletpassphrasechange),
1847 make_pair("walletlock", &walletlock),
1848 make_pair("encryptwallet", &encryptwallet),
1849 make_pair("validateaddress", &validateaddress),
1850 make_pair("getbalance", &getbalance),
1851 make_pair("move", &movecmd),
1852 make_pair("sendfrom", &sendfrom),
1853 make_pair("sendmany", &sendmany),
1854 make_pair("gettransaction", &gettransaction),
1855 make_pair("listtransactions", &listtransactions),
1856 make_pair("signmessage", &signmessage),
1857 make_pair("verifymessage", &verifymessage),
1858 make_pair("getwork", &getwork),
1859 make_pair("listaccounts", &listaccounts),
1860 make_pair("settxfee", &settxfee),
1861 make_pair("getmemorypool", &getmemorypool),
1862 make_pair("listsinceblock", &listsinceblock),
1864 map<string, rpcfn_type> mapCallTable(pCallTable, pCallTable + sizeof(pCallTable)/sizeof(pCallTable[0]));
1866 string pAllowInSafeMode[] =
1872 "getconnectioncount",
1879 "getaccountaddress",
1881 "getaddressesbyaccount",
1890 set<string> setAllowInSafeMode(pAllowInSafeMode, pAllowInSafeMode + sizeof(pAllowInSafeMode)/sizeof(pAllowInSafeMode[0]));
1898 // This ain't Apache. We're just using HTTP header for the length field
1899 // and to be compatible with other JSON-RPC implementations.
1902 string HTTPPost(const string& strMsg, const map<string,string>& mapRequestHeaders)
1905 s << "POST / HTTP/1.1\r\n"
1906 << "User-Agent: bitcoin-json-rpc/" << FormatFullVersion() << "\r\n"
1907 << "Host: 127.0.0.1\r\n"
1908 << "Content-Type: application/json\r\n"
1909 << "Content-Length: " << strMsg.size() << "\r\n"
1910 << "Connection: close\r\n"
1911 << "Accept: application/json\r\n";
1912 BOOST_FOREACH(const PAIRTYPE(string, string)& item, mapRequestHeaders)
1913 s << item.first << ": " << item.second << "\r\n";
1914 s << "\r\n" << strMsg;
1919 string rfc1123Time()
1924 struct tm* now_gmt = gmtime(&now);
1925 string locale(setlocale(LC_TIME, NULL));
1926 setlocale(LC_TIME, "C"); // we want posix (aka "C") weekday/month strings
1927 strftime(buffer, sizeof(buffer), "%a, %d %b %Y %H:%M:%S +0000", now_gmt);
1928 setlocale(LC_TIME, locale.c_str());
1929 return string(buffer);
1932 static string HTTPReply(int nStatus, const string& strMsg)
1935 return strprintf("HTTP/1.0 401 Authorization Required\r\n"
1937 "Server: bitcoin-json-rpc/%s\r\n"
1938 "WWW-Authenticate: Basic realm=\"jsonrpc\"\r\n"
1939 "Content-Type: text/html\r\n"
1940 "Content-Length: 296\r\n"
1942 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\r\n"
1943 "\"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd\">\r\n"
1946 "<TITLE>Error</TITLE>\r\n"
1947 "<META HTTP-EQUIV='Content-Type' CONTENT='text/html; charset=ISO-8859-1'>\r\n"
1949 "<BODY><H1>401 Unauthorized.</H1></BODY>\r\n"
1950 "</HTML>\r\n", rfc1123Time().c_str(), FormatFullVersion().c_str());
1951 const char *cStatus;
1952 if (nStatus == 200) cStatus = "OK";
1953 else if (nStatus == 400) cStatus = "Bad Request";
1954 else if (nStatus == 403) cStatus = "Forbidden";
1955 else if (nStatus == 404) cStatus = "Not Found";
1956 else if (nStatus == 500) cStatus = "Internal Server Error";
1959 "HTTP/1.1 %d %s\r\n"
1961 "Connection: close\r\n"
1962 "Content-Length: %d\r\n"
1963 "Content-Type: application/json\r\n"
1964 "Server: bitcoin-json-rpc/%s\r\n"
1969 rfc1123Time().c_str(),
1971 FormatFullVersion().c_str(),
1975 int ReadHTTPStatus(std::basic_istream<char>& stream)
1978 getline(stream, str);
1979 vector<string> vWords;
1980 boost::split(vWords, str, boost::is_any_of(" "));
1981 if (vWords.size() < 2)
1983 return atoi(vWords[1].c_str());
1986 int ReadHTTPHeader(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet)
1992 std::getline(stream, str);
1993 if (str.empty() || str == "\r")
1995 string::size_type nColon = str.find(":");
1996 if (nColon != string::npos)
1998 string strHeader = str.substr(0, nColon);
1999 boost::trim(strHeader);
2000 boost::to_lower(strHeader);
2001 string strValue = str.substr(nColon+1);
2002 boost::trim(strValue);
2003 mapHeadersRet[strHeader] = strValue;
2004 if (strHeader == "content-length")
2005 nLen = atoi(strValue.c_str());
2011 int ReadHTTP(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet, string& strMessageRet)
2013 mapHeadersRet.clear();
2017 int nStatus = ReadHTTPStatus(stream);
2020 int nLen = ReadHTTPHeader(stream, mapHeadersRet);
2021 if (nLen < 0 || nLen > MAX_SIZE)
2027 vector<char> vch(nLen);
2028 stream.read(&vch[0], nLen);
2029 strMessageRet = string(vch.begin(), vch.end());
2035 bool HTTPAuthorized(map<string, string>& mapHeaders)
2037 string strAuth = mapHeaders["authorization"];
2038 if (strAuth.substr(0,6) != "Basic ")
2040 string strUserPass64 = strAuth.substr(6); boost::trim(strUserPass64);
2041 string strUserPass = DecodeBase64(strUserPass64);
2042 string::size_type nColon = strUserPass.find(":");
2043 if (nColon == string::npos)
2045 string strUser = strUserPass.substr(0, nColon);
2046 string strPassword = strUserPass.substr(nColon+1);
2047 return (strUser == mapArgs["-rpcuser"] && strPassword == mapArgs["-rpcpassword"]);
2051 // JSON-RPC protocol. Bitcoin speaks version 1.0 for maximum compatibility,
2052 // but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
2053 // unspecified (HTTP errors and contents of 'error').
2055 // 1.0 spec: http://json-rpc.org/wiki/specification
2056 // 1.2 spec: http://groups.google.com/group/json-rpc/web/json-rpc-over-http
2057 // http://www.codeproject.com/KB/recipes/JSON_Spirit.aspx
2060 string JSONRPCRequest(const string& strMethod, const Array& params, const Value& id)
2063 request.push_back(Pair("method", strMethod));
2064 request.push_back(Pair("params", params));
2065 request.push_back(Pair("id", id));
2066 return write_string(Value(request), false) + "\n";
2069 string JSONRPCReply(const Value& result, const Value& error, const Value& id)
2072 if (error.type() != null_type)
2073 reply.push_back(Pair("result", Value::null));
2075 reply.push_back(Pair("result", result));
2076 reply.push_back(Pair("error", error));
2077 reply.push_back(Pair("id", id));
2078 return write_string(Value(reply), false) + "\n";
2081 void ErrorReply(std::ostream& stream, const Object& objError, const Value& id)
2083 // Send error reply from json-rpc error object
2085 int code = find_value(objError, "code").get_int();
2086 if (code == -32600) nStatus = 400;
2087 else if (code == -32601) nStatus = 404;
2088 string strReply = JSONRPCReply(Value::null, objError, id);
2089 stream << HTTPReply(nStatus, strReply) << std::flush;
2092 bool ClientAllowed(const string& strAddress)
2094 if (strAddress == asio::ip::address_v4::loopback().to_string())
2096 const vector<string>& vAllow = mapMultiArgs["-rpcallowip"];
2097 BOOST_FOREACH(string strAllow, vAllow)
2098 if (WildcardMatch(strAddress, strAllow))
2105 // IOStream device that speaks SSL but can also speak non-SSL
2107 class SSLIOStreamDevice : public iostreams::device<iostreams::bidirectional> {
2109 SSLIOStreamDevice(SSLStream &streamIn, bool fUseSSLIn) : stream(streamIn)
2111 fUseSSL = fUseSSLIn;
2112 fNeedHandshake = fUseSSLIn;
2115 void handshake(ssl::stream_base::handshake_type role)
2117 if (!fNeedHandshake) return;
2118 fNeedHandshake = false;
2119 stream.handshake(role);
2121 std::streamsize read(char* s, std::streamsize n)
2123 handshake(ssl::stream_base::server); // HTTPS servers read first
2124 if (fUseSSL) return stream.read_some(asio::buffer(s, n));
2125 return stream.next_layer().read_some(asio::buffer(s, n));
2127 std::streamsize write(const char* s, std::streamsize n)
2129 handshake(ssl::stream_base::client); // HTTPS clients write first
2130 if (fUseSSL) return asio::write(stream, asio::buffer(s, n));
2131 return asio::write(stream.next_layer(), asio::buffer(s, n));
2133 bool connect(const std::string& server, const std::string& port)
2135 ip::tcp::resolver resolver(stream.get_io_service());
2136 ip::tcp::resolver::query query(server.c_str(), port.c_str());
2137 ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
2138 ip::tcp::resolver::iterator end;
2139 boost::system::error_code error = asio::error::host_not_found;
2140 while (error && endpoint_iterator != end)
2142 stream.lowest_layer().close();
2143 stream.lowest_layer().connect(*endpoint_iterator++, error);
2151 bool fNeedHandshake;
2157 void ThreadRPCServer(void* parg)
2159 IMPLEMENT_RANDOMIZE_STACK(ThreadRPCServer(parg));
2162 vnThreadsRunning[4]++;
2163 ThreadRPCServer2(parg);
2164 vnThreadsRunning[4]--;
2166 catch (std::exception& e) {
2167 vnThreadsRunning[4]--;
2168 PrintException(&e, "ThreadRPCServer()");
2170 vnThreadsRunning[4]--;
2171 PrintException(NULL, "ThreadRPCServer()");
2173 printf("ThreadRPCServer exiting\n");
2177 extern bool HACK_SHUTDOWN;
2180 void ThreadRPCServer2(void* parg)
2182 printf("ThreadRPCServer started\n");
2184 if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
2186 unsigned char rand_pwd[32];
2187 RAND_bytes(rand_pwd, 32);
2188 string strWhatAmI = "To use bitcoind";
2189 if (mapArgs.count("-server"))
2190 strWhatAmI = strprintf(_("To use the %s option"), "\"-server\"");
2191 else if (mapArgs.count("-daemon"))
2192 strWhatAmI = strprintf(_("To use the %s option"), "\"-daemon\"");
2193 ThreadSafeMessageBox(strprintf(
2194 _("Error: %s, you must set a rpcpassword in the configuration file:\n %s\n"
2195 "It is recommended you use the following random password:\n"
2196 "rpcuser=bitcoinrpc\n"
2198 "(you do not need to remember this password)\n"
2199 "If the file does not exist, create it with owner-readable-only file permissions.\n"),
2201 GetConfigFile().c_str(),
2202 EncodeBase58(&rand_pwd[0],&rand_pwd[0]+32).c_str()),
2203 _("Error"), wxOK | wxMODAL);
2205 CreateThread(Shutdown, NULL);
2210 bool fUseSSL = GetBoolArg("-rpcssl");
2211 asio::ip::address bindAddress = mapArgs.count("-rpcallowip") ? asio::ip::address_v4::any() : asio::ip::address_v4::loopback();
2213 asio::io_service io_service;
2214 ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", 8332));
2216 ip::tcp::acceptor acceptor(io_service, endpoint);
2218 acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
2220 ip::tcp::acceptor acceptor(io_service);
2223 acceptor.open(endpoint.protocol());
2224 acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
2225 acceptor.bind(endpoint);
2226 acceptor.listen(socket_base::max_connections);
2228 catch(system::system_error &e)
2230 HACK_SHUTDOWN = true;
2231 ThreadSafeMessageBox(strprintf(_("An error occured while setting up the RPC port %i for listening: %s"), endpoint.port(), e.what()),
2232 _("Error"), wxOK | wxMODAL);
2238 ssl::context context(io_service, ssl::context::sslv23);
2241 context.set_options(ssl::context::no_sslv2);
2242 filesystem::path certfile = GetArg("-rpcsslcertificatechainfile", "server.cert");
2243 if (!certfile.is_complete()) certfile = filesystem::path(GetDataDir()) / certfile;
2244 if (filesystem::exists(certfile)) context.use_certificate_chain_file(certfile.string().c_str());
2245 else printf("ThreadRPCServer ERROR: missing server certificate file %s\n", certfile.string().c_str());
2246 filesystem::path pkfile = GetArg("-rpcsslprivatekeyfile", "server.pem");
2247 if (!pkfile.is_complete()) pkfile = filesystem::path(GetDataDir()) / pkfile;
2248 if (filesystem::exists(pkfile)) context.use_private_key_file(pkfile.string().c_str(), ssl::context::pem);
2249 else printf("ThreadRPCServer ERROR: missing server private key file %s\n", pkfile.string().c_str());
2251 string ciphers = GetArg("-rpcsslciphers",
2252 "TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH");
2253 SSL_CTX_set_cipher_list(context.impl(), ciphers.c_str());
2257 throw runtime_error("-rpcssl=1, but bitcoin compiled without full openssl libraries.");
2262 // Accept connection
2264 SSLStream sslStream(io_service, context);
2265 SSLIOStreamDevice d(sslStream, fUseSSL);
2266 iostreams::stream<SSLIOStreamDevice> stream(d);
2268 ip::tcp::iostream stream;
2271 ip::tcp::endpoint peer;
2272 vnThreadsRunning[4]--;
2274 acceptor.accept(sslStream.lowest_layer(), peer);
2276 acceptor.accept(*stream.rdbuf(), peer);
2278 vnThreadsRunning[4]++;
2282 // Restrict callers by IP
2283 if (!ClientAllowed(peer.address().to_string()))
2285 // Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake.
2287 stream << HTTPReply(403, "") << std::flush;
2291 map<string, string> mapHeaders;
2294 boost::thread api_caller(ReadHTTP, boost::ref(stream), boost::ref(mapHeaders), boost::ref(strRequest));
2295 if (!api_caller.timed_join(boost::posix_time::seconds(GetArg("-rpctimeout", 30))))
2298 printf("ThreadRPCServer ReadHTTP timeout\n");
2302 // Check authorization
2303 if (mapHeaders.count("authorization") == 0)
2305 stream << HTTPReply(401, "") << std::flush;
2308 if (!HTTPAuthorized(mapHeaders))
2310 printf("ThreadRPCServer incorrect password attempt from %s\n",peer.address().to_string().c_str());
2311 /* Deter brute-forcing short passwords.
2312 If this results in a DOS the user really
2313 shouldn't have their RPC port exposed.*/
2314 if (mapArgs["-rpcpassword"].size() < 20)
2317 stream << HTTPReply(401, "") << std::flush;
2321 Value id = Value::null;
2326 if (!read_string(strRequest, valRequest) || valRequest.type() != obj_type)
2327 throw JSONRPCError(-32700, "Parse error");
2328 const Object& request = valRequest.get_obj();
2330 // Parse id now so errors from here on will have the id
2331 id = find_value(request, "id");
2334 Value valMethod = find_value(request, "method");
2335 if (valMethod.type() == null_type)
2336 throw JSONRPCError(-32600, "Missing method");
2337 if (valMethod.type() != str_type)
2338 throw JSONRPCError(-32600, "Method must be a string");
2339 string strMethod = valMethod.get_str();
2340 if (strMethod != "getwork" && strMethod != "getmemorypool")
2341 printf("ThreadRPCServer method=%s\n", strMethod.c_str());
2344 Value valParams = find_value(request, "params");
2346 if (valParams.type() == array_type)
2347 params = valParams.get_array();
2348 else if (valParams.type() == null_type)
2351 throw JSONRPCError(-32600, "Params must be an array");
2354 map<string, rpcfn_type>::iterator mi = mapCallTable.find(strMethod);
2355 if (mi == mapCallTable.end())
2356 throw JSONRPCError(-32601, "Method not found");
2358 // Observe safe mode
2359 string strWarning = GetWarnings("rpc");
2360 if (strWarning != "" && !GetBoolArg("-disablesafemode") && !setAllowInSafeMode.count(strMethod))
2361 throw JSONRPCError(-2, string("Safe mode: ") + strWarning);
2367 CRITICAL_BLOCK(cs_main)
2368 CRITICAL_BLOCK(pwalletMain->cs_wallet)
2369 result = (*(*mi).second)(params, false);
2372 string strReply = JSONRPCReply(result, Value::null, id);
2373 stream << HTTPReply(200, strReply) << std::flush;
2375 catch (std::exception& e)
2377 ErrorReply(stream, JSONRPCError(-1, e.what()), id);
2380 catch (Object& objError)
2382 ErrorReply(stream, objError, id);
2384 catch (std::exception& e)
2386 ErrorReply(stream, JSONRPCError(-32700, e.what()), id);
2394 Object CallRPC(const string& strMethod, const Array& params)
2396 if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
2397 throw runtime_error(strprintf(
2398 _("You must set rpcpassword=<password> in the configuration file:\n%s\n"
2399 "If the file does not exist, create it with owner-readable-only file permissions."),
2400 GetConfigFile().c_str()));
2402 // Connect to localhost
2403 bool fUseSSL = GetBoolArg("-rpcssl");
2405 asio::io_service io_service;
2406 ssl::context context(io_service, ssl::context::sslv23);
2407 context.set_options(ssl::context::no_sslv2);
2408 SSLStream sslStream(io_service, context);
2409 SSLIOStreamDevice d(sslStream, fUseSSL);
2410 iostreams::stream<SSLIOStreamDevice> stream(d);
2411 if (!d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332")))
2412 throw runtime_error("couldn't connect to server");
2415 throw runtime_error("-rpcssl=1, but bitcoin compiled without full openssl libraries.");
2417 ip::tcp::iostream stream(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332"));
2419 throw runtime_error("couldn't connect to server");
2423 // HTTP basic authentication
2424 string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
2425 map<string, string> mapRequestHeaders;
2426 mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64;
2429 string strRequest = JSONRPCRequest(strMethod, params, 1);
2430 string strPost = HTTPPost(strRequest, mapRequestHeaders);
2431 stream << strPost << std::flush;
2434 map<string, string> mapHeaders;
2436 int nStatus = ReadHTTP(stream, mapHeaders, strReply);
2438 throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
2439 else if (nStatus >= 400 && nStatus != 400 && nStatus != 404 && nStatus != 500)
2440 throw runtime_error(strprintf("server returned HTTP error %d", nStatus));
2441 else if (strReply.empty())
2442 throw runtime_error("no response from server");
2446 if (!read_string(strReply, valReply))
2447 throw runtime_error("couldn't parse reply from server");
2448 const Object& reply = valReply.get_obj();
2450 throw runtime_error("expected reply to have result, error and id properties");
2458 template<typename T>
2459 void ConvertTo(Value& value)
2461 if (value.type() == str_type)
2463 // reinterpret string as unquoted json value
2465 if (!read_string(value.get_str(), value2))
2466 throw runtime_error("type mismatch");
2467 value = value2.get_value<T>();
2471 value = value.get_value<T>();
2475 int CommandLineRPC(int argc, char *argv[])
2482 while (argc > 1 && IsSwitchChar(argv[1][0]))
2490 throw runtime_error("too few parameters");
2491 string strMethod = argv[1];
2493 // Parameters default to strings
2495 for (int i = 2; i < argc; i++)
2496 params.push_back(argv[i]);
2497 int n = params.size();
2500 // Special case non-string parameter types
2502 if (strMethod == "setgenerate" && n > 0) ConvertTo<bool>(params[0]);
2503 if (strMethod == "setgenerate" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2504 if (strMethod == "sendtoaddress" && n > 1) ConvertTo<double>(params[1]);
2505 if (strMethod == "settxfee" && n > 0) ConvertTo<double>(params[0]);
2506 if (strMethod == "getreceivedbyaddress" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2507 if (strMethod == "getreceivedbyaccount" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2508 if (strMethod == "listreceivedbyaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2509 if (strMethod == "listreceivedbyaddress" && n > 1) ConvertTo<bool>(params[1]);
2510 if (strMethod == "listreceivedbyaccount" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2511 if (strMethod == "listreceivedbyaccount" && n > 1) ConvertTo<bool>(params[1]);
2512 if (strMethod == "getbalance" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2513 if (strMethod == "move" && n > 2) ConvertTo<double>(params[2]);
2514 if (strMethod == "move" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2515 if (strMethod == "sendfrom" && n > 2) ConvertTo<double>(params[2]);
2516 if (strMethod == "sendfrom" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2517 if (strMethod == "listtransactions" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2518 if (strMethod == "listtransactions" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2519 if (strMethod == "listaccounts" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2520 if (strMethod == "walletpassphrase" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2521 if (strMethod == "listsinceblock" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2522 if (strMethod == "sendmany" && n > 1)
2524 string s = params[1].get_str();
2526 if (!read_string(s, v) || v.type() != obj_type)
2527 throw runtime_error("type mismatch");
2528 params[1] = v.get_obj();
2530 if (strMethod == "sendmany" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2533 Object reply = CallRPC(strMethod, params);
2536 const Value& result = find_value(reply, "result");
2537 const Value& error = find_value(reply, "error");
2539 if (error.type() != null_type)
2542 strPrint = "error: " + write_string(error, false);
2543 int code = find_value(error.get_obj(), "code").get_int();
2549 if (result.type() == null_type)
2551 else if (result.type() == str_type)
2552 strPrint = result.get_str();
2554 strPrint = write_string(result, true);
2557 catch (std::exception& e)
2559 strPrint = string("error: ") + e.what();
2564 PrintException(NULL, "CommandLineRPC()");
2569 fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
2578 int main(int argc, char *argv[])
2581 // Turn off microsoft heap dump noise
2582 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
2583 _CrtSetReportFile(_CRT_WARN, CreateFile("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0));
2585 setbuf(stdin, NULL);
2586 setbuf(stdout, NULL);
2587 setbuf(stderr, NULL);
2591 if (argc >= 2 && string(argv[1]) == "-server")
2593 printf("server ready\n");
2594 ThreadRPCServer(NULL);
2598 return CommandLineRPC(argc, argv);
2601 catch (std::exception& e) {
2602 PrintException(&e, "main()");
2604 PrintException(NULL, "main()");