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 == "getblocknumber" || // deprecated
130 (strMethod.find("label") != string::npos))
132 if (strCommand != "" && strMethod != strCommand)
137 rpcfn_type pfn = (*mi).second;
138 if (setDone.insert(pfn).second)
139 (*pfn)(params, true);
141 catch (std::exception& e)
143 // Help text is returned in an exception
144 string strHelp = string(e.what());
145 if (strCommand == "")
146 if (strHelp.find('\n') != -1)
147 strHelp = strHelp.substr(0, strHelp.find('\n'));
148 strRet += strHelp + "\n";
152 strRet = strprintf("help: unknown command: %s\n", strCommand.c_str());
153 strRet = strRet.substr(0,strRet.size()-1);
158 Value stop(const Array& params, bool fHelp)
160 if (fHelp || params.size() != 0)
163 "Stop bitcoin server.");
165 // Shutdown will take long enough that the response should get back
166 CreateThread(Shutdown, NULL);
167 return "bitcoin server stopping";
169 throw runtime_error("NYI: cannot shut down GUI with RPC command");
174 Value getblockcount(const Array& params, bool fHelp)
176 if (fHelp || params.size() != 0)
179 "Returns the number of blocks in the longest block chain.");
186 Value getblocknumber(const Array& params, bool fHelp)
188 if (fHelp || params.size() != 0)
191 "Deprecated. Use getblockcount.");
197 Value getconnectioncount(const Array& params, bool fHelp)
199 if (fHelp || params.size() != 0)
201 "getconnectioncount\n"
202 "Returns the number of connections to other nodes.");
204 return (int)vNodes.size();
208 double GetDifficulty()
210 // Floating point number that is a multiple of the minimum difficulty,
211 // minimum difficulty = 1.0.
213 if (pindexBest == NULL)
215 int nShift = (pindexBest->nBits >> 24) & 0xff;
218 (double)0x0000ffff / (double)(pindexBest->nBits & 0x00ffffff);
234 Value getdifficulty(const Array& params, bool fHelp)
236 if (fHelp || params.size() != 0)
239 "Returns the proof-of-work difficulty as a multiple of the minimum difficulty.");
241 return GetDifficulty();
245 Value getgenerate(const Array& params, bool fHelp)
247 if (fHelp || params.size() != 0)
250 "Returns true or false.");
252 return (bool)fGenerateBitcoins;
256 Value setgenerate(const Array& params, bool fHelp)
258 if (fHelp || params.size() < 1 || params.size() > 2)
260 "setgenerate <generate> [genproclimit]\n"
261 "<generate> is true or false to turn generation on or off.\n"
262 "Generation is limited to [genproclimit] processors, -1 is unlimited.");
264 bool fGenerate = true;
265 if (params.size() > 0)
266 fGenerate = params[0].get_bool();
268 if (params.size() > 1)
270 int nGenProcLimit = params[1].get_int();
271 fLimitProcessors = (nGenProcLimit != -1);
272 WriteSetting("fLimitProcessors", fLimitProcessors);
273 if (nGenProcLimit != -1)
274 WriteSetting("nLimitProcessors", nLimitProcessors = nGenProcLimit);
275 if (nGenProcLimit == 0)
279 GenerateBitcoins(fGenerate, pwalletMain);
284 Value gethashespersec(const Array& params, bool fHelp)
286 if (fHelp || params.size() != 0)
289 "Returns a recent hashes per second performance measurement while generating.");
291 if (GetTimeMillis() - nHPSTimerStart > 8000)
292 return (boost::int64_t)0;
293 return (boost::int64_t)dHashesPerSec;
297 Value getinfo(const Array& params, bool fHelp)
299 if (fHelp || params.size() != 0)
302 "Returns an object containing various state info.");
305 obj.push_back(Pair("version", (int)VERSION));
306 obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance())));
307 obj.push_back(Pair("blocks", (int)nBestHeight));
308 obj.push_back(Pair("connections", (int)vNodes.size()));
309 obj.push_back(Pair("proxy", (fUseProxy ? addrProxy.ToStringIPPort() : string())));
310 obj.push_back(Pair("generate", (bool)fGenerateBitcoins));
311 obj.push_back(Pair("genproclimit", (int)(fLimitProcessors ? nLimitProcessors : -1)));
312 obj.push_back(Pair("difficulty", (double)GetDifficulty()));
313 obj.push_back(Pair("hashespersec", gethashespersec(params, false)));
314 obj.push_back(Pair("testnet", fTestNet));
315 obj.push_back(Pair("keypoololdest", (boost::int64_t)pwalletMain->GetOldestKeyPoolTime()));
316 obj.push_back(Pair("keypoolsize", pwalletMain->GetKeyPoolSize()));
317 obj.push_back(Pair("paytxfee", ValueFromAmount(nTransactionFee)));
318 if (pwalletMain->IsCrypted())
319 obj.push_back(Pair("unlocked_until", (boost::int64_t)nWalletUnlockTime));
320 obj.push_back(Pair("errors", GetWarnings("statusbar")));
325 Value getnewaddress(const Array& params, bool fHelp)
327 if (fHelp || params.size() > 1)
329 "getnewaddress [account]\n"
330 "Returns a new bitcoin address for receiving payments. "
331 "If [account] is specified (recommended), it is added to the address book "
332 "so payments received with the address will be credited to [account].");
334 // Parse the account first so we don't generate a key if there's an error
336 if (params.size() > 0)
337 strAccount = AccountFromValue(params[0]);
339 if (!pwalletMain->IsLocked())
340 pwalletMain->TopUpKeyPool();
342 // Generate a new key that is added to wallet
343 std::vector<unsigned char> newKey;
344 if (!pwalletMain->GetKeyFromPool(newKey, false))
345 throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
346 CBitcoinAddress address(newKey);
348 pwalletMain->SetAddressBookName(address, strAccount);
350 return address.ToString();
354 CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false)
356 CWalletDB walletdb(pwalletMain->strWalletFile);
359 walletdb.ReadAccount(strAccount, account);
361 bool bKeyUsed = false;
363 // Check if the current key has been used
364 if (!account.vchPubKey.empty())
366 CScript scriptPubKey;
367 scriptPubKey.SetBitcoinAddress(account.vchPubKey);
368 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
369 it != pwalletMain->mapWallet.end() && !account.vchPubKey.empty();
372 const CWalletTx& wtx = (*it).second;
373 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
374 if (txout.scriptPubKey == scriptPubKey)
379 // Generate a new key
380 if (account.vchPubKey.empty() || bForceNew || bKeyUsed)
382 if (!pwalletMain->GetKeyFromPool(account.vchPubKey, false))
383 throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
385 pwalletMain->SetAddressBookName(CBitcoinAddress(account.vchPubKey), strAccount);
386 walletdb.WriteAccount(strAccount, account);
389 return CBitcoinAddress(account.vchPubKey);
392 Value getaccountaddress(const Array& params, bool fHelp)
394 if (fHelp || params.size() != 1)
396 "getaccountaddress <account>\n"
397 "Returns the current bitcoin address for receiving payments to this account.");
399 // Parse the account first so we don't generate a key if there's an error
400 string strAccount = AccountFromValue(params[0]);
404 ret = GetAccountAddress(strAccount).ToString();
411 Value setaccount(const Array& params, bool fHelp)
413 if (fHelp || params.size() < 1 || params.size() > 2)
415 "setaccount <bitcoinaddress> <account>\n"
416 "Sets the account associated with the given address.");
418 CBitcoinAddress address(params[0].get_str());
419 if (!address.IsValid())
420 throw JSONRPCError(-5, "Invalid bitcoin address");
424 if (params.size() > 1)
425 strAccount = AccountFromValue(params[1]);
427 // Detect when changing the account of an address that is the 'unused current key' of another account:
428 if (pwalletMain->mapAddressBook.count(address))
430 string strOldAccount = pwalletMain->mapAddressBook[address];
431 if (address == GetAccountAddress(strOldAccount))
432 GetAccountAddress(strOldAccount, true);
435 pwalletMain->SetAddressBookName(address, strAccount);
441 Value getaccount(const Array& params, bool fHelp)
443 if (fHelp || params.size() != 1)
445 "getaccount <bitcoinaddress>\n"
446 "Returns the account associated with the given address.");
448 CBitcoinAddress address(params[0].get_str());
449 if (!address.IsValid())
450 throw JSONRPCError(-5, "Invalid bitcoin address");
453 map<CBitcoinAddress, string>::iterator mi = pwalletMain->mapAddressBook.find(address);
454 if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.empty())
455 strAccount = (*mi).second;
460 Value getaddressesbyaccount(const Array& params, bool fHelp)
462 if (fHelp || params.size() != 1)
464 "getaddressesbyaccount <account>\n"
465 "Returns the list of addresses for the given account.");
467 string strAccount = AccountFromValue(params[0]);
469 // Find all addresses that have the given account
471 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
473 const CBitcoinAddress& address = item.first;
474 const string& strName = item.second;
475 if (strName == strAccount)
476 ret.push_back(address.ToString());
481 Value settxfee(const Array& params, bool fHelp)
483 if (fHelp || params.size() < 1 || params.size() > 1)
485 "settxfee <amount>\n"
486 "<amount> is a real and is rounded to the nearest 0.00000001");
490 if (params[0].get_real() != 0.0)
491 nAmount = AmountFromValue(params[0]); // rejects 0.0 amounts
493 nTransactionFee = nAmount;
497 Value sendtoaddress(const Array& params, bool fHelp)
499 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
501 "sendtoaddress <bitcoinaddress> <amount> [comment] [comment-to]\n"
502 "<amount> is a real and is rounded to the nearest 0.00000001\n"
503 "requires wallet passphrase to be set with walletpassphrase first");
504 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
506 "sendtoaddress <bitcoinaddress> <amount> [comment] [comment-to]\n"
507 "<amount> is a real and is rounded to the nearest 0.00000001");
509 CBitcoinAddress address(params[0].get_str());
510 if (!address.IsValid())
511 throw JSONRPCError(-5, "Invalid bitcoin address");
514 int64 nAmount = AmountFromValue(params[1]);
518 if (params.size() > 2 && params[2].type() != null_type && !params[2].get_str().empty())
519 wtx.mapValue["comment"] = params[2].get_str();
520 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
521 wtx.mapValue["to"] = params[3].get_str();
523 if (pwalletMain->IsLocked())
524 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
526 string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
528 throw JSONRPCError(-4, strError);
530 return wtx.GetHash().GetHex();
533 static const string strMessageMagic = "Bitcoin Signed Message:\n";
535 Value signmessage(const Array& params, bool fHelp)
537 if (fHelp || params.size() != 2)
539 "signmessage <bitcoinaddress> <message>\n"
540 "Sign a message with the private key of an address");
542 if (pwalletMain->IsLocked())
543 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
545 string strAddress = params[0].get_str();
546 string strMessage = params[1].get_str();
548 CBitcoinAddress addr(strAddress);
550 throw JSONRPCError(-3, "Invalid address");
553 if (!pwalletMain->GetKey(addr, key))
554 throw JSONRPCError(-4, "Private key not available");
556 CDataStream ss(SER_GETHASH);
557 ss << strMessageMagic;
560 vector<unsigned char> vchSig;
561 if (!key.SignCompact(Hash(ss.begin(), ss.end()), vchSig))
562 throw JSONRPCError(-5, "Sign failed");
564 return EncodeBase64(&vchSig[0], vchSig.size());
567 Value verifymessage(const Array& params, bool fHelp)
569 if (fHelp || params.size() != 3)
571 "verifymessage <bitcoinaddress> <signature> <message>\n"
572 "Verify a signed message");
574 string strAddress = params[0].get_str();
575 string strSign = params[1].get_str();
576 string strMessage = params[2].get_str();
578 CBitcoinAddress addr(strAddress);
580 throw JSONRPCError(-3, "Invalid address");
582 bool fInvalid = false;
583 vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid);
586 throw JSONRPCError(-5, "Malformed base64 encoding");
588 CDataStream ss(SER_GETHASH);
589 ss << strMessageMagic;
593 if (!key.SetCompactSignature(Hash(ss.begin(), ss.end()), vchSig))
596 return (key.GetAddress() == addr);
600 Value getreceivedbyaddress(const Array& params, bool fHelp)
602 if (fHelp || params.size() < 1 || params.size() > 2)
604 "getreceivedbyaddress <bitcoinaddress> [minconf=1]\n"
605 "Returns the total amount received by <bitcoinaddress> in transactions with at least [minconf] confirmations.");
608 CBitcoinAddress address = CBitcoinAddress(params[0].get_str());
609 CScript scriptPubKey;
610 if (!address.IsValid())
611 throw JSONRPCError(-5, "Invalid bitcoin address");
612 scriptPubKey.SetBitcoinAddress(address);
613 if (!IsMine(*pwalletMain,scriptPubKey))
616 // Minimum confirmations
618 if (params.size() > 1)
619 nMinDepth = params[1].get_int();
623 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
625 const CWalletTx& wtx = (*it).second;
626 if (wtx.IsCoinBase() || !wtx.IsFinal())
629 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
630 if (txout.scriptPubKey == scriptPubKey)
631 if (wtx.GetDepthInMainChain() >= nMinDepth)
632 nAmount += txout.nValue;
635 return ValueFromAmount(nAmount);
639 void GetAccountAddresses(string strAccount, set<CBitcoinAddress>& setAddress)
641 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
643 const CBitcoinAddress& address = item.first;
644 const string& strName = item.second;
645 if (strName == strAccount)
646 setAddress.insert(address);
651 Value getreceivedbyaccount(const Array& params, bool fHelp)
653 if (fHelp || params.size() < 1 || params.size() > 2)
655 "getreceivedbyaccount <account> [minconf=1]\n"
656 "Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.");
658 // Minimum confirmations
660 if (params.size() > 1)
661 nMinDepth = params[1].get_int();
663 // Get the set of pub keys that have the label
664 string strAccount = AccountFromValue(params[0]);
665 set<CBitcoinAddress> setAddress;
666 GetAccountAddresses(strAccount, setAddress);
670 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
672 const CWalletTx& wtx = (*it).second;
673 if (wtx.IsCoinBase() || !wtx.IsFinal())
676 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
678 CBitcoinAddress address;
679 if (ExtractAddress(txout.scriptPubKey, pwalletMain, address) && setAddress.count(address))
680 if (wtx.GetDepthInMainChain() >= nMinDepth)
681 nAmount += txout.nValue;
685 return (double)nAmount / (double)COIN;
689 int64 GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth)
693 // Tally wallet transactions
694 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
696 const CWalletTx& wtx = (*it).second;
700 int64 nGenerated, nReceived, nSent, nFee;
701 wtx.GetAccountAmounts(strAccount, nGenerated, nReceived, nSent, nFee);
703 if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
704 nBalance += nReceived;
705 nBalance += nGenerated - nSent - nFee;
708 // Tally internal accounting entries
709 nBalance += walletdb.GetAccountCreditDebit(strAccount);
714 int64 GetAccountBalance(const string& strAccount, int nMinDepth)
716 CWalletDB walletdb(pwalletMain->strWalletFile);
717 return GetAccountBalance(walletdb, strAccount, nMinDepth);
721 Value getbalance(const Array& params, bool fHelp)
723 if (fHelp || params.size() > 2)
725 "getbalance [account] [minconf=1]\n"
726 "If [account] is not specified, returns the server's total available balance.\n"
727 "If [account] is specified, returns the balance in the account.");
729 if (params.size() == 0)
730 return ValueFromAmount(pwalletMain->GetBalance());
733 if (params.size() > 1)
734 nMinDepth = params[1].get_int();
736 if (params[0].get_str() == "*") {
737 // Calculate total balance a different way from GetBalance()
738 // (GetBalance() sums up all unspent TxOuts)
739 // getbalance and getbalance '*' should always return the same number.
741 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
743 const CWalletTx& wtx = (*it).second;
747 int64 allGeneratedImmature, allGeneratedMature, allFee;
748 allGeneratedImmature = allGeneratedMature = allFee = 0;
749 string strSentAccount;
750 list<pair<CBitcoinAddress, int64> > listReceived;
751 list<pair<CBitcoinAddress, int64> > listSent;
752 wtx.GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount);
753 if (wtx.GetDepthInMainChain() >= nMinDepth)
754 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listReceived)
755 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)
1113 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1116 if (pwalletMain->mapAddressBook.count(r.first))
1117 account = pwalletMain->mapAddressBook[r.first];
1118 if (fAllAccounts || (account == strAccount))
1121 entry.push_back(Pair("account", account));
1122 entry.push_back(Pair("address", r.first.ToString()));
1123 entry.push_back(Pair("category", "receive"));
1124 entry.push_back(Pair("amount", ValueFromAmount(r.second)));
1126 WalletTxToJSON(wtx, entry);
1127 ret.push_back(entry);
1132 void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret)
1134 bool fAllAccounts = (strAccount == string("*"));
1136 if (fAllAccounts || acentry.strAccount == strAccount)
1139 entry.push_back(Pair("account", acentry.strAccount));
1140 entry.push_back(Pair("category", "move"));
1141 entry.push_back(Pair("time", (boost::int64_t)acentry.nTime));
1142 entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
1143 entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
1144 entry.push_back(Pair("comment", acentry.strComment));
1145 ret.push_back(entry);
1149 Value listtransactions(const Array& params, bool fHelp)
1151 if (fHelp || params.size() > 3)
1152 throw runtime_error(
1153 "listtransactions [account] [count=10] [from=0]\n"
1154 "Returns up to [count] most recent transactions skipping the first [from] transactions for account [account].");
1156 string strAccount = "*";
1157 if (params.size() > 0)
1158 strAccount = params[0].get_str();
1160 if (params.size() > 1)
1161 nCount = params[1].get_int();
1163 if (params.size() > 2)
1164 nFrom = params[2].get_int();
1167 CWalletDB walletdb(pwalletMain->strWalletFile);
1169 // Firs: get all CWalletTx and CAccountingEntry into a sorted-by-time multimap:
1170 typedef pair<CWalletTx*, CAccountingEntry*> TxPair;
1171 typedef multimap<int64, TxPair > TxItems;
1174 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1176 CWalletTx* wtx = &((*it).second);
1177 txByTime.insert(make_pair(wtx->GetTxTime(), TxPair(wtx, (CAccountingEntry*)0)));
1179 list<CAccountingEntry> acentries;
1180 walletdb.ListAccountCreditDebit(strAccount, acentries);
1181 BOOST_FOREACH(CAccountingEntry& entry, acentries)
1183 txByTime.insert(make_pair(entry.nTime, TxPair((CWalletTx*)0, &entry)));
1186 // Now: iterate backwards until we have nCount items to return:
1187 TxItems::reverse_iterator it = txByTime.rbegin();
1188 if (txByTime.size() > nFrom) std::advance(it, nFrom);
1189 for (; it != txByTime.rend(); ++it)
1191 CWalletTx *const pwtx = (*it).second.first;
1193 ListTransactions(*pwtx, strAccount, 0, true, ret);
1194 CAccountingEntry *const pacentry = (*it).second.second;
1196 AcentryToJSON(*pacentry, strAccount, ret);
1198 if (ret.size() >= nCount) break;
1200 // ret is now newest to oldest
1202 // Make sure we return only last nCount items (sends-to-self might give us an extra):
1203 if (ret.size() > nCount)
1205 Array::iterator last = ret.begin();
1206 std::advance(last, nCount);
1207 ret.erase(last, ret.end());
1209 std::reverse(ret.begin(), ret.end()); // oldest to newest
1214 Value listaccounts(const Array& params, bool fHelp)
1216 if (fHelp || params.size() > 1)
1217 throw runtime_error(
1218 "listaccounts [minconf=1]\n"
1219 "Returns Object that has account names as keys, account balances as values.");
1222 if (params.size() > 0)
1223 nMinDepth = params[0].get_int();
1225 map<string, int64> mapAccountBalances;
1226 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& entry, pwalletMain->mapAddressBook) {
1227 if (pwalletMain->HaveKey(entry.first)) // This address belongs to me
1228 mapAccountBalances[entry.second] = 0;
1231 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1233 const CWalletTx& wtx = (*it).second;
1234 int64 nGeneratedImmature, nGeneratedMature, nFee;
1235 string strSentAccount;
1236 list<pair<CBitcoinAddress, int64> > listReceived;
1237 list<pair<CBitcoinAddress, int64> > listSent;
1238 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1239 mapAccountBalances[strSentAccount] -= nFee;
1240 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1241 mapAccountBalances[strSentAccount] -= s.second;
1242 if (wtx.GetDepthInMainChain() >= nMinDepth)
1244 mapAccountBalances[""] += nGeneratedMature;
1245 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1246 if (pwalletMain->mapAddressBook.count(r.first))
1247 mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second;
1249 mapAccountBalances[""] += r.second;
1253 list<CAccountingEntry> acentries;
1254 CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
1255 BOOST_FOREACH(const CAccountingEntry& entry, acentries)
1256 mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
1259 BOOST_FOREACH(const PAIRTYPE(string, int64)& accountBalance, mapAccountBalances) {
1260 ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
1265 Value listsinceblock(const Array& params, bool fHelp)
1268 throw runtime_error(
1269 "listsinceblock [blockid] [target-confirmations]\n"
1270 "Get all transactions in blocks since block [blockid], or all transactions if omitted");
1272 CBlockIndex *pindex = NULL;
1273 int target_confirms = 1;
1275 if (params.size() > 0)
1277 uint256 blockId = 0;
1279 blockId.SetHex(params[0].get_str());
1280 pindex = CBlockLocator(blockId).GetBlockIndex();
1283 if (params.size() > 1)
1285 target_confirms = params[1].get_int();
1287 if (target_confirms < 1)
1288 throw JSONRPCError(-8, "Invalid parameter");
1291 int depth = pindex ? (1 + nBestHeight - pindex->nHeight) : -1;
1295 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++)
1297 CWalletTx tx = (*it).second;
1299 if (depth == -1 || tx.GetDepthInMainChain() < depth)
1300 ListTransactions(tx, "*", 0, true, transactions);
1305 if (target_confirms == 1)
1308 lastblock = hashBestChain;
1312 int target_height = pindexBest->nHeight + 1 - target_confirms;
1315 for (block = pindexBest;
1316 block && block->nHeight > target_height;
1317 block = block->pprev);
1319 lastblock = block ? block->GetBlockHash() : 0;
1323 ret.push_back(Pair("transactions", transactions));
1324 ret.push_back(Pair("lastblock", lastblock.GetHex()));
1329 Value gettransaction(const Array& params, bool fHelp)
1331 if (fHelp || params.size() != 1)
1332 throw runtime_error(
1333 "gettransaction <txid>\n"
1334 "Get detailed information about <txid>");
1337 hash.SetHex(params[0].get_str());
1341 if (!pwalletMain->mapWallet.count(hash))
1342 throw JSONRPCError(-5, "Invalid or non-wallet transaction id");
1343 const CWalletTx& wtx = pwalletMain->mapWallet[hash];
1345 int64 nCredit = wtx.GetCredit();
1346 int64 nDebit = wtx.GetDebit();
1347 int64 nNet = nCredit - nDebit;
1348 int64 nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0);
1350 entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
1352 entry.push_back(Pair("fee", ValueFromAmount(nFee)));
1354 WalletTxToJSON(pwalletMain->mapWallet[hash], entry);
1357 ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details);
1358 entry.push_back(Pair("details", details));
1364 Value backupwallet(const Array& params, bool fHelp)
1366 if (fHelp || params.size() != 1)
1367 throw runtime_error(
1368 "backupwallet <destination>\n"
1369 "Safely copies wallet.dat to destination, which can be a directory or a path with filename.");
1371 string strDest = params[0].get_str();
1372 BackupWallet(*pwalletMain, strDest);
1378 Value keypoolrefill(const Array& params, bool fHelp)
1380 if (pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1381 throw runtime_error(
1383 "Fills the keypool, requires wallet passphrase to be set.");
1384 if (!pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1385 throw runtime_error(
1387 "Fills the keypool.");
1389 if (pwalletMain->IsLocked())
1390 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
1392 pwalletMain->TopUpKeyPool();
1394 if (pwalletMain->GetKeyPoolSize() < GetArg("-keypool", 100))
1395 throw JSONRPCError(-4, "Error refreshing keypool.");
1401 void ThreadTopUpKeyPool(void* parg)
1403 pwalletMain->TopUpKeyPool();
1406 void ThreadCleanWalletPassphrase(void* parg)
1408 int64 nMyWakeTime = GetTime() + *((int*)parg);
1410 if (nWalletUnlockTime == 0)
1412 CRITICAL_BLOCK(cs_nWalletUnlockTime)
1414 nWalletUnlockTime = nMyWakeTime;
1417 while (GetTime() < nWalletUnlockTime)
1418 Sleep(GetTime() - nWalletUnlockTime);
1420 CRITICAL_BLOCK(cs_nWalletUnlockTime)
1422 nWalletUnlockTime = 0;
1427 CRITICAL_BLOCK(cs_nWalletUnlockTime)
1429 if (nWalletUnlockTime < nMyWakeTime)
1430 nWalletUnlockTime = nMyWakeTime;
1436 pwalletMain->Lock();
1441 Value walletpassphrase(const Array& params, bool fHelp)
1443 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1444 throw runtime_error(
1445 "walletpassphrase <passphrase> <timeout>\n"
1446 "Stores the wallet decryption key in memory for <timeout> seconds.");
1449 if (!pwalletMain->IsCrypted())
1450 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
1452 if (!pwalletMain->IsLocked())
1453 throw JSONRPCError(-17, "Error: Wallet is already unlocked.");
1455 // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
1456 string strWalletPass;
1457 strWalletPass.reserve(100);
1458 mlock(&strWalletPass[0], strWalletPass.capacity());
1459 strWalletPass = params[0].get_str();
1461 if (strWalletPass.length() > 0)
1463 if (!pwalletMain->Unlock(strWalletPass))
1465 fill(strWalletPass.begin(), strWalletPass.end(), '\0');
1466 munlock(&strWalletPass[0], strWalletPass.capacity());
1467 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1469 fill(strWalletPass.begin(), strWalletPass.end(), '\0');
1470 munlock(&strWalletPass[0], strWalletPass.capacity());
1473 throw runtime_error(
1474 "walletpassphrase <passphrase> <timeout>\n"
1475 "Stores the wallet decryption key in memory for <timeout> seconds.");
1477 CreateThread(ThreadTopUpKeyPool, NULL);
1478 int* pnSleepTime = new int(params[1].get_int());
1479 CreateThread(ThreadCleanWalletPassphrase, pnSleepTime);
1485 Value walletpassphrasechange(const Array& params, bool fHelp)
1487 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1488 throw runtime_error(
1489 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1490 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1493 if (!pwalletMain->IsCrypted())
1494 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
1496 string strOldWalletPass;
1497 strOldWalletPass.reserve(100);
1498 mlock(&strOldWalletPass[0], strOldWalletPass.capacity());
1499 strOldWalletPass = params[0].get_str();
1501 string strNewWalletPass;
1502 strNewWalletPass.reserve(100);
1503 mlock(&strNewWalletPass[0], strNewWalletPass.capacity());
1504 strNewWalletPass = params[1].get_str();
1506 if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
1507 throw runtime_error(
1508 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1509 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1511 if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
1513 fill(strOldWalletPass.begin(), strOldWalletPass.end(), '\0');
1514 fill(strNewWalletPass.begin(), strNewWalletPass.end(), '\0');
1515 munlock(&strOldWalletPass[0], strOldWalletPass.capacity());
1516 munlock(&strNewWalletPass[0], strNewWalletPass.capacity());
1517 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1519 fill(strNewWalletPass.begin(), strNewWalletPass.end(), '\0');
1520 fill(strOldWalletPass.begin(), strOldWalletPass.end(), '\0');
1521 munlock(&strOldWalletPass[0], strOldWalletPass.capacity());
1522 munlock(&strNewWalletPass[0], strNewWalletPass.capacity());
1528 Value walletlock(const Array& params, bool fHelp)
1530 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
1531 throw runtime_error(
1533 "Removes the wallet encryption key from memory, locking the wallet.\n"
1534 "After calling this method, you will need to call walletpassphrase again\n"
1535 "before being able to call any methods which require the wallet to be unlocked.");
1538 if (!pwalletMain->IsCrypted())
1539 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletlock was called.");
1541 pwalletMain->Lock();
1542 CRITICAL_BLOCK(cs_nWalletUnlockTime)
1544 nWalletUnlockTime = 0;
1551 Value encryptwallet(const Array& params, bool fHelp)
1553 if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
1554 throw runtime_error(
1555 "encryptwallet <passphrase>\n"
1556 "Encrypts the wallet with <passphrase>.");
1559 if (pwalletMain->IsCrypted())
1560 throw JSONRPCError(-15, "Error: running with an encrypted wallet, but encryptwallet was called.");
1563 // shutting down via RPC while the GUI is running does not work (yet):
1564 throw runtime_error("Not Yet Implemented: use GUI to encrypt wallet, not RPC command");
1567 string strWalletPass;
1568 strWalletPass.reserve(100);
1569 mlock(&strWalletPass[0], strWalletPass.capacity());
1570 strWalletPass = params[0].get_str();
1572 if (strWalletPass.length() < 1)
1573 throw runtime_error(
1574 "encryptwallet <passphrase>\n"
1575 "Encrypts the wallet with <passphrase>.");
1577 if (!pwalletMain->EncryptWallet(strWalletPass))
1579 fill(strWalletPass.begin(), strWalletPass.end(), '\0');
1580 munlock(&strWalletPass[0], strWalletPass.capacity());
1581 throw JSONRPCError(-16, "Error: Failed to encrypt the wallet.");
1583 fill(strWalletPass.begin(), strWalletPass.end(), '\0');
1584 munlock(&strWalletPass[0], strWalletPass.capacity());
1586 // BDB seems to have a bad habit of writing old data into
1587 // slack space in .dat files; that is bad if the old data is
1588 // unencrypted private keys. So:
1589 CreateThread(Shutdown, NULL);
1590 return "wallet encrypted; bitcoin server stopping, restart to run with encrypted wallet";
1594 Value validateaddress(const Array& params, bool fHelp)
1596 if (fHelp || params.size() != 1)
1597 throw runtime_error(
1598 "validateaddress <bitcoinaddress>\n"
1599 "Return information about <bitcoinaddress>.");
1601 CBitcoinAddress address(params[0].get_str());
1602 bool isValid = address.IsValid();
1605 ret.push_back(Pair("isvalid", isValid));
1608 // Call Hash160ToAddress() so we always return current ADDRESSVERSION
1609 // version of the address:
1610 string currentAddress = address.ToString();
1611 ret.push_back(Pair("address", currentAddress));
1612 ret.push_back(Pair("ismine", (pwalletMain->HaveKey(address) > 0)));
1613 if (pwalletMain->mapAddressBook.count(address))
1614 ret.push_back(Pair("account", pwalletMain->mapAddressBook[address]));
1620 Value getwork(const Array& params, bool fHelp)
1622 if (fHelp || params.size() > 1)
1623 throw runtime_error(
1625 "If [data] is not specified, returns formatted hash data to work on:\n"
1626 " \"midstate\" : precomputed hash state after hashing the first half of the data (DEPRECATED)\n" // deprecated
1627 " \"data\" : block data\n"
1628 " \"hash1\" : formatted hash buffer for second hash (DEPRECATED)\n" // deprecated
1629 " \"target\" : little endian hash target\n"
1630 "If [data] is specified, tries to solve the block and returns true if it was successful.");
1633 throw JSONRPCError(-9, "Bitcoin is not connected!");
1635 if (IsInitialBlockDownload())
1636 throw JSONRPCError(-10, "Bitcoin is downloading blocks...");
1638 typedef map<uint256, pair<CBlock*, CScript> > mapNewBlock_t;
1639 static mapNewBlock_t mapNewBlock;
1640 static vector<CBlock*> vNewBlock;
1641 static CReserveKey reservekey(pwalletMain);
1643 if (params.size() == 0)
1646 static unsigned int nTransactionsUpdatedLast;
1647 static CBlockIndex* pindexPrev;
1648 static int64 nStart;
1649 static CBlock* pblock;
1650 if (pindexPrev != pindexBest ||
1651 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60))
1653 if (pindexPrev != pindexBest)
1655 // Deallocate old blocks since they're obsolete now
1656 mapNewBlock.clear();
1657 BOOST_FOREACH(CBlock* pblock, vNewBlock)
1661 nTransactionsUpdatedLast = nTransactionsUpdated;
1662 pindexPrev = pindexBest;
1666 pblock = CreateNewBlock(reservekey);
1668 throw JSONRPCError(-7, "Out of memory");
1669 vNewBlock.push_back(pblock);
1673 pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
1676 // Update nExtraNonce
1677 static unsigned int nExtraNonce = 0;
1678 IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
1681 mapNewBlock[pblock->hashMerkleRoot] = make_pair(pblock, pblock->vtx[0].vin[0].scriptSig);
1683 // Prebuild hash buffers
1687 FormatHashBuffers(pblock, pmidstate, pdata, phash1);
1689 uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
1692 result.push_back(Pair("midstate", HexStr(BEGIN(pmidstate), END(pmidstate)))); // deprecated
1693 result.push_back(Pair("data", HexStr(BEGIN(pdata), END(pdata))));
1694 result.push_back(Pair("hash1", HexStr(BEGIN(phash1), END(phash1)))); // deprecated
1695 result.push_back(Pair("target", HexStr(BEGIN(hashTarget), END(hashTarget))));
1701 vector<unsigned char> vchData = ParseHex(params[0].get_str());
1702 if (vchData.size() != 128)
1703 throw JSONRPCError(-8, "Invalid parameter");
1704 CBlock* pdata = (CBlock*)&vchData[0];
1707 for (int i = 0; i < 128/4; i++)
1708 ((unsigned int*)pdata)[i] = ByteReverse(((unsigned int*)pdata)[i]);
1711 if (!mapNewBlock.count(pdata->hashMerkleRoot))
1713 CBlock* pblock = mapNewBlock[pdata->hashMerkleRoot].first;
1715 pblock->nTime = pdata->nTime;
1716 pblock->nNonce = pdata->nNonce;
1717 pblock->vtx[0].vin[0].scriptSig = mapNewBlock[pdata->hashMerkleRoot].second;
1718 pblock->hashMerkleRoot = pblock->BuildMerkleTree();
1720 return CheckWork(pblock, *pwalletMain, reservekey);
1725 Value getmemorypool(const Array& params, bool fHelp)
1727 if (fHelp || params.size() > 1)
1728 throw runtime_error(
1729 "getmemorypool [data]\n"
1730 "If [data] is not specified, returns data needed to construct a block to work on:\n"
1731 " \"version\" : block version\n"
1732 " \"previousblockhash\" : hash of current highest block\n"
1733 " \"transactions\" : contents of non-coinbase transactions that should be included in the next block\n"
1734 " \"coinbasevalue\" : maximum allowable input to coinbase transaction, including the generation award and transaction fees\n"
1735 " \"time\" : timestamp appropriate for next block\n"
1736 " \"bits\" : compressed target of next block\n"
1737 "If [data] is specified, tries to solve the block and returns true if it was successful.");
1739 if (params.size() == 0)
1742 throw JSONRPCError(-9, "Bitcoin is not connected!");
1744 if (IsInitialBlockDownload())
1745 throw JSONRPCError(-10, "Bitcoin is downloading blocks...");
1747 static CReserveKey reservekey(pwalletMain);
1750 static unsigned int nTransactionsUpdatedLast;
1751 static CBlockIndex* pindexPrev;
1752 static int64 nStart;
1753 static CBlock* pblock;
1754 if (pindexPrev != pindexBest ||
1755 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 5))
1757 nTransactionsUpdatedLast = nTransactionsUpdated;
1758 pindexPrev = pindexBest;
1764 pblock = CreateNewBlock(reservekey);
1766 throw JSONRPCError(-7, "Out of memory");
1770 pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
1774 BOOST_FOREACH(CTransaction tx, pblock->vtx) {
1781 transactions.push_back(HexStr(ssTx.begin(), ssTx.end()));
1785 result.push_back(Pair("version", pblock->nVersion));
1786 result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex()));
1787 result.push_back(Pair("transactions", transactions));
1788 result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue));
1789 result.push_back(Pair("time", (int64_t)pblock->nTime));
1795 uBits.nBits = htonl((int32_t)pblock->nBits);
1796 result.push_back(Pair("bits", HexStr(BEGIN(uBits.cBits), END(uBits.cBits))));
1803 CDataStream ssBlock(ParseHex(params[0].get_str()));
1807 return ProcessBlock(NULL, &pblock);
1825 pair<string, rpcfn_type> pCallTable[] =
1827 make_pair("help", &help),
1828 make_pair("stop", &stop),
1829 make_pair("getblockcount", &getblockcount),
1830 make_pair("getblocknumber", &getblocknumber),
1831 make_pair("getconnectioncount", &getconnectioncount),
1832 make_pair("getdifficulty", &getdifficulty),
1833 make_pair("getgenerate", &getgenerate),
1834 make_pair("setgenerate", &setgenerate),
1835 make_pair("gethashespersec", &gethashespersec),
1836 make_pair("getinfo", &getinfo),
1837 make_pair("getnewaddress", &getnewaddress),
1838 make_pair("getaccountaddress", &getaccountaddress),
1839 make_pair("setaccount", &setaccount),
1840 make_pair("getaccount", &getaccount),
1841 make_pair("getaddressesbyaccount", &getaddressesbyaccount),
1842 make_pair("sendtoaddress", &sendtoaddress),
1843 make_pair("getreceivedbyaddress", &getreceivedbyaddress),
1844 make_pair("getreceivedbyaccount", &getreceivedbyaccount),
1845 make_pair("listreceivedbyaddress", &listreceivedbyaddress),
1846 make_pair("listreceivedbyaccount", &listreceivedbyaccount),
1847 make_pair("backupwallet", &backupwallet),
1848 make_pair("keypoolrefill", &keypoolrefill),
1849 make_pair("walletpassphrase", &walletpassphrase),
1850 make_pair("walletpassphrasechange", &walletpassphrasechange),
1851 make_pair("walletlock", &walletlock),
1852 make_pair("encryptwallet", &encryptwallet),
1853 make_pair("validateaddress", &validateaddress),
1854 make_pair("getbalance", &getbalance),
1855 make_pair("move", &movecmd),
1856 make_pair("sendfrom", &sendfrom),
1857 make_pair("sendmany", &sendmany),
1858 make_pair("gettransaction", &gettransaction),
1859 make_pair("listtransactions", &listtransactions),
1860 make_pair("signmessage", &signmessage),
1861 make_pair("verifymessage", &verifymessage),
1862 make_pair("getwork", &getwork),
1863 make_pair("listaccounts", &listaccounts),
1864 make_pair("settxfee", &settxfee),
1865 make_pair("getmemorypool", &getmemorypool),
1866 make_pair("listsinceblock", &listsinceblock),
1868 map<string, rpcfn_type> mapCallTable(pCallTable, pCallTable + sizeof(pCallTable)/sizeof(pCallTable[0]));
1870 string pAllowInSafeMode[] =
1875 "getblocknumber", // deprecated
1876 "getconnectioncount",
1883 "getaccountaddress",
1885 "getaddressesbyaccount",
1894 set<string> setAllowInSafeMode(pAllowInSafeMode, pAllowInSafeMode + sizeof(pAllowInSafeMode)/sizeof(pAllowInSafeMode[0]));
1902 // This ain't Apache. We're just using HTTP header for the length field
1903 // and to be compatible with other JSON-RPC implementations.
1906 string HTTPPost(const string& strMsg, const map<string,string>& mapRequestHeaders)
1909 s << "POST / HTTP/1.1\r\n"
1910 << "User-Agent: bitcoin-json-rpc/" << FormatFullVersion() << "\r\n"
1911 << "Host: 127.0.0.1\r\n"
1912 << "Content-Type: application/json\r\n"
1913 << "Content-Length: " << strMsg.size() << "\r\n"
1914 << "Connection: close\r\n"
1915 << "Accept: application/json\r\n";
1916 BOOST_FOREACH(const PAIRTYPE(string, string)& item, mapRequestHeaders)
1917 s << item.first << ": " << item.second << "\r\n";
1918 s << "\r\n" << strMsg;
1923 string rfc1123Time()
1928 struct tm* now_gmt = gmtime(&now);
1929 string locale(setlocale(LC_TIME, NULL));
1930 setlocale(LC_TIME, "C"); // we want posix (aka "C") weekday/month strings
1931 strftime(buffer, sizeof(buffer), "%a, %d %b %Y %H:%M:%S +0000", now_gmt);
1932 setlocale(LC_TIME, locale.c_str());
1933 return string(buffer);
1936 static string HTTPReply(int nStatus, const string& strMsg)
1939 return strprintf("HTTP/1.0 401 Authorization Required\r\n"
1941 "Server: bitcoin-json-rpc/%s\r\n"
1942 "WWW-Authenticate: Basic realm=\"jsonrpc\"\r\n"
1943 "Content-Type: text/html\r\n"
1944 "Content-Length: 296\r\n"
1946 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\r\n"
1947 "\"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd\">\r\n"
1950 "<TITLE>Error</TITLE>\r\n"
1951 "<META HTTP-EQUIV='Content-Type' CONTENT='text/html; charset=ISO-8859-1'>\r\n"
1953 "<BODY><H1>401 Unauthorized.</H1></BODY>\r\n"
1954 "</HTML>\r\n", rfc1123Time().c_str(), FormatFullVersion().c_str());
1955 const char *cStatus;
1956 if (nStatus == 200) cStatus = "OK";
1957 else if (nStatus == 400) cStatus = "Bad Request";
1958 else if (nStatus == 403) cStatus = "Forbidden";
1959 else if (nStatus == 404) cStatus = "Not Found";
1960 else if (nStatus == 500) cStatus = "Internal Server Error";
1963 "HTTP/1.1 %d %s\r\n"
1965 "Connection: close\r\n"
1966 "Content-Length: %d\r\n"
1967 "Content-Type: application/json\r\n"
1968 "Server: bitcoin-json-rpc/%s\r\n"
1973 rfc1123Time().c_str(),
1975 FormatFullVersion().c_str(),
1979 int ReadHTTPStatus(std::basic_istream<char>& stream)
1982 getline(stream, str);
1983 vector<string> vWords;
1984 boost::split(vWords, str, boost::is_any_of(" "));
1985 if (vWords.size() < 2)
1987 return atoi(vWords[1].c_str());
1990 int ReadHTTPHeader(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet)
1996 std::getline(stream, str);
1997 if (str.empty() || str == "\r")
1999 string::size_type nColon = str.find(":");
2000 if (nColon != string::npos)
2002 string strHeader = str.substr(0, nColon);
2003 boost::trim(strHeader);
2004 boost::to_lower(strHeader);
2005 string strValue = str.substr(nColon+1);
2006 boost::trim(strValue);
2007 mapHeadersRet[strHeader] = strValue;
2008 if (strHeader == "content-length")
2009 nLen = atoi(strValue.c_str());
2015 int ReadHTTP(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet, string& strMessageRet)
2017 mapHeadersRet.clear();
2021 int nStatus = ReadHTTPStatus(stream);
2024 int nLen = ReadHTTPHeader(stream, mapHeadersRet);
2025 if (nLen < 0 || nLen > MAX_SIZE)
2031 vector<char> vch(nLen);
2032 stream.read(&vch[0], nLen);
2033 strMessageRet = string(vch.begin(), vch.end());
2039 bool HTTPAuthorized(map<string, string>& mapHeaders)
2041 string strAuth = mapHeaders["authorization"];
2042 if (strAuth.substr(0,6) != "Basic ")
2044 string strUserPass64 = strAuth.substr(6); boost::trim(strUserPass64);
2045 string strUserPass = DecodeBase64(strUserPass64);
2046 string::size_type nColon = strUserPass.find(":");
2047 if (nColon == string::npos)
2049 string strUser = strUserPass.substr(0, nColon);
2050 string strPassword = strUserPass.substr(nColon+1);
2051 return (strUser == mapArgs["-rpcuser"] && strPassword == mapArgs["-rpcpassword"]);
2055 // JSON-RPC protocol. Bitcoin speaks version 1.0 for maximum compatibility,
2056 // but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
2057 // unspecified (HTTP errors and contents of 'error').
2059 // 1.0 spec: http://json-rpc.org/wiki/specification
2060 // 1.2 spec: http://groups.google.com/group/json-rpc/web/json-rpc-over-http
2061 // http://www.codeproject.com/KB/recipes/JSON_Spirit.aspx
2064 string JSONRPCRequest(const string& strMethod, const Array& params, const Value& id)
2067 request.push_back(Pair("method", strMethod));
2068 request.push_back(Pair("params", params));
2069 request.push_back(Pair("id", id));
2070 return write_string(Value(request), false) + "\n";
2073 string JSONRPCReply(const Value& result, const Value& error, const Value& id)
2076 if (error.type() != null_type)
2077 reply.push_back(Pair("result", Value::null));
2079 reply.push_back(Pair("result", result));
2080 reply.push_back(Pair("error", error));
2081 reply.push_back(Pair("id", id));
2082 return write_string(Value(reply), false) + "\n";
2085 void ErrorReply(std::ostream& stream, const Object& objError, const Value& id)
2087 // Send error reply from json-rpc error object
2089 int code = find_value(objError, "code").get_int();
2090 if (code == -32600) nStatus = 400;
2091 else if (code == -32601) nStatus = 404;
2092 string strReply = JSONRPCReply(Value::null, objError, id);
2093 stream << HTTPReply(nStatus, strReply) << std::flush;
2096 bool ClientAllowed(const string& strAddress)
2098 if (strAddress == asio::ip::address_v4::loopback().to_string())
2100 const vector<string>& vAllow = mapMultiArgs["-rpcallowip"];
2101 BOOST_FOREACH(string strAllow, vAllow)
2102 if (WildcardMatch(strAddress, strAllow))
2109 // IOStream device that speaks SSL but can also speak non-SSL
2111 class SSLIOStreamDevice : public iostreams::device<iostreams::bidirectional> {
2113 SSLIOStreamDevice(SSLStream &streamIn, bool fUseSSLIn) : stream(streamIn)
2115 fUseSSL = fUseSSLIn;
2116 fNeedHandshake = fUseSSLIn;
2119 void handshake(ssl::stream_base::handshake_type role)
2121 if (!fNeedHandshake) return;
2122 fNeedHandshake = false;
2123 stream.handshake(role);
2125 std::streamsize read(char* s, std::streamsize n)
2127 handshake(ssl::stream_base::server); // HTTPS servers read first
2128 if (fUseSSL) return stream.read_some(asio::buffer(s, n));
2129 return stream.next_layer().read_some(asio::buffer(s, n));
2131 std::streamsize write(const char* s, std::streamsize n)
2133 handshake(ssl::stream_base::client); // HTTPS clients write first
2134 if (fUseSSL) return asio::write(stream, asio::buffer(s, n));
2135 return asio::write(stream.next_layer(), asio::buffer(s, n));
2137 bool connect(const std::string& server, const std::string& port)
2139 ip::tcp::resolver resolver(stream.get_io_service());
2140 ip::tcp::resolver::query query(server.c_str(), port.c_str());
2141 ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
2142 ip::tcp::resolver::iterator end;
2143 boost::system::error_code error = asio::error::host_not_found;
2144 while (error && endpoint_iterator != end)
2146 stream.lowest_layer().close();
2147 stream.lowest_layer().connect(*endpoint_iterator++, error);
2155 bool fNeedHandshake;
2161 void ThreadRPCServer(void* parg)
2163 IMPLEMENT_RANDOMIZE_STACK(ThreadRPCServer(parg));
2166 vnThreadsRunning[4]++;
2167 ThreadRPCServer2(parg);
2168 vnThreadsRunning[4]--;
2170 catch (std::exception& e) {
2171 vnThreadsRunning[4]--;
2172 PrintException(&e, "ThreadRPCServer()");
2174 vnThreadsRunning[4]--;
2175 PrintException(NULL, "ThreadRPCServer()");
2177 printf("ThreadRPCServer exiting\n");
2180 void ThreadRPCServer2(void* parg)
2182 printf("ThreadRPCServer started\n");
2184 if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
2186 string strWhatAmI = "To use bitcoind";
2187 if (mapArgs.count("-server"))
2188 strWhatAmI = strprintf(_("To use the %s option"), "\"-server\"");
2189 else if (mapArgs.count("-daemon"))
2190 strWhatAmI = strprintf(_("To use the %s option"), "\"-daemon\"");
2192 _("Error: %s, you must set rpcpassword=<password>\nin the configuration file: %s\n"
2193 "If the file does not exist, create it with owner-readable-only file permissions.\n"),
2195 GetConfigFile().c_str());
2197 CreateThread(Shutdown, NULL);
2202 bool fUseSSL = GetBoolArg("-rpcssl");
2203 asio::ip::address bindAddress = mapArgs.count("-rpcallowip") ? asio::ip::address_v4::any() : asio::ip::address_v4::loopback();
2205 asio::io_service io_service;
2206 ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", 8332));
2207 ip::tcp::acceptor acceptor(io_service, endpoint);
2209 acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
2212 ssl::context context(io_service, ssl::context::sslv23);
2215 context.set_options(ssl::context::no_sslv2);
2216 filesystem::path certfile = GetArg("-rpcsslcertificatechainfile", "server.cert");
2217 if (!certfile.is_complete()) certfile = filesystem::path(GetDataDir()) / certfile;
2218 if (filesystem::exists(certfile)) context.use_certificate_chain_file(certfile.string().c_str());
2219 else printf("ThreadRPCServer ERROR: missing server certificate file %s\n", certfile.string().c_str());
2220 filesystem::path pkfile = GetArg("-rpcsslprivatekeyfile", "server.pem");
2221 if (!pkfile.is_complete()) pkfile = filesystem::path(GetDataDir()) / pkfile;
2222 if (filesystem::exists(pkfile)) context.use_private_key_file(pkfile.string().c_str(), ssl::context::pem);
2223 else printf("ThreadRPCServer ERROR: missing server private key file %s\n", pkfile.string().c_str());
2225 string ciphers = GetArg("-rpcsslciphers",
2226 "TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH");
2227 SSL_CTX_set_cipher_list(context.impl(), ciphers.c_str());
2231 throw runtime_error("-rpcssl=1, but bitcoin compiled without full openssl libraries.");
2236 // Accept connection
2238 SSLStream sslStream(io_service, context);
2239 SSLIOStreamDevice d(sslStream, fUseSSL);
2240 iostreams::stream<SSLIOStreamDevice> stream(d);
2242 ip::tcp::iostream stream;
2245 ip::tcp::endpoint peer;
2246 vnThreadsRunning[4]--;
2248 acceptor.accept(sslStream.lowest_layer(), peer);
2250 acceptor.accept(*stream.rdbuf(), peer);
2252 vnThreadsRunning[4]++;
2256 // Restrict callers by IP
2257 if (!ClientAllowed(peer.address().to_string()))
2259 // Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake.
2261 stream << HTTPReply(403, "") << std::flush;
2265 map<string, string> mapHeaders;
2268 boost::thread api_caller(ReadHTTP, boost::ref(stream), boost::ref(mapHeaders), boost::ref(strRequest));
2269 if (!api_caller.timed_join(boost::posix_time::seconds(GetArg("-rpctimeout", 30))))
2272 printf("ThreadRPCServer ReadHTTP timeout\n");
2276 // Check authorization
2277 if (mapHeaders.count("authorization") == 0)
2279 stream << HTTPReply(401, "") << std::flush;
2282 if (!HTTPAuthorized(mapHeaders))
2284 // Deter brute-forcing short passwords
2285 if (mapArgs["-rpcpassword"].size() < 15)
2288 stream << HTTPReply(401, "") << std::flush;
2289 printf("ThreadRPCServer incorrect password attempt\n");
2293 Value id = Value::null;
2298 if (!read_string(strRequest, valRequest) || valRequest.type() != obj_type)
2299 throw JSONRPCError(-32700, "Parse error");
2300 const Object& request = valRequest.get_obj();
2302 // Parse id now so errors from here on will have the id
2303 id = find_value(request, "id");
2306 Value valMethod = find_value(request, "method");
2307 if (valMethod.type() == null_type)
2308 throw JSONRPCError(-32600, "Missing method");
2309 if (valMethod.type() != str_type)
2310 throw JSONRPCError(-32600, "Method must be a string");
2311 string strMethod = valMethod.get_str();
2312 if (strMethod != "getwork" && strMethod != "getmemorypool")
2313 printf("ThreadRPCServer method=%s\n", strMethod.c_str());
2316 Value valParams = find_value(request, "params");
2318 if (valParams.type() == array_type)
2319 params = valParams.get_array();
2320 else if (valParams.type() == null_type)
2323 throw JSONRPCError(-32600, "Params must be an array");
2326 map<string, rpcfn_type>::iterator mi = mapCallTable.find(strMethod);
2327 if (mi == mapCallTable.end())
2328 throw JSONRPCError(-32601, "Method not found");
2330 // Observe safe mode
2331 string strWarning = GetWarnings("rpc");
2332 if (strWarning != "" && !GetBoolArg("-disablesafemode") && !setAllowInSafeMode.count(strMethod))
2333 throw JSONRPCError(-2, string("Safe mode: ") + strWarning);
2339 CRITICAL_BLOCK(cs_main)
2340 CRITICAL_BLOCK(pwalletMain->cs_wallet)
2341 result = (*(*mi).second)(params, false);
2344 string strReply = JSONRPCReply(result, Value::null, id);
2345 stream << HTTPReply(200, strReply) << std::flush;
2347 catch (std::exception& e)
2349 ErrorReply(stream, JSONRPCError(-1, e.what()), id);
2352 catch (Object& objError)
2354 ErrorReply(stream, objError, id);
2356 catch (std::exception& e)
2358 ErrorReply(stream, JSONRPCError(-32700, e.what()), id);
2366 Object CallRPC(const string& strMethod, const Array& params)
2368 if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
2369 throw runtime_error(strprintf(
2370 _("You must set rpcpassword=<password> in the configuration file:\n%s\n"
2371 "If the file does not exist, create it with owner-readable-only file permissions."),
2372 GetConfigFile().c_str()));
2374 // Connect to localhost
2375 bool fUseSSL = GetBoolArg("-rpcssl");
2377 asio::io_service io_service;
2378 ssl::context context(io_service, ssl::context::sslv23);
2379 context.set_options(ssl::context::no_sslv2);
2380 SSLStream sslStream(io_service, context);
2381 SSLIOStreamDevice d(sslStream, fUseSSL);
2382 iostreams::stream<SSLIOStreamDevice> stream(d);
2383 if (!d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332")))
2384 throw runtime_error("couldn't connect to server");
2387 throw runtime_error("-rpcssl=1, but bitcoin compiled without full openssl libraries.");
2389 ip::tcp::iostream stream(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332"));
2391 throw runtime_error("couldn't connect to server");
2395 // HTTP basic authentication
2396 string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
2397 map<string, string> mapRequestHeaders;
2398 mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64;
2401 string strRequest = JSONRPCRequest(strMethod, params, 1);
2402 string strPost = HTTPPost(strRequest, mapRequestHeaders);
2403 stream << strPost << std::flush;
2406 map<string, string> mapHeaders;
2408 int nStatus = ReadHTTP(stream, mapHeaders, strReply);
2410 throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
2411 else if (nStatus >= 400 && nStatus != 400 && nStatus != 404 && nStatus != 500)
2412 throw runtime_error(strprintf("server returned HTTP error %d", nStatus));
2413 else if (strReply.empty())
2414 throw runtime_error("no response from server");
2418 if (!read_string(strReply, valReply))
2419 throw runtime_error("couldn't parse reply from server");
2420 const Object& reply = valReply.get_obj();
2422 throw runtime_error("expected reply to have result, error and id properties");
2430 template<typename T>
2431 void ConvertTo(Value& value)
2433 if (value.type() == str_type)
2435 // reinterpret string as unquoted json value
2437 if (!read_string(value.get_str(), value2))
2438 throw runtime_error("type mismatch");
2439 value = value2.get_value<T>();
2443 value = value.get_value<T>();
2447 int CommandLineRPC(int argc, char *argv[])
2454 while (argc > 1 && IsSwitchChar(argv[1][0]))
2462 throw runtime_error("too few parameters");
2463 string strMethod = argv[1];
2465 // Parameters default to strings
2467 for (int i = 2; i < argc; i++)
2468 params.push_back(argv[i]);
2469 int n = params.size();
2472 // Special case non-string parameter types
2474 if (strMethod == "setgenerate" && n > 0) ConvertTo<bool>(params[0]);
2475 if (strMethod == "setgenerate" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2476 if (strMethod == "sendtoaddress" && n > 1) ConvertTo<double>(params[1]);
2477 if (strMethod == "settxfee" && n > 0) ConvertTo<double>(params[0]);
2478 if (strMethod == "getreceivedbyaddress" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2479 if (strMethod == "getreceivedbyaccount" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2480 if (strMethod == "listreceivedbyaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2481 if (strMethod == "listreceivedbyaddress" && n > 1) ConvertTo<bool>(params[1]);
2482 if (strMethod == "listreceivedbyaccount" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2483 if (strMethod == "listreceivedbyaccount" && n > 1) ConvertTo<bool>(params[1]);
2484 if (strMethod == "getbalance" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2485 if (strMethod == "move" && n > 2) ConvertTo<double>(params[2]);
2486 if (strMethod == "move" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2487 if (strMethod == "sendfrom" && n > 2) ConvertTo<double>(params[2]);
2488 if (strMethod == "sendfrom" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2489 if (strMethod == "listtransactions" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2490 if (strMethod == "listtransactions" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2491 if (strMethod == "listaccounts" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2492 if (strMethod == "walletpassphrase" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2493 if (strMethod == "listsinceblock" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2494 if (strMethod == "sendmany" && n > 1)
2496 string s = params[1].get_str();
2498 if (!read_string(s, v) || v.type() != obj_type)
2499 throw runtime_error("type mismatch");
2500 params[1] = v.get_obj();
2502 if (strMethod == "sendmany" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2505 Object reply = CallRPC(strMethod, params);
2508 const Value& result = find_value(reply, "result");
2509 const Value& error = find_value(reply, "error");
2511 if (error.type() != null_type)
2514 strPrint = "error: " + write_string(error, false);
2515 int code = find_value(error.get_obj(), "code").get_int();
2521 if (result.type() == null_type)
2523 else if (result.type() == str_type)
2524 strPrint = result.get_str();
2526 strPrint = write_string(result, true);
2529 catch (std::exception& e)
2531 strPrint = string("error: ") + e.what();
2536 PrintException(NULL, "CommandLineRPC()");
2541 fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
2550 int main(int argc, char *argv[])
2553 // Turn off microsoft heap dump noise
2554 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
2555 _CrtSetReportFile(_CRT_WARN, CreateFile("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0));
2557 setbuf(stdin, NULL);
2558 setbuf(stdout, NULL);
2559 setbuf(stderr, NULL);
2563 if (argc >= 2 && string(argv[1]) == "-server")
2565 printf("server ready\n");
2566 ThreadRPCServer(NULL);
2570 return CommandLineRPC(argc, argv);
2573 catch (std::exception& e) {
2574 PrintException(&e, "main()");
2576 PrintException(NULL, "main()");