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.
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));
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)
752 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listReceived)
753 nBalance += r.second;
754 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listSent)
755 nBalance -= r.second;
757 nBalance += allGeneratedMature;
759 return ValueFromAmount(nBalance);
762 string strAccount = AccountFromValue(params[0]);
764 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
766 return ValueFromAmount(nBalance);
770 Value movecmd(const Array& params, bool fHelp)
772 if (fHelp || params.size() < 3 || params.size() > 5)
774 "move <fromaccount> <toaccount> <amount> [minconf=1] [comment]\n"
775 "Move from one account in your wallet to another.");
777 string strFrom = AccountFromValue(params[0]);
778 string strTo = AccountFromValue(params[1]);
779 int64 nAmount = AmountFromValue(params[2]);
780 if (params.size() > 3)
781 // unused parameter, used to be nMinDepth, keep type-checking it though
782 (void)params[3].get_int();
784 if (params.size() > 4)
785 strComment = params[4].get_str();
787 CWalletDB walletdb(pwalletMain->strWalletFile);
790 int64 nNow = GetAdjustedTime();
793 CAccountingEntry debit;
794 debit.strAccount = strFrom;
795 debit.nCreditDebit = -nAmount;
797 debit.strOtherAccount = strTo;
798 debit.strComment = strComment;
799 walletdb.WriteAccountingEntry(debit);
802 CAccountingEntry credit;
803 credit.strAccount = strTo;
804 credit.nCreditDebit = nAmount;
806 credit.strOtherAccount = strFrom;
807 credit.strComment = strComment;
808 walletdb.WriteAccountingEntry(credit);
810 walletdb.TxnCommit();
816 Value sendfrom(const Array& params, bool fHelp)
818 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
820 "sendfrom <fromaccount> <tobitcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
821 "<amount> is a real and is rounded to the nearest 0.00000001\n"
822 "requires wallet passphrase to be set with walletpassphrase first");
823 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
825 "sendfrom <fromaccount> <tobitcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
826 "<amount> is a real and is rounded to the nearest 0.00000001");
828 string strAccount = AccountFromValue(params[0]);
829 CBitcoinAddress address(params[1].get_str());
830 if (!address.IsValid())
831 throw JSONRPCError(-5, "Invalid bitcoin address");
832 int64 nAmount = AmountFromValue(params[2]);
834 if (params.size() > 3)
835 nMinDepth = params[3].get_int();
838 wtx.strFromAccount = strAccount;
839 if (params.size() > 4 && params[4].type() != null_type && !params[4].get_str().empty())
840 wtx.mapValue["comment"] = params[4].get_str();
841 if (params.size() > 5 && params[5].type() != null_type && !params[5].get_str().empty())
842 wtx.mapValue["to"] = params[5].get_str();
844 if (pwalletMain->IsLocked())
845 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
848 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
849 if (nAmount > nBalance)
850 throw JSONRPCError(-6, "Account has insufficient funds");
853 string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
855 throw JSONRPCError(-4, strError);
857 return wtx.GetHash().GetHex();
861 Value sendmany(const Array& params, bool fHelp)
863 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
865 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
866 "amounts are double-precision floating point numbers\n"
867 "requires wallet passphrase to be set with walletpassphrase first");
868 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
870 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
871 "amounts are double-precision floating point numbers");
873 string strAccount = AccountFromValue(params[0]);
874 Object sendTo = params[1].get_obj();
876 if (params.size() > 2)
877 nMinDepth = params[2].get_int();
880 wtx.strFromAccount = strAccount;
881 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
882 wtx.mapValue["comment"] = params[3].get_str();
884 set<CBitcoinAddress> setAddress;
885 vector<pair<CScript, int64> > vecSend;
887 int64 totalAmount = 0;
888 BOOST_FOREACH(const Pair& s, sendTo)
890 CBitcoinAddress address(s.name_);
891 if (!address.IsValid())
892 throw JSONRPCError(-5, string("Invalid bitcoin address:")+s.name_);
894 if (setAddress.count(address))
895 throw JSONRPCError(-8, string("Invalid parameter, duplicated address: ")+s.name_);
896 setAddress.insert(address);
898 CScript scriptPubKey;
899 scriptPubKey.SetBitcoinAddress(address);
900 int64 nAmount = AmountFromValue(s.value_);
901 totalAmount += nAmount;
903 vecSend.push_back(make_pair(scriptPubKey, nAmount));
906 if (pwalletMain->IsLocked())
907 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
910 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
911 if (totalAmount > nBalance)
912 throw JSONRPCError(-6, "Account has insufficient funds");
915 CReserveKey keyChange(pwalletMain);
916 int64 nFeeRequired = 0;
917 bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired);
920 if (totalAmount + nFeeRequired > pwalletMain->GetBalance())
921 throw JSONRPCError(-6, "Insufficient funds");
922 throw JSONRPCError(-4, "Transaction creation failed");
924 if (!pwalletMain->CommitTransaction(wtx, keyChange))
925 throw JSONRPCError(-4, "Transaction commit failed");
927 return wtx.GetHash().GetHex();
942 Value ListReceived(const Array& params, bool fByAccounts)
944 // Minimum confirmations
946 if (params.size() > 0)
947 nMinDepth = params[0].get_int();
949 // Whether to include empty accounts
950 bool fIncludeEmpty = false;
951 if (params.size() > 1)
952 fIncludeEmpty = params[1].get_bool();
955 map<CBitcoinAddress, tallyitem> mapTally;
956 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
958 const CWalletTx& wtx = (*it).second;
959 if (wtx.IsCoinBase() || !wtx.IsFinal())
962 int nDepth = wtx.GetDepthInMainChain();
963 if (nDepth < nMinDepth)
966 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
968 CBitcoinAddress address;
969 if (!ExtractAddress(txout.scriptPubKey, pwalletMain, address) || !address.IsValid())
972 tallyitem& item = mapTally[address];
973 item.nAmount += txout.nValue;
974 item.nConf = min(item.nConf, nDepth);
980 map<string, tallyitem> mapAccountTally;
981 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
983 const CBitcoinAddress& address = item.first;
984 const string& strAccount = item.second;
985 map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
986 if (it == mapTally.end() && !fIncludeEmpty)
991 if (it != mapTally.end())
993 nAmount = (*it).second.nAmount;
994 nConf = (*it).second.nConf;
999 tallyitem& item = mapAccountTally[strAccount];
1000 item.nAmount += nAmount;
1001 item.nConf = min(item.nConf, nConf);
1006 obj.push_back(Pair("address", address.ToString()));
1007 obj.push_back(Pair("account", strAccount));
1008 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1009 obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf)));
1016 for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
1018 int64 nAmount = (*it).second.nAmount;
1019 int nConf = (*it).second.nConf;
1021 obj.push_back(Pair("account", (*it).first));
1022 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1023 obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf)));
1031 Value listreceivedbyaddress(const Array& params, bool fHelp)
1033 if (fHelp || params.size() > 2)
1034 throw runtime_error(
1035 "listreceivedbyaddress [minconf=1] [includeempty=false]\n"
1036 "[minconf] is the minimum number of confirmations before payments are included.\n"
1037 "[includeempty] whether to include addresses that haven't received any payments.\n"
1038 "Returns an array of objects containing:\n"
1039 " \"address\" : receiving address\n"
1040 " \"account\" : the account of the receiving address\n"
1041 " \"amount\" : total amount received by the address\n"
1042 " \"confirmations\" : number of confirmations of the most recent transaction included");
1044 return ListReceived(params, false);
1047 Value listreceivedbyaccount(const Array& params, bool fHelp)
1049 if (fHelp || params.size() > 2)
1050 throw runtime_error(
1051 "listreceivedbyaccount [minconf=1] [includeempty=false]\n"
1052 "[minconf] is the minimum number of confirmations before payments are included.\n"
1053 "[includeempty] whether to include accounts that haven't received any payments.\n"
1054 "Returns an array of objects containing:\n"
1055 " \"account\" : the account of the receiving addresses\n"
1056 " \"amount\" : total amount received by addresses with this account\n"
1057 " \"confirmations\" : number of confirmations of the most recent transaction included");
1059 return ListReceived(params, true);
1062 void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret)
1064 int64 nGeneratedImmature, nGeneratedMature, nFee;
1065 string strSentAccount;
1066 list<pair<CBitcoinAddress, int64> > listReceived;
1067 list<pair<CBitcoinAddress, int64> > listSent;
1068 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1070 bool fAllAccounts = (strAccount == string("*"));
1072 // Generated blocks assigned to account ""
1073 if ((nGeneratedMature+nGeneratedImmature) != 0 && (fAllAccounts || strAccount == ""))
1076 entry.push_back(Pair("account", string("")));
1077 if (nGeneratedImmature)
1079 entry.push_back(Pair("category", wtx.GetDepthInMainChain() ? "immature" : "orphan"));
1080 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedImmature)));
1084 entry.push_back(Pair("category", "generate"));
1085 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedMature)));
1088 WalletTxToJSON(wtx, entry);
1089 ret.push_back(entry);
1093 if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
1095 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1098 entry.push_back(Pair("account", strSentAccount));
1099 entry.push_back(Pair("address", s.first.ToString()));
1100 entry.push_back(Pair("category", "send"));
1101 entry.push_back(Pair("amount", ValueFromAmount(-s.second)));
1102 entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
1104 WalletTxToJSON(wtx, entry);
1105 ret.push_back(entry);
1110 if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
1111 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1114 if (pwalletMain->mapAddressBook.count(r.first))
1115 account = pwalletMain->mapAddressBook[r.first];
1116 if (fAllAccounts || (account == strAccount))
1119 entry.push_back(Pair("account", account));
1120 entry.push_back(Pair("address", r.first.ToString()));
1121 entry.push_back(Pair("category", "receive"));
1122 entry.push_back(Pair("amount", ValueFromAmount(r.second)));
1124 WalletTxToJSON(wtx, entry);
1125 ret.push_back(entry);
1130 void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret)
1132 bool fAllAccounts = (strAccount == string("*"));
1134 if (fAllAccounts || acentry.strAccount == strAccount)
1137 entry.push_back(Pair("account", acentry.strAccount));
1138 entry.push_back(Pair("category", "move"));
1139 entry.push_back(Pair("time", (boost::int64_t)acentry.nTime));
1140 entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
1141 entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
1142 entry.push_back(Pair("comment", acentry.strComment));
1143 ret.push_back(entry);
1147 Value listtransactions(const Array& params, bool fHelp)
1149 if (fHelp || params.size() > 3)
1150 throw runtime_error(
1151 "listtransactions [account] [count=10] [from=0]\n"
1152 "Returns up to [count] most recent transactions skipping the first [from] transactions for account [account].");
1154 string strAccount = "*";
1155 if (params.size() > 0)
1156 strAccount = params[0].get_str();
1158 if (params.size() > 1)
1159 nCount = params[1].get_int();
1161 if (params.size() > 2)
1162 nFrom = params[2].get_int();
1165 CWalletDB walletdb(pwalletMain->strWalletFile);
1167 // Firs: get all CWalletTx and CAccountingEntry into a sorted-by-time multimap:
1168 typedef pair<CWalletTx*, CAccountingEntry*> TxPair;
1169 typedef multimap<int64, TxPair > TxItems;
1172 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1174 CWalletTx* wtx = &((*it).second);
1175 txByTime.insert(make_pair(wtx->GetTxTime(), TxPair(wtx, (CAccountingEntry*)0)));
1177 list<CAccountingEntry> acentries;
1178 walletdb.ListAccountCreditDebit(strAccount, acentries);
1179 BOOST_FOREACH(CAccountingEntry& entry, acentries)
1181 txByTime.insert(make_pair(entry.nTime, TxPair((CWalletTx*)0, &entry)));
1184 // Now: iterate backwards until we have nCount items to return:
1185 TxItems::reverse_iterator it = txByTime.rbegin();
1186 if (txByTime.size() > nFrom) std::advance(it, nFrom);
1187 for (; it != txByTime.rend(); ++it)
1189 CWalletTx *const pwtx = (*it).second.first;
1191 ListTransactions(*pwtx, strAccount, 0, true, ret);
1192 CAccountingEntry *const pacentry = (*it).second.second;
1194 AcentryToJSON(*pacentry, strAccount, ret);
1196 if (ret.size() >= nCount) break;
1198 // ret is now newest to oldest
1200 // Make sure we return only last nCount items (sends-to-self might give us an extra):
1201 if (ret.size() > nCount)
1203 Array::iterator last = ret.begin();
1204 std::advance(last, nCount);
1205 ret.erase(last, ret.end());
1207 std::reverse(ret.begin(), ret.end()); // oldest to newest
1212 Value listaccounts(const Array& params, bool fHelp)
1214 if (fHelp || params.size() > 1)
1215 throw runtime_error(
1216 "listaccounts [minconf=1]\n"
1217 "Returns Object that has account names as keys, account balances as values.");
1220 if (params.size() > 0)
1221 nMinDepth = params[0].get_int();
1223 map<string, int64> mapAccountBalances;
1224 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& entry, pwalletMain->mapAddressBook) {
1225 if (pwalletMain->HaveKey(entry.first)) // This address belongs to me
1226 mapAccountBalances[entry.second] = 0;
1229 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1231 const CWalletTx& wtx = (*it).second;
1232 int64 nGeneratedImmature, nGeneratedMature, nFee;
1233 string strSentAccount;
1234 list<pair<CBitcoinAddress, int64> > listReceived;
1235 list<pair<CBitcoinAddress, int64> > listSent;
1236 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1237 mapAccountBalances[strSentAccount] -= nFee;
1238 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1239 mapAccountBalances[strSentAccount] -= s.second;
1240 if (wtx.GetDepthInMainChain() >= nMinDepth)
1242 mapAccountBalances[""] += nGeneratedMature;
1243 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1244 if (pwalletMain->mapAddressBook.count(r.first))
1245 mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second;
1247 mapAccountBalances[""] += r.second;
1251 list<CAccountingEntry> acentries;
1252 CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
1253 BOOST_FOREACH(const CAccountingEntry& entry, acentries)
1254 mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
1257 BOOST_FOREACH(const PAIRTYPE(string, int64)& accountBalance, mapAccountBalances) {
1258 ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
1263 Value listsinceblock(const Array& params, bool fHelp)
1266 throw runtime_error(
1267 "listsinceblock [blockid] [target-confirmations]\n"
1268 "Get all transactions in blocks since block [blockid], or all transactions if omitted");
1270 CBlockIndex *pindex = NULL;
1271 int target_confirms = 1;
1273 if (params.size() > 0)
1275 uint256 blockId = 0;
1277 blockId.SetHex(params[0].get_str());
1278 pindex = CBlockLocator(blockId).GetBlockIndex();
1281 if (params.size() > 1)
1283 target_confirms = params[1].get_int();
1285 if (target_confirms < 1)
1286 throw JSONRPCError(-8, "Invalid parameter");
1289 int depth = pindex ? (1 + nBestHeight - pindex->nHeight) : -1;
1293 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++)
1295 CWalletTx tx = (*it).second;
1297 if (depth == -1 || tx.GetDepthInMainChain() < depth)
1298 ListTransactions(tx, "*", 0, true, transactions);
1303 if (target_confirms == 1)
1306 lastblock = hashBestChain;
1310 int target_height = pindexBest->nHeight + 1 - target_confirms;
1313 for (block = pindexBest;
1314 block && block->nHeight > target_height;
1315 block = block->pprev);
1317 lastblock = block ? block->GetBlockHash() : 0;
1321 ret.push_back(Pair("transactions", transactions));
1322 ret.push_back(Pair("lastblock", lastblock.GetHex()));
1327 Value gettransaction(const Array& params, bool fHelp)
1329 if (fHelp || params.size() != 1)
1330 throw runtime_error(
1331 "gettransaction <txid>\n"
1332 "Get detailed information about <txid>");
1335 hash.SetHex(params[0].get_str());
1339 if (!pwalletMain->mapWallet.count(hash))
1340 throw JSONRPCError(-5, "Invalid or non-wallet transaction id");
1341 const CWalletTx& wtx = pwalletMain->mapWallet[hash];
1343 int64 nCredit = wtx.GetCredit();
1344 int64 nDebit = wtx.GetDebit();
1345 int64 nNet = nCredit - nDebit;
1346 int64 nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0);
1348 entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
1350 entry.push_back(Pair("fee", ValueFromAmount(nFee)));
1352 WalletTxToJSON(pwalletMain->mapWallet[hash], entry);
1355 ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details);
1356 entry.push_back(Pair("details", details));
1362 Value backupwallet(const Array& params, bool fHelp)
1364 if (fHelp || params.size() != 1)
1365 throw runtime_error(
1366 "backupwallet <destination>\n"
1367 "Safely copies wallet.dat to destination, which can be a directory or a path with filename.");
1369 string strDest = params[0].get_str();
1370 BackupWallet(*pwalletMain, strDest);
1376 Value keypoolrefill(const Array& params, bool fHelp)
1378 if (pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1379 throw runtime_error(
1381 "Fills the keypool, requires wallet passphrase to be set.");
1382 if (!pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1383 throw runtime_error(
1385 "Fills the keypool.");
1387 if (pwalletMain->IsLocked())
1388 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
1390 pwalletMain->TopUpKeyPool();
1392 if (pwalletMain->GetKeyPoolSize() < GetArg("-keypool", 100))
1393 throw JSONRPCError(-4, "Error refreshing keypool.");
1399 void ThreadTopUpKeyPool(void* parg)
1401 pwalletMain->TopUpKeyPool();
1404 void ThreadCleanWalletPassphrase(void* parg)
1406 int64 nMyWakeTime = GetTime() + *((int*)parg);
1408 if (nWalletUnlockTime == 0)
1410 CRITICAL_BLOCK(cs_nWalletUnlockTime)
1412 nWalletUnlockTime = nMyWakeTime;
1415 while (GetTime() < nWalletUnlockTime)
1416 Sleep(GetTime() - nWalletUnlockTime);
1418 CRITICAL_BLOCK(cs_nWalletUnlockTime)
1420 nWalletUnlockTime = 0;
1425 CRITICAL_BLOCK(cs_nWalletUnlockTime)
1427 if (nWalletUnlockTime < nMyWakeTime)
1428 nWalletUnlockTime = nMyWakeTime;
1434 pwalletMain->Lock();
1439 Value walletpassphrase(const Array& params, bool fHelp)
1441 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1442 throw runtime_error(
1443 "walletpassphrase <passphrase> <timeout>\n"
1444 "Stores the wallet decryption key in memory for <timeout> seconds.");
1447 if (!pwalletMain->IsCrypted())
1448 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
1450 if (!pwalletMain->IsLocked())
1451 throw JSONRPCError(-17, "Error: Wallet is already unlocked.");
1453 // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
1454 string strWalletPass;
1455 strWalletPass.reserve(100);
1456 mlock(&strWalletPass[0], strWalletPass.capacity());
1457 strWalletPass = params[0].get_str();
1459 if (strWalletPass.length() > 0)
1461 if (!pwalletMain->Unlock(strWalletPass))
1463 fill(strWalletPass.begin(), strWalletPass.end(), '\0');
1464 munlock(&strWalletPass[0], strWalletPass.capacity());
1465 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1467 fill(strWalletPass.begin(), strWalletPass.end(), '\0');
1468 munlock(&strWalletPass[0], strWalletPass.capacity());
1471 throw runtime_error(
1472 "walletpassphrase <passphrase> <timeout>\n"
1473 "Stores the wallet decryption key in memory for <timeout> seconds.");
1475 CreateThread(ThreadTopUpKeyPool, NULL);
1476 int* pnSleepTime = new int(params[1].get_int());
1477 CreateThread(ThreadCleanWalletPassphrase, pnSleepTime);
1483 Value walletpassphrasechange(const Array& params, bool fHelp)
1485 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1486 throw runtime_error(
1487 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1488 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1491 if (!pwalletMain->IsCrypted())
1492 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
1494 string strOldWalletPass;
1495 strOldWalletPass.reserve(100);
1496 mlock(&strOldWalletPass[0], strOldWalletPass.capacity());
1497 strOldWalletPass = params[0].get_str();
1499 string strNewWalletPass;
1500 strNewWalletPass.reserve(100);
1501 mlock(&strNewWalletPass[0], strNewWalletPass.capacity());
1502 strNewWalletPass = params[1].get_str();
1504 if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
1505 throw runtime_error(
1506 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1507 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1509 if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
1511 fill(strOldWalletPass.begin(), strOldWalletPass.end(), '\0');
1512 fill(strNewWalletPass.begin(), strNewWalletPass.end(), '\0');
1513 munlock(&strOldWalletPass[0], strOldWalletPass.capacity());
1514 munlock(&strNewWalletPass[0], strNewWalletPass.capacity());
1515 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1517 fill(strNewWalletPass.begin(), strNewWalletPass.end(), '\0');
1518 fill(strOldWalletPass.begin(), strOldWalletPass.end(), '\0');
1519 munlock(&strOldWalletPass[0], strOldWalletPass.capacity());
1520 munlock(&strNewWalletPass[0], strNewWalletPass.capacity());
1526 Value walletlock(const Array& params, bool fHelp)
1528 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
1529 throw runtime_error(
1531 "Removes the wallet encryption key from memory, locking the wallet.\n"
1532 "After calling this method, you will need to call walletpassphrase again\n"
1533 "before being able to call any methods which require the wallet to be unlocked.");
1536 if (!pwalletMain->IsCrypted())
1537 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletlock was called.");
1539 pwalletMain->Lock();
1540 CRITICAL_BLOCK(cs_nWalletUnlockTime)
1542 nWalletUnlockTime = 0;
1549 Value encryptwallet(const Array& params, bool fHelp)
1551 if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
1552 throw runtime_error(
1553 "encryptwallet <passphrase>\n"
1554 "Encrypts the wallet with <passphrase>.");
1557 if (pwalletMain->IsCrypted())
1558 throw JSONRPCError(-15, "Error: running with an encrypted wallet, but encryptwallet was called.");
1561 // shutting down via RPC while the GUI is running does not work (yet):
1562 throw runtime_error("Not Yet Implemented: use GUI to encrypt wallet, not RPC command");
1565 string strWalletPass;
1566 strWalletPass.reserve(100);
1567 mlock(&strWalletPass[0], strWalletPass.capacity());
1568 strWalletPass = params[0].get_str();
1570 if (strWalletPass.length() < 1)
1571 throw runtime_error(
1572 "encryptwallet <passphrase>\n"
1573 "Encrypts the wallet with <passphrase>.");
1575 if (!pwalletMain->EncryptWallet(strWalletPass))
1577 fill(strWalletPass.begin(), strWalletPass.end(), '\0');
1578 munlock(&strWalletPass[0], strWalletPass.capacity());
1579 throw JSONRPCError(-16, "Error: Failed to encrypt the wallet.");
1581 fill(strWalletPass.begin(), strWalletPass.end(), '\0');
1582 munlock(&strWalletPass[0], strWalletPass.capacity());
1584 // BDB seems to have a bad habit of writing old data into
1585 // slack space in .dat files; that is bad if the old data is
1586 // unencrypted private keys. So:
1587 CreateThread(Shutdown, NULL);
1588 return "wallet encrypted; bitcoin server stopping, restart to run with encrypted wallet";
1592 Value validateaddress(const Array& params, bool fHelp)
1594 if (fHelp || params.size() != 1)
1595 throw runtime_error(
1596 "validateaddress <bitcoinaddress>\n"
1597 "Return information about <bitcoinaddress>.");
1599 CBitcoinAddress address(params[0].get_str());
1600 bool isValid = address.IsValid();
1603 ret.push_back(Pair("isvalid", isValid));
1606 // Call Hash160ToAddress() so we always return current ADDRESSVERSION
1607 // version of the address:
1608 string currentAddress = address.ToString();
1609 ret.push_back(Pair("address", currentAddress));
1610 ret.push_back(Pair("ismine", (pwalletMain->HaveKey(address) > 0)));
1611 if (pwalletMain->mapAddressBook.count(address))
1612 ret.push_back(Pair("account", pwalletMain->mapAddressBook[address]));
1618 Value getwork(const Array& params, bool fHelp)
1620 if (fHelp || params.size() > 1)
1621 throw runtime_error(
1623 "If [data] is not specified, returns formatted hash data to work on:\n"
1624 " \"midstate\" : precomputed hash state after hashing the first half of the data (DEPRECATED)\n" // deprecated
1625 " \"data\" : block data\n"
1626 " \"hash1\" : formatted hash buffer for second hash (DEPRECATED)\n" // deprecated
1627 " \"target\" : little endian hash target\n"
1628 "If [data] is specified, tries to solve the block and returns true if it was successful.");
1631 throw JSONRPCError(-9, "Bitcoin is not connected!");
1633 if (IsInitialBlockDownload())
1634 throw JSONRPCError(-10, "Bitcoin is downloading blocks...");
1636 typedef map<uint256, pair<CBlock*, CScript> > mapNewBlock_t;
1637 static mapNewBlock_t mapNewBlock;
1638 static vector<CBlock*> vNewBlock;
1639 static CReserveKey reservekey(pwalletMain);
1641 if (params.size() == 0)
1644 static unsigned int nTransactionsUpdatedLast;
1645 static CBlockIndex* pindexPrev;
1646 static int64 nStart;
1647 static CBlock* pblock;
1648 if (pindexPrev != pindexBest ||
1649 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60))
1651 if (pindexPrev != pindexBest)
1653 // Deallocate old blocks since they're obsolete now
1654 mapNewBlock.clear();
1655 BOOST_FOREACH(CBlock* pblock, vNewBlock)
1659 nTransactionsUpdatedLast = nTransactionsUpdated;
1660 pindexPrev = pindexBest;
1664 pblock = CreateNewBlock(reservekey);
1666 throw JSONRPCError(-7, "Out of memory");
1667 vNewBlock.push_back(pblock);
1671 pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
1674 // Update nExtraNonce
1675 static unsigned int nExtraNonce = 0;
1676 IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
1679 mapNewBlock[pblock->hashMerkleRoot] = make_pair(pblock, pblock->vtx[0].vin[0].scriptSig);
1681 // Prebuild hash buffers
1685 FormatHashBuffers(pblock, pmidstate, pdata, phash1);
1687 uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
1690 result.push_back(Pair("midstate", HexStr(BEGIN(pmidstate), END(pmidstate)))); // deprecated
1691 result.push_back(Pair("data", HexStr(BEGIN(pdata), END(pdata))));
1692 result.push_back(Pair("hash1", HexStr(BEGIN(phash1), END(phash1)))); // deprecated
1693 result.push_back(Pair("target", HexStr(BEGIN(hashTarget), END(hashTarget))));
1699 vector<unsigned char> vchData = ParseHex(params[0].get_str());
1700 if (vchData.size() != 128)
1701 throw JSONRPCError(-8, "Invalid parameter");
1702 CBlock* pdata = (CBlock*)&vchData[0];
1705 for (int i = 0; i < 128/4; i++)
1706 ((unsigned int*)pdata)[i] = ByteReverse(((unsigned int*)pdata)[i]);
1709 if (!mapNewBlock.count(pdata->hashMerkleRoot))
1711 CBlock* pblock = mapNewBlock[pdata->hashMerkleRoot].first;
1713 pblock->nTime = pdata->nTime;
1714 pblock->nNonce = pdata->nNonce;
1715 pblock->vtx[0].vin[0].scriptSig = mapNewBlock[pdata->hashMerkleRoot].second;
1716 pblock->hashMerkleRoot = pblock->BuildMerkleTree();
1718 return CheckWork(pblock, *pwalletMain, reservekey);
1723 Value getmemorypool(const Array& params, bool fHelp)
1725 if (fHelp || params.size() > 1)
1726 throw runtime_error(
1727 "getmemorypool [data]\n"
1728 "If [data] is not specified, returns data needed to construct a block to work on:\n"
1729 " \"version\" : block version\n"
1730 " \"previousblockhash\" : hash of current highest block\n"
1731 " \"transactions\" : contents of non-coinbase transactions that should be included in the next block\n"
1732 " \"coinbasevalue\" : maximum allowable input to coinbase transaction, including the generation award and transaction fees\n"
1733 " \"time\" : timestamp appropriate for next block\n"
1734 " \"bits\" : compressed target of next block\n"
1735 "If [data] is specified, tries to solve the block and returns true if it was successful.");
1737 if (params.size() == 0)
1740 throw JSONRPCError(-9, "Bitcoin is not connected!");
1742 if (IsInitialBlockDownload())
1743 throw JSONRPCError(-10, "Bitcoin is downloading blocks...");
1745 static CReserveKey reservekey(pwalletMain);
1748 static unsigned int nTransactionsUpdatedLast;
1749 static CBlockIndex* pindexPrev;
1750 static int64 nStart;
1751 static CBlock* pblock;
1752 if (pindexPrev != pindexBest ||
1753 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 5))
1755 nTransactionsUpdatedLast = nTransactionsUpdated;
1756 pindexPrev = pindexBest;
1762 pblock = CreateNewBlock(reservekey);
1764 throw JSONRPCError(-7, "Out of memory");
1768 pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
1772 BOOST_FOREACH(CTransaction tx, pblock->vtx) {
1779 transactions.push_back(HexStr(ssTx.begin(), ssTx.end()));
1783 result.push_back(Pair("version", pblock->nVersion));
1784 result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex()));
1785 result.push_back(Pair("transactions", transactions));
1786 result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue));
1787 result.push_back(Pair("time", (int64_t)pblock->nTime));
1793 uBits.nBits = htonl((int32_t)pblock->nBits);
1794 result.push_back(Pair("bits", HexStr(BEGIN(uBits.cBits), END(uBits.cBits))));
1801 CDataStream ssBlock(ParseHex(params[0].get_str()));
1805 return ProcessBlock(NULL, &pblock);
1823 pair<string, rpcfn_type> pCallTable[] =
1825 make_pair("help", &help),
1826 make_pair("stop", &stop),
1827 make_pair("getblockcount", &getblockcount),
1828 make_pair("getblocknumber", &getblocknumber),
1829 make_pair("getconnectioncount", &getconnectioncount),
1830 make_pair("getdifficulty", &getdifficulty),
1831 make_pair("getgenerate", &getgenerate),
1832 make_pair("setgenerate", &setgenerate),
1833 make_pair("gethashespersec", &gethashespersec),
1834 make_pair("getinfo", &getinfo),
1835 make_pair("getnewaddress", &getnewaddress),
1836 make_pair("getaccountaddress", &getaccountaddress),
1837 make_pair("setaccount", &setaccount),
1838 make_pair("getaccount", &getaccount),
1839 make_pair("getaddressesbyaccount", &getaddressesbyaccount),
1840 make_pair("sendtoaddress", &sendtoaddress),
1841 make_pair("getreceivedbyaddress", &getreceivedbyaddress),
1842 make_pair("getreceivedbyaccount", &getreceivedbyaccount),
1843 make_pair("listreceivedbyaddress", &listreceivedbyaddress),
1844 make_pair("listreceivedbyaccount", &listreceivedbyaccount),
1845 make_pair("backupwallet", &backupwallet),
1846 make_pair("keypoolrefill", &keypoolrefill),
1847 make_pair("walletpassphrase", &walletpassphrase),
1848 make_pair("walletpassphrasechange", &walletpassphrasechange),
1849 make_pair("walletlock", &walletlock),
1850 make_pair("encryptwallet", &encryptwallet),
1851 make_pair("validateaddress", &validateaddress),
1852 make_pair("getbalance", &getbalance),
1853 make_pair("move", &movecmd),
1854 make_pair("sendfrom", &sendfrom),
1855 make_pair("sendmany", &sendmany),
1856 make_pair("gettransaction", &gettransaction),
1857 make_pair("listtransactions", &listtransactions),
1858 make_pair("signmessage", &signmessage),
1859 make_pair("verifymessage", &verifymessage),
1860 make_pair("getwork", &getwork),
1861 make_pair("listaccounts", &listaccounts),
1862 make_pair("settxfee", &settxfee),
1863 make_pair("getmemorypool", &getmemorypool),
1864 make_pair("listsinceblock", &listsinceblock),
1866 map<string, rpcfn_type> mapCallTable(pCallTable, pCallTable + sizeof(pCallTable)/sizeof(pCallTable[0]));
1868 string pAllowInSafeMode[] =
1874 "getconnectioncount",
1881 "getaccountaddress",
1883 "getaddressesbyaccount",
1892 set<string> setAllowInSafeMode(pAllowInSafeMode, pAllowInSafeMode + sizeof(pAllowInSafeMode)/sizeof(pAllowInSafeMode[0]));
1900 // This ain't Apache. We're just using HTTP header for the length field
1901 // and to be compatible with other JSON-RPC implementations.
1904 string HTTPPost(const string& strMsg, const map<string,string>& mapRequestHeaders)
1907 s << "POST / HTTP/1.1\r\n"
1908 << "User-Agent: bitcoin-json-rpc/" << FormatFullVersion() << "\r\n"
1909 << "Host: 127.0.0.1\r\n"
1910 << "Content-Type: application/json\r\n"
1911 << "Content-Length: " << strMsg.size() << "\r\n"
1912 << "Connection: close\r\n"
1913 << "Accept: application/json\r\n";
1914 BOOST_FOREACH(const PAIRTYPE(string, string)& item, mapRequestHeaders)
1915 s << item.first << ": " << item.second << "\r\n";
1916 s << "\r\n" << strMsg;
1921 string rfc1123Time()
1926 struct tm* now_gmt = gmtime(&now);
1927 string locale(setlocale(LC_TIME, NULL));
1928 setlocale(LC_TIME, "C"); // we want posix (aka "C") weekday/month strings
1929 strftime(buffer, sizeof(buffer), "%a, %d %b %Y %H:%M:%S +0000", now_gmt);
1930 setlocale(LC_TIME, locale.c_str());
1931 return string(buffer);
1934 static string HTTPReply(int nStatus, const string& strMsg)
1937 return strprintf("HTTP/1.0 401 Authorization Required\r\n"
1939 "Server: bitcoin-json-rpc/%s\r\n"
1940 "WWW-Authenticate: Basic realm=\"jsonrpc\"\r\n"
1941 "Content-Type: text/html\r\n"
1942 "Content-Length: 296\r\n"
1944 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\r\n"
1945 "\"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd\">\r\n"
1948 "<TITLE>Error</TITLE>\r\n"
1949 "<META HTTP-EQUIV='Content-Type' CONTENT='text/html; charset=ISO-8859-1'>\r\n"
1951 "<BODY><H1>401 Unauthorized.</H1></BODY>\r\n"
1952 "</HTML>\r\n", rfc1123Time().c_str(), FormatFullVersion().c_str());
1953 const char *cStatus;
1954 if (nStatus == 200) cStatus = "OK";
1955 else if (nStatus == 400) cStatus = "Bad Request";
1956 else if (nStatus == 403) cStatus = "Forbidden";
1957 else if (nStatus == 404) cStatus = "Not Found";
1958 else if (nStatus == 500) cStatus = "Internal Server Error";
1961 "HTTP/1.1 %d %s\r\n"
1963 "Connection: close\r\n"
1964 "Content-Length: %d\r\n"
1965 "Content-Type: application/json\r\n"
1966 "Server: bitcoin-json-rpc/%s\r\n"
1971 rfc1123Time().c_str(),
1973 FormatFullVersion().c_str(),
1977 int ReadHTTPStatus(std::basic_istream<char>& stream)
1980 getline(stream, str);
1981 vector<string> vWords;
1982 boost::split(vWords, str, boost::is_any_of(" "));
1983 if (vWords.size() < 2)
1985 return atoi(vWords[1].c_str());
1988 int ReadHTTPHeader(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet)
1994 std::getline(stream, str);
1995 if (str.empty() || str == "\r")
1997 string::size_type nColon = str.find(":");
1998 if (nColon != string::npos)
2000 string strHeader = str.substr(0, nColon);
2001 boost::trim(strHeader);
2002 boost::to_lower(strHeader);
2003 string strValue = str.substr(nColon+1);
2004 boost::trim(strValue);
2005 mapHeadersRet[strHeader] = strValue;
2006 if (strHeader == "content-length")
2007 nLen = atoi(strValue.c_str());
2013 int ReadHTTP(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet, string& strMessageRet)
2015 mapHeadersRet.clear();
2019 int nStatus = ReadHTTPStatus(stream);
2022 int nLen = ReadHTTPHeader(stream, mapHeadersRet);
2023 if (nLen < 0 || nLen > MAX_SIZE)
2029 vector<char> vch(nLen);
2030 stream.read(&vch[0], nLen);
2031 strMessageRet = string(vch.begin(), vch.end());
2037 bool HTTPAuthorized(map<string, string>& mapHeaders)
2039 string strAuth = mapHeaders["authorization"];
2040 if (strAuth.substr(0,6) != "Basic ")
2042 string strUserPass64 = strAuth.substr(6); boost::trim(strUserPass64);
2043 string strUserPass = DecodeBase64(strUserPass64);
2044 string::size_type nColon = strUserPass.find(":");
2045 if (nColon == string::npos)
2047 string strUser = strUserPass.substr(0, nColon);
2048 string strPassword = strUserPass.substr(nColon+1);
2049 return (strUser == mapArgs["-rpcuser"] && strPassword == mapArgs["-rpcpassword"]);
2053 // JSON-RPC protocol. Bitcoin speaks version 1.0 for maximum compatibility,
2054 // but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
2055 // unspecified (HTTP errors and contents of 'error').
2057 // 1.0 spec: http://json-rpc.org/wiki/specification
2058 // 1.2 spec: http://groups.google.com/group/json-rpc/web/json-rpc-over-http
2059 // http://www.codeproject.com/KB/recipes/JSON_Spirit.aspx
2062 string JSONRPCRequest(const string& strMethod, const Array& params, const Value& id)
2065 request.push_back(Pair("method", strMethod));
2066 request.push_back(Pair("params", params));
2067 request.push_back(Pair("id", id));
2068 return write_string(Value(request), false) + "\n";
2071 string JSONRPCReply(const Value& result, const Value& error, const Value& id)
2074 if (error.type() != null_type)
2075 reply.push_back(Pair("result", Value::null));
2077 reply.push_back(Pair("result", result));
2078 reply.push_back(Pair("error", error));
2079 reply.push_back(Pair("id", id));
2080 return write_string(Value(reply), false) + "\n";
2083 void ErrorReply(std::ostream& stream, const Object& objError, const Value& id)
2085 // Send error reply from json-rpc error object
2087 int code = find_value(objError, "code").get_int();
2088 if (code == -32600) nStatus = 400;
2089 else if (code == -32601) nStatus = 404;
2090 string strReply = JSONRPCReply(Value::null, objError, id);
2091 stream << HTTPReply(nStatus, strReply) << std::flush;
2094 bool ClientAllowed(const string& strAddress)
2096 if (strAddress == asio::ip::address_v4::loopback().to_string())
2098 const vector<string>& vAllow = mapMultiArgs["-rpcallowip"];
2099 BOOST_FOREACH(string strAllow, vAllow)
2100 if (WildcardMatch(strAddress, strAllow))
2107 // IOStream device that speaks SSL but can also speak non-SSL
2109 class SSLIOStreamDevice : public iostreams::device<iostreams::bidirectional> {
2111 SSLIOStreamDevice(SSLStream &streamIn, bool fUseSSLIn) : stream(streamIn)
2113 fUseSSL = fUseSSLIn;
2114 fNeedHandshake = fUseSSLIn;
2117 void handshake(ssl::stream_base::handshake_type role)
2119 if (!fNeedHandshake) return;
2120 fNeedHandshake = false;
2121 stream.handshake(role);
2123 std::streamsize read(char* s, std::streamsize n)
2125 handshake(ssl::stream_base::server); // HTTPS servers read first
2126 if (fUseSSL) return stream.read_some(asio::buffer(s, n));
2127 return stream.next_layer().read_some(asio::buffer(s, n));
2129 std::streamsize write(const char* s, std::streamsize n)
2131 handshake(ssl::stream_base::client); // HTTPS clients write first
2132 if (fUseSSL) return asio::write(stream, asio::buffer(s, n));
2133 return asio::write(stream.next_layer(), asio::buffer(s, n));
2135 bool connect(const std::string& server, const std::string& port)
2137 ip::tcp::resolver resolver(stream.get_io_service());
2138 ip::tcp::resolver::query query(server.c_str(), port.c_str());
2139 ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
2140 ip::tcp::resolver::iterator end;
2141 boost::system::error_code error = asio::error::host_not_found;
2142 while (error && endpoint_iterator != end)
2144 stream.lowest_layer().close();
2145 stream.lowest_layer().connect(*endpoint_iterator++, error);
2153 bool fNeedHandshake;
2159 void ThreadRPCServer(void* parg)
2161 IMPLEMENT_RANDOMIZE_STACK(ThreadRPCServer(parg));
2164 vnThreadsRunning[4]++;
2165 ThreadRPCServer2(parg);
2166 vnThreadsRunning[4]--;
2168 catch (std::exception& e) {
2169 vnThreadsRunning[4]--;
2170 PrintException(&e, "ThreadRPCServer()");
2172 vnThreadsRunning[4]--;
2173 PrintException(NULL, "ThreadRPCServer()");
2175 printf("ThreadRPCServer exiting\n");
2178 void ThreadRPCServer2(void* parg)
2180 printf("ThreadRPCServer started\n");
2182 if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
2184 string strWhatAmI = "To use bitcoind";
2185 if (mapArgs.count("-server"))
2186 strWhatAmI = strprintf(_("To use the %s option"), "\"-server\"");
2187 else if (mapArgs.count("-daemon"))
2188 strWhatAmI = strprintf(_("To use the %s option"), "\"-daemon\"");
2190 _("Error: %s, you must set rpcpassword=<password>\nin the configuration file: %s\n"
2191 "If the file does not exist, create it with owner-readable-only file permissions.\n"),
2193 GetConfigFile().c_str());
2195 CreateThread(Shutdown, NULL);
2200 bool fUseSSL = GetBoolArg("-rpcssl");
2201 asio::ip::address bindAddress = mapArgs.count("-rpcallowip") ? asio::ip::address_v4::any() : asio::ip::address_v4::loopback();
2203 asio::io_service io_service;
2204 ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", 8332));
2205 ip::tcp::acceptor acceptor(io_service, endpoint);
2207 acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
2210 ssl::context context(io_service, ssl::context::sslv23);
2213 context.set_options(ssl::context::no_sslv2);
2214 filesystem::path certfile = GetArg("-rpcsslcertificatechainfile", "server.cert");
2215 if (!certfile.is_complete()) certfile = filesystem::path(GetDataDir()) / certfile;
2216 if (filesystem::exists(certfile)) context.use_certificate_chain_file(certfile.string().c_str());
2217 else printf("ThreadRPCServer ERROR: missing server certificate file %s\n", certfile.string().c_str());
2218 filesystem::path pkfile = GetArg("-rpcsslprivatekeyfile", "server.pem");
2219 if (!pkfile.is_complete()) pkfile = filesystem::path(GetDataDir()) / pkfile;
2220 if (filesystem::exists(pkfile)) context.use_private_key_file(pkfile.string().c_str(), ssl::context::pem);
2221 else printf("ThreadRPCServer ERROR: missing server private key file %s\n", pkfile.string().c_str());
2223 string ciphers = GetArg("-rpcsslciphers",
2224 "TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH");
2225 SSL_CTX_set_cipher_list(context.impl(), ciphers.c_str());
2229 throw runtime_error("-rpcssl=1, but bitcoin compiled without full openssl libraries.");
2234 // Accept connection
2236 SSLStream sslStream(io_service, context);
2237 SSLIOStreamDevice d(sslStream, fUseSSL);
2238 iostreams::stream<SSLIOStreamDevice> stream(d);
2240 ip::tcp::iostream stream;
2243 ip::tcp::endpoint peer;
2244 vnThreadsRunning[4]--;
2246 acceptor.accept(sslStream.lowest_layer(), peer);
2248 acceptor.accept(*stream.rdbuf(), peer);
2250 vnThreadsRunning[4]++;
2254 // Restrict callers by IP
2255 if (!ClientAllowed(peer.address().to_string()))
2257 // Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake.
2259 stream << HTTPReply(403, "") << std::flush;
2263 map<string, string> mapHeaders;
2266 boost::thread api_caller(ReadHTTP, boost::ref(stream), boost::ref(mapHeaders), boost::ref(strRequest));
2267 if (!api_caller.timed_join(boost::posix_time::seconds(GetArg("-rpctimeout", 30))))
2270 printf("ThreadRPCServer ReadHTTP timeout\n");
2274 // Check authorization
2275 if (mapHeaders.count("authorization") == 0)
2277 stream << HTTPReply(401, "") << std::flush;
2280 if (!HTTPAuthorized(mapHeaders))
2282 // Deter brute-forcing short passwords
2283 if (mapArgs["-rpcpassword"].size() < 15)
2286 stream << HTTPReply(401, "") << std::flush;
2287 printf("ThreadRPCServer incorrect password attempt\n");
2291 Value id = Value::null;
2296 if (!read_string(strRequest, valRequest) || valRequest.type() != obj_type)
2297 throw JSONRPCError(-32700, "Parse error");
2298 const Object& request = valRequest.get_obj();
2300 // Parse id now so errors from here on will have the id
2301 id = find_value(request, "id");
2304 Value valMethod = find_value(request, "method");
2305 if (valMethod.type() == null_type)
2306 throw JSONRPCError(-32600, "Missing method");
2307 if (valMethod.type() != str_type)
2308 throw JSONRPCError(-32600, "Method must be a string");
2309 string strMethod = valMethod.get_str();
2310 if (strMethod != "getwork" && strMethod != "getmemorypool")
2311 printf("ThreadRPCServer method=%s\n", strMethod.c_str());
2314 Value valParams = find_value(request, "params");
2316 if (valParams.type() == array_type)
2317 params = valParams.get_array();
2318 else if (valParams.type() == null_type)
2321 throw JSONRPCError(-32600, "Params must be an array");
2324 map<string, rpcfn_type>::iterator mi = mapCallTable.find(strMethod);
2325 if (mi == mapCallTable.end())
2326 throw JSONRPCError(-32601, "Method not found");
2328 // Observe safe mode
2329 string strWarning = GetWarnings("rpc");
2330 if (strWarning != "" && !GetBoolArg("-disablesafemode") && !setAllowInSafeMode.count(strMethod))
2331 throw JSONRPCError(-2, string("Safe mode: ") + strWarning);
2337 CRITICAL_BLOCK(cs_main)
2338 CRITICAL_BLOCK(pwalletMain->cs_wallet)
2339 result = (*(*mi).second)(params, false);
2342 string strReply = JSONRPCReply(result, Value::null, id);
2343 stream << HTTPReply(200, strReply) << std::flush;
2345 catch (std::exception& e)
2347 ErrorReply(stream, JSONRPCError(-1, e.what()), id);
2350 catch (Object& objError)
2352 ErrorReply(stream, objError, id);
2354 catch (std::exception& e)
2356 ErrorReply(stream, JSONRPCError(-32700, e.what()), id);
2364 Object CallRPC(const string& strMethod, const Array& params)
2366 if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
2367 throw runtime_error(strprintf(
2368 _("You must set rpcpassword=<password> in the configuration file:\n%s\n"
2369 "If the file does not exist, create it with owner-readable-only file permissions."),
2370 GetConfigFile().c_str()));
2372 // Connect to localhost
2373 bool fUseSSL = GetBoolArg("-rpcssl");
2375 asio::io_service io_service;
2376 ssl::context context(io_service, ssl::context::sslv23);
2377 context.set_options(ssl::context::no_sslv2);
2378 SSLStream sslStream(io_service, context);
2379 SSLIOStreamDevice d(sslStream, fUseSSL);
2380 iostreams::stream<SSLIOStreamDevice> stream(d);
2381 if (!d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332")))
2382 throw runtime_error("couldn't connect to server");
2385 throw runtime_error("-rpcssl=1, but bitcoin compiled without full openssl libraries.");
2387 ip::tcp::iostream stream(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332"));
2389 throw runtime_error("couldn't connect to server");
2393 // HTTP basic authentication
2394 string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
2395 map<string, string> mapRequestHeaders;
2396 mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64;
2399 string strRequest = JSONRPCRequest(strMethod, params, 1);
2400 string strPost = HTTPPost(strRequest, mapRequestHeaders);
2401 stream << strPost << std::flush;
2404 map<string, string> mapHeaders;
2406 int nStatus = ReadHTTP(stream, mapHeaders, strReply);
2408 throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
2409 else if (nStatus >= 400 && nStatus != 400 && nStatus != 404 && nStatus != 500)
2410 throw runtime_error(strprintf("server returned HTTP error %d", nStatus));
2411 else if (strReply.empty())
2412 throw runtime_error("no response from server");
2416 if (!read_string(strReply, valReply))
2417 throw runtime_error("couldn't parse reply from server");
2418 const Object& reply = valReply.get_obj();
2420 throw runtime_error("expected reply to have result, error and id properties");
2428 template<typename T>
2429 void ConvertTo(Value& value)
2431 if (value.type() == str_type)
2433 // reinterpret string as unquoted json value
2435 if (!read_string(value.get_str(), value2))
2436 throw runtime_error("type mismatch");
2437 value = value2.get_value<T>();
2441 value = value.get_value<T>();
2445 int CommandLineRPC(int argc, char *argv[])
2452 while (argc > 1 && IsSwitchChar(argv[1][0]))
2460 throw runtime_error("too few parameters");
2461 string strMethod = argv[1];
2463 // Parameters default to strings
2465 for (int i = 2; i < argc; i++)
2466 params.push_back(argv[i]);
2467 int n = params.size();
2470 // Special case non-string parameter types
2472 if (strMethod == "setgenerate" && n > 0) ConvertTo<bool>(params[0]);
2473 if (strMethod == "setgenerate" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2474 if (strMethod == "sendtoaddress" && n > 1) ConvertTo<double>(params[1]);
2475 if (strMethod == "settxfee" && n > 0) ConvertTo<double>(params[0]);
2476 if (strMethod == "getreceivedbyaddress" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2477 if (strMethod == "getreceivedbyaccount" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2478 if (strMethod == "listreceivedbyaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2479 if (strMethod == "listreceivedbyaddress" && n > 1) ConvertTo<bool>(params[1]);
2480 if (strMethod == "listreceivedbyaccount" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2481 if (strMethod == "listreceivedbyaccount" && n > 1) ConvertTo<bool>(params[1]);
2482 if (strMethod == "getbalance" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2483 if (strMethod == "move" && n > 2) ConvertTo<double>(params[2]);
2484 if (strMethod == "move" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2485 if (strMethod == "sendfrom" && n > 2) ConvertTo<double>(params[2]);
2486 if (strMethod == "sendfrom" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2487 if (strMethod == "listtransactions" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2488 if (strMethod == "listtransactions" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2489 if (strMethod == "listaccounts" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2490 if (strMethod == "walletpassphrase" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2491 if (strMethod == "listsinceblock" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2492 if (strMethod == "sendmany" && n > 1)
2494 string s = params[1].get_str();
2496 if (!read_string(s, v) || v.type() != obj_type)
2497 throw runtime_error("type mismatch");
2498 params[1] = v.get_obj();
2500 if (strMethod == "sendmany" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2503 Object reply = CallRPC(strMethod, params);
2506 const Value& result = find_value(reply, "result");
2507 const Value& error = find_value(reply, "error");
2509 if (error.type() != null_type)
2512 strPrint = "error: " + write_string(error, false);
2513 int code = find_value(error.get_obj(), "code").get_int();
2519 if (result.type() == null_type)
2521 else if (result.type() == str_type)
2522 strPrint = result.get_str();
2524 strPrint = write_string(result, true);
2527 catch (std::exception& e)
2529 strPrint = string("error: ") + e.what();
2534 PrintException(NULL, "CommandLineRPC()");
2539 fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
2548 int main(int argc, char *argv[])
2551 // Turn off microsoft heap dump noise
2552 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
2553 _CrtSetReportFile(_CRT_WARN, CreateFile("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0));
2555 setbuf(stdin, NULL);
2556 setbuf(stdout, NULL);
2557 setbuf(stderr, NULL);
2561 if (argc >= 2 && string(argv[1]) == "-server")
2563 printf("server ready\n");
2564 ThreadRPCServer(NULL);
2568 return CommandLineRPC(argc, argv);
2571 catch (std::exception& e) {
2572 PrintException(&e, "main()");
2574 PrintException(NULL, "main()");