1 // Copyright (c) 2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2012 The Bitcoin developers
3 // Distributed under the MIT/X11 software license, see the accompanying
4 // file license.txt or http://www.opensource.org/licenses/mit-license.php.
11 #include <boost/asio.hpp>
12 #include <boost/iostreams/concepts.hpp>
13 #include <boost/iostreams/stream.hpp>
14 #include <boost/algorithm/string.hpp>
16 #include <boost/asio/ssl.hpp>
17 #include <boost/filesystem.hpp>
18 #include <boost/filesystem/fstream.hpp>
19 typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> SSLStream;
21 #include "json/json_spirit_reader_template.h"
22 #include "json/json_spirit_writer_template.h"
23 #include "json/json_spirit_utils.h"
24 #define printf OutputDebugStringF
25 // MinGW 3.4.5 gets "fatal error: had to relocate PCH" if the json headers are
26 // precompiled in headers.h. The problem might be when the pch file goes over
27 // a certain size around 145MB. If we need access to json_spirit outside this
28 // file, we could use the compiled json_spirit option.
31 using namespace boost;
32 using namespace boost::asio;
33 using namespace json_spirit;
35 void ThreadRPCServer2(void* parg);
36 typedef Value(*rpcfn_type)(const Array& params, bool fHelp);
37 extern map<string, rpcfn_type> mapCallTable;
39 static int64 nWalletUnlockTime;
40 static CCriticalSection cs_nWalletUnlockTime;
43 Object JSONRPCError(int code, const string& message)
46 error.push_back(Pair("code", code));
47 error.push_back(Pair("message", message));
52 void PrintConsole(const std::string &format, ...)
55 int limit = sizeof(buffer);
57 va_start(arg_ptr, format);
58 int ret = _vsnprintf(buffer, limit, format.c_str(), arg_ptr);
60 if (ret < 0 || ret >= limit)
66 fprintf(stdout, "%s", buffer);
70 int64 AmountFromValue(const Value& value)
72 double dAmount = value.get_real();
73 if (dAmount <= 0.0 || dAmount > 21000000.0)
74 throw JSONRPCError(-3, "Invalid amount");
75 int64 nAmount = roundint64(dAmount * COIN);
76 if (!MoneyRange(nAmount))
77 throw JSONRPCError(-3, "Invalid amount");
81 Value ValueFromAmount(int64 amount)
83 return (double)amount / (double)COIN;
86 void WalletTxToJSON(const CWalletTx& wtx, Object& entry)
88 entry.push_back(Pair("confirmations", wtx.GetDepthInMainChain()));
89 entry.push_back(Pair("txid", wtx.GetHash().GetHex()));
90 entry.push_back(Pair("time", (boost::int64_t)wtx.GetTxTime()));
91 BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue)
92 entry.push_back(Pair(item.first, item.second));
95 string AccountFromValue(const Value& value)
97 string strAccount = value.get_str();
98 if (strAccount == "*")
99 throw JSONRPCError(-11, "Invalid account name");
106 /// Note: This interface may still be subject to change.
110 Value help(const Array& params, bool fHelp)
112 if (fHelp || params.size() > 1)
115 "List commands, or get help for a command.");
118 if (params.size() > 0)
119 strCommand = params[0].get_str();
122 set<rpcfn_type> setDone;
123 for (map<string, rpcfn_type>::iterator mi = mapCallTable.begin(); mi != mapCallTable.end(); ++mi)
125 string strMethod = (*mi).first;
126 // We already filter duplicates, but these deprecated screw up the sort order
127 if (strMethod == "getamountreceived" ||
128 strMethod == "getallreceived" ||
129 (strMethod.find("label") != string::npos))
131 if (strCommand != "" && strMethod != strCommand)
136 rpcfn_type pfn = (*mi).second;
137 if (setDone.insert(pfn).second)
138 (*pfn)(params, true);
140 catch (std::exception& e)
142 // Help text is returned in an exception
143 string strHelp = string(e.what());
144 if (strCommand == "")
145 if (strHelp.find('\n') != -1)
146 strHelp = strHelp.substr(0, strHelp.find('\n'));
147 strRet += strHelp + "\n";
151 strRet = strprintf("help: unknown command: %s\n", strCommand.c_str());
152 strRet = strRet.substr(0,strRet.size()-1);
157 Value stop(const Array& params, bool fHelp)
159 if (fHelp || params.size() != 0)
162 "Stop bitcoin server.");
164 // Shutdown will take long enough that the response should get back
165 CreateThread(Shutdown, NULL);
166 return "bitcoin server stopping";
168 throw runtime_error("NYI: cannot shut down GUI with RPC command");
173 Value getblockcount(const Array& params, bool fHelp)
175 if (fHelp || params.size() != 0)
178 "Returns the number of blocks in the longest block chain.");
184 Value getblocknumber(const Array& params, bool fHelp)
186 if (fHelp || params.size() != 0)
189 "Returns the block number of the latest block in the longest block chain.");
195 Value getconnectioncount(const Array& params, bool fHelp)
197 if (fHelp || params.size() != 0)
199 "getconnectioncount\n"
200 "Returns the number of connections to other nodes.");
202 return (int)vNodes.size();
206 double GetDifficulty()
208 // Floating point number that is a multiple of the minimum difficulty,
209 // minimum difficulty = 1.0.
211 if (pindexBest == NULL)
213 int nShift = (pindexBest->nBits >> 24) & 0xff;
216 (double)0x0000ffff / (double)(pindexBest->nBits & 0x00ffffff);
232 Value getdifficulty(const Array& params, bool fHelp)
234 if (fHelp || params.size() != 0)
237 "Returns the proof-of-work difficulty as a multiple of the minimum difficulty.");
239 return GetDifficulty();
243 Value getgenerate(const Array& params, bool fHelp)
245 if (fHelp || params.size() != 0)
248 "Returns true or false.");
250 return (bool)fGenerateBitcoins;
254 Value setgenerate(const Array& params, bool fHelp)
256 if (fHelp || params.size() < 1 || params.size() > 2)
258 "setgenerate <generate> [genproclimit]\n"
259 "<generate> is true or false to turn generation on or off.\n"
260 "Generation is limited to [genproclimit] processors, -1 is unlimited.");
262 bool fGenerate = true;
263 if (params.size() > 0)
264 fGenerate = params[0].get_bool();
266 if (params.size() > 1)
268 int nGenProcLimit = params[1].get_int();
269 fLimitProcessors = (nGenProcLimit != -1);
270 WriteSetting("fLimitProcessors", fLimitProcessors);
271 if (nGenProcLimit != -1)
272 WriteSetting("nLimitProcessors", nLimitProcessors = nGenProcLimit);
273 if (nGenProcLimit == 0)
277 GenerateBitcoins(fGenerate, pwalletMain);
282 Value gethashespersec(const Array& params, bool fHelp)
284 if (fHelp || params.size() != 0)
287 "Returns a recent hashes per second performance measurement while generating.");
289 if (GetTimeMillis() - nHPSTimerStart > 8000)
290 return (boost::int64_t)0;
291 return (boost::int64_t)dHashesPerSec;
295 Value getinfo(const Array& params, bool fHelp)
297 if (fHelp || params.size() != 0)
300 "Returns an object containing various state info.");
303 obj.push_back(Pair("version", (int)VERSION));
304 obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance())));
305 obj.push_back(Pair("blocks", (int)nBestHeight));
306 obj.push_back(Pair("connections", (int)vNodes.size()));
307 obj.push_back(Pair("proxy", (fUseProxy ? addrProxy.ToStringIPPort() : string())));
308 obj.push_back(Pair("generate", (bool)fGenerateBitcoins));
309 obj.push_back(Pair("genproclimit", (int)(fLimitProcessors ? nLimitProcessors : -1)));
310 obj.push_back(Pair("difficulty", (double)GetDifficulty()));
311 obj.push_back(Pair("hashespersec", gethashespersec(params, false)));
312 obj.push_back(Pair("testnet", fTestNet));
313 obj.push_back(Pair("keypoololdest", (boost::int64_t)pwalletMain->GetOldestKeyPoolTime()));
314 obj.push_back(Pair("keypoolsize", pwalletMain->GetKeyPoolSize()));
315 obj.push_back(Pair("paytxfee", ValueFromAmount(nTransactionFee)));
316 if (pwalletMain->IsCrypted())
317 obj.push_back(Pair("unlocked_until", (boost::int64_t)nWalletUnlockTime / 1000));
318 obj.push_back(Pair("errors", GetWarnings("statusbar")));
323 Value getnewaddress(const Array& params, bool fHelp)
325 if (fHelp || params.size() > 1)
327 "getnewaddress [account]\n"
328 "Returns a new bitcoin address for receiving payments. "
329 "If [account] is specified (recommended), it is added to the address book "
330 "so payments received with the address will be credited to [account].");
332 // Parse the account first so we don't generate a key if there's an error
334 if (params.size() > 0)
335 strAccount = AccountFromValue(params[0]);
337 if (!pwalletMain->IsLocked())
338 pwalletMain->TopUpKeyPool();
340 // Generate a new key that is added to wallet
341 std::vector<unsigned char> newKey;
342 if (!pwalletMain->GetKeyFromPool(newKey, false))
343 throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
344 CBitcoinAddress address(newKey);
346 pwalletMain->SetAddressBookName(address, strAccount);
348 return address.ToString();
352 CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false)
354 CWalletDB walletdb(pwalletMain->strWalletFile);
357 walletdb.ReadAccount(strAccount, account);
359 bool bKeyUsed = false;
361 // Check if the current key has been used
362 if (!account.vchPubKey.empty())
364 CScript scriptPubKey;
365 scriptPubKey.SetBitcoinAddress(account.vchPubKey);
366 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
367 it != pwalletMain->mapWallet.end() && !account.vchPubKey.empty();
370 const CWalletTx& wtx = (*it).second;
371 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
372 if (txout.scriptPubKey == scriptPubKey)
377 // Generate a new key
378 if (account.vchPubKey.empty() || bForceNew || bKeyUsed)
380 if (!pwalletMain->GetKeyFromPool(account.vchPubKey, false))
381 throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
383 pwalletMain->SetAddressBookName(CBitcoinAddress(account.vchPubKey), strAccount);
384 walletdb.WriteAccount(strAccount, account);
387 return CBitcoinAddress(account.vchPubKey);
390 Value getaccountaddress(const Array& params, bool fHelp)
392 if (fHelp || params.size() != 1)
394 "getaccountaddress <account>\n"
395 "Returns the current bitcoin address for receiving payments to this account.");
397 // Parse the account first so we don't generate a key if there's an error
398 string strAccount = AccountFromValue(params[0]);
402 ret = GetAccountAddress(strAccount).ToString();
409 Value setaccount(const Array& params, bool fHelp)
411 if (fHelp || params.size() < 1 || params.size() > 2)
413 "setaccount <bitcoinaddress> <account>\n"
414 "Sets the account associated with the given address.");
416 CBitcoinAddress address(params[0].get_str());
417 if (!address.IsValid())
418 throw JSONRPCError(-5, "Invalid bitcoin address");
422 if (params.size() > 1)
423 strAccount = AccountFromValue(params[1]);
425 // Detect when changing the account of an address that is the 'unused current key' of another account:
426 if (pwalletMain->mapAddressBook.count(address))
428 string strOldAccount = pwalletMain->mapAddressBook[address];
429 if (address == GetAccountAddress(strOldAccount))
430 GetAccountAddress(strOldAccount, true);
433 pwalletMain->SetAddressBookName(address, strAccount);
439 Value getaccount(const Array& params, bool fHelp)
441 if (fHelp || params.size() != 1)
443 "getaccount <bitcoinaddress>\n"
444 "Returns the account associated with the given address.");
446 CBitcoinAddress address(params[0].get_str());
447 if (!address.IsValid())
448 throw JSONRPCError(-5, "Invalid bitcoin address");
451 map<CBitcoinAddress, string>::iterator mi = pwalletMain->mapAddressBook.find(address);
452 if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.empty())
453 strAccount = (*mi).second;
458 Value getaddressesbyaccount(const Array& params, bool fHelp)
460 if (fHelp || params.size() != 1)
462 "getaddressesbyaccount <account>\n"
463 "Returns the list of addresses for the given account.");
465 string strAccount = AccountFromValue(params[0]);
467 // Find all addresses that have the given account
469 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
471 const CBitcoinAddress& address = item.first;
472 const string& strName = item.second;
473 if (strName == strAccount)
474 ret.push_back(address.ToString());
479 Value settxfee(const Array& params, bool fHelp)
481 if (fHelp || params.size() < 1 || params.size() > 1)
483 "settxfee <amount>\n"
484 "<amount> is a real and is rounded to the nearest 0.00000001");
488 if (params[0].get_real() != 0.0)
489 nAmount = AmountFromValue(params[0]); // rejects 0.0 amounts
491 nTransactionFee = nAmount;
495 Value sendtoaddress(const Array& params, bool fHelp)
497 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
499 "sendtoaddress <bitcoinaddress> <amount> [comment] [comment-to]\n"
500 "<amount> is a real and is rounded to the nearest 0.00000001\n"
501 "requires wallet passphrase to be set with walletpassphrase first");
502 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
504 "sendtoaddress <bitcoinaddress> <amount> [comment] [comment-to]\n"
505 "<amount> is a real and is rounded to the nearest 0.00000001");
507 CBitcoinAddress address(params[0].get_str());
508 if (!address.IsValid())
509 throw JSONRPCError(-5, "Invalid bitcoin address");
512 int64 nAmount = AmountFromValue(params[1]);
516 if (params.size() > 2 && params[2].type() != null_type && !params[2].get_str().empty())
517 wtx.mapValue["comment"] = params[2].get_str();
518 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
519 wtx.mapValue["to"] = params[3].get_str();
521 if (pwalletMain->IsLocked())
522 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
524 string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
526 throw JSONRPCError(-4, strError);
528 return wtx.GetHash().GetHex();
531 static const string strMessageMagic = "Bitcoin Signed Message:\n";
533 Value signmessage(const Array& params, bool fHelp)
535 if (fHelp || params.size() != 2)
537 "signmessage <bitcoinaddress> <message>\n"
538 "Sign a message with the private key of an address");
540 if (pwalletMain->IsLocked())
541 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
543 string strAddress = params[0].get_str();
544 string strMessage = params[1].get_str();
546 CBitcoinAddress addr(strAddress);
548 throw JSONRPCError(-3, "Invalid address");
551 if (!pwalletMain->GetKey(addr, key))
552 throw JSONRPCError(-4, "Private key not available");
554 CDataStream ss(SER_GETHASH);
555 ss << strMessageMagic;
558 vector<unsigned char> vchSig;
559 if (!key.SignCompact(Hash(ss.begin(), ss.end()), vchSig))
560 throw JSONRPCError(-5, "Sign failed");
562 return EncodeBase64(&vchSig[0], vchSig.size());
565 Value verifymessage(const Array& params, bool fHelp)
567 if (fHelp || params.size() != 3)
569 "verifymessage <bitcoinaddress> <signature> <message>\n"
570 "Verify a signed message");
572 string strAddress = params[0].get_str();
573 string strSign = params[1].get_str();
574 string strMessage = params[2].get_str();
576 CBitcoinAddress addr(strAddress);
578 throw JSONRPCError(-3, "Invalid address");
580 bool fInvalid = false;
581 vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid);
584 throw JSONRPCError(-5, "Malformed base64 encoding");
586 CDataStream ss(SER_GETHASH);
587 ss << strMessageMagic;
591 if (!key.SetCompactSignature(Hash(ss.begin(), ss.end()), vchSig))
594 return (key.GetAddress() == addr);
598 Value getreceivedbyaddress(const Array& params, bool fHelp)
600 if (fHelp || params.size() < 1 || params.size() > 2)
602 "getreceivedbyaddress <bitcoinaddress> [minconf=1]\n"
603 "Returns the total amount received by <bitcoinaddress> in transactions with at least [minconf] confirmations.");
606 CBitcoinAddress address = CBitcoinAddress(params[0].get_str());
607 CScript scriptPubKey;
608 if (!address.IsValid())
609 throw JSONRPCError(-5, "Invalid bitcoin address");
610 scriptPubKey.SetBitcoinAddress(address);
611 if (!IsMine(*pwalletMain,scriptPubKey))
614 // Minimum confirmations
616 if (params.size() > 1)
617 nMinDepth = params[1].get_int();
621 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
623 const CWalletTx& wtx = (*it).second;
624 if (wtx.IsCoinBase() || !wtx.IsFinal())
627 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
628 if (txout.scriptPubKey == scriptPubKey)
629 if (wtx.GetDepthInMainChain() >= nMinDepth)
630 nAmount += txout.nValue;
633 return ValueFromAmount(nAmount);
637 void GetAccountAddresses(string strAccount, set<CBitcoinAddress>& setAddress)
639 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
641 const CBitcoinAddress& address = item.first;
642 const string& strName = item.second;
643 if (strName == strAccount)
644 setAddress.insert(address);
649 Value getreceivedbyaccount(const Array& params, bool fHelp)
651 if (fHelp || params.size() < 1 || params.size() > 2)
653 "getreceivedbyaccount <account> [minconf=1]\n"
654 "Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.");
656 // Minimum confirmations
658 if (params.size() > 1)
659 nMinDepth = params[1].get_int();
661 // Get the set of pub keys that have the label
662 string strAccount = AccountFromValue(params[0]);
663 set<CBitcoinAddress> setAddress;
664 GetAccountAddresses(strAccount, setAddress);
668 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
670 const CWalletTx& wtx = (*it).second;
671 if (wtx.IsCoinBase() || !wtx.IsFinal())
674 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
676 CBitcoinAddress address;
677 if (ExtractAddress(txout.scriptPubKey, pwalletMain, address) && setAddress.count(address))
678 if (wtx.GetDepthInMainChain() >= nMinDepth)
679 nAmount += txout.nValue;
683 return (double)nAmount / (double)COIN;
687 int64 GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth)
691 // Tally wallet transactions
692 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
694 const CWalletTx& wtx = (*it).second;
698 int64 nGenerated, nReceived, nSent, nFee;
699 wtx.GetAccountAmounts(strAccount, nGenerated, nReceived, nSent, nFee);
701 if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
702 nBalance += nReceived;
703 nBalance += nGenerated - nSent - nFee;
706 // Tally internal accounting entries
707 nBalance += walletdb.GetAccountCreditDebit(strAccount);
712 int64 GetAccountBalance(const string& strAccount, int nMinDepth)
714 CWalletDB walletdb(pwalletMain->strWalletFile);
715 return GetAccountBalance(walletdb, strAccount, nMinDepth);
719 Value getbalance(const Array& params, bool fHelp)
721 if (fHelp || params.size() > 2)
723 "getbalance [account] [minconf=1]\n"
724 "If [account] is not specified, returns the server's total available balance.\n"
725 "If [account] is specified, returns the balance in the account.");
727 if (params.size() == 0)
728 return ValueFromAmount(pwalletMain->GetBalance());
731 if (params.size() > 1)
732 nMinDepth = params[1].get_int();
734 if (params[0].get_str() == "*") {
735 // Calculate total balance a different way from GetBalance()
736 // (GetBalance() sums up all unspent TxOuts)
737 // getbalance and getbalance '*' should always return the same number.
739 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
741 const CWalletTx& wtx = (*it).second;
745 int64 allGeneratedImmature, allGeneratedMature, allFee;
746 allGeneratedImmature = allGeneratedMature = allFee = 0;
747 string strSentAccount;
748 list<pair<CBitcoinAddress, int64> > listReceived;
749 list<pair<CBitcoinAddress, int64> > listSent;
750 wtx.GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount);
751 if (wtx.GetDepthInMainChain() >= nMinDepth)
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 = GetTimeMillis() + *((int64*)parg) * 1000;
1408 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1410 if (nWalletUnlockTime == 0)
1412 nWalletUnlockTime = nMyWakeTime;
1416 if (nWalletUnlockTime==0)
1418 int64 nToSleep = nWalletUnlockTime - GetTimeMillis();
1422 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1424 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1428 if (nWalletUnlockTime)
1430 nWalletUnlockTime = 0;
1431 pwalletMain->Lock();
1436 if (nWalletUnlockTime < nMyWakeTime)
1437 nWalletUnlockTime = nMyWakeTime;
1440 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1442 delete (int64*)parg;
1445 Value walletpassphrase(const Array& params, bool fHelp)
1447 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1448 throw runtime_error(
1449 "walletpassphrase <passphrase> <timeout>\n"
1450 "Stores the wallet decryption key in memory for <timeout> seconds.");
1453 if (!pwalletMain->IsCrypted())
1454 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
1456 if (!pwalletMain->IsLocked())
1457 throw JSONRPCError(-17, "Error: Wallet is already unlocked.");
1459 // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
1460 SecureString strWalletPass;
1461 strWalletPass.reserve(100);
1462 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1463 // Alternately, find a way to make params[0] mlock()'d to begin with.
1464 strWalletPass = params[0].get_str().c_str();
1466 if (strWalletPass.length() > 0)
1468 if (!pwalletMain->Unlock(strWalletPass))
1469 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1472 throw runtime_error(
1473 "walletpassphrase <passphrase> <timeout>\n"
1474 "Stores the wallet decryption key in memory for <timeout> seconds.");
1476 CreateThread(ThreadTopUpKeyPool, NULL);
1477 int64* pnSleepTime = new int64(params[1].get_int64());
1478 CreateThread(ThreadCleanWalletPassphrase, pnSleepTime);
1484 Value walletpassphrasechange(const Array& params, bool fHelp)
1486 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1487 throw runtime_error(
1488 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1489 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1492 if (!pwalletMain->IsCrypted())
1493 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
1495 // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
1496 // Alternately, find a way to make params[0] mlock()'d to begin with.
1497 SecureString strOldWalletPass;
1498 strOldWalletPass.reserve(100);
1499 strOldWalletPass = params[0].get_str().c_str();
1501 SecureString strNewWalletPass;
1502 strNewWalletPass.reserve(100);
1503 strNewWalletPass = params[1].get_str().c_str();
1505 if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
1506 throw runtime_error(
1507 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1508 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1510 if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
1511 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1517 Value walletlock(const Array& params, bool fHelp)
1519 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
1520 throw runtime_error(
1522 "Removes the wallet encryption key from memory, locking the wallet.\n"
1523 "After calling this method, you will need to call walletpassphrase again\n"
1524 "before being able to call any methods which require the wallet to be unlocked.");
1527 if (!pwalletMain->IsCrypted())
1528 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletlock was called.");
1530 CRITICAL_BLOCK(cs_nWalletUnlockTime)
1532 pwalletMain->Lock();
1533 nWalletUnlockTime = 0;
1540 Value encryptwallet(const Array& params, bool fHelp)
1542 if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
1543 throw runtime_error(
1544 "encryptwallet <passphrase>\n"
1545 "Encrypts the wallet with <passphrase>.");
1548 if (pwalletMain->IsCrypted())
1549 throw JSONRPCError(-15, "Error: running with an encrypted wallet, but encryptwallet was called.");
1552 // shutting down via RPC while the GUI is running does not work (yet):
1553 throw runtime_error("Not Yet Implemented: use GUI to encrypt wallet, not RPC command");
1556 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1557 // Alternately, find a way to make params[0] mlock()'d to begin with.
1558 SecureString strWalletPass;
1559 strWalletPass.reserve(100);
1560 strWalletPass = params[0].get_str().c_str();
1562 if (strWalletPass.length() < 1)
1563 throw runtime_error(
1564 "encryptwallet <passphrase>\n"
1565 "Encrypts the wallet with <passphrase>.");
1567 if (!pwalletMain->EncryptWallet(strWalletPass))
1568 throw JSONRPCError(-16, "Error: Failed to encrypt the wallet.");
1570 // BDB seems to have a bad habit of writing old data into
1571 // slack space in .dat files; that is bad if the old data is
1572 // unencrypted private keys. So:
1573 CreateThread(Shutdown, NULL);
1574 return "wallet encrypted; bitcoin server stopping, restart to run with encrypted wallet";
1578 Value validateaddress(const Array& params, bool fHelp)
1580 if (fHelp || params.size() != 1)
1581 throw runtime_error(
1582 "validateaddress <bitcoinaddress>\n"
1583 "Return information about <bitcoinaddress>.");
1585 CBitcoinAddress address(params[0].get_str());
1586 bool isValid = address.IsValid();
1589 ret.push_back(Pair("isvalid", isValid));
1592 // Call Hash160ToAddress() so we always return current ADDRESSVERSION
1593 // version of the address:
1594 string currentAddress = address.ToString();
1595 ret.push_back(Pair("address", currentAddress));
1596 ret.push_back(Pair("ismine", (pwalletMain->HaveKey(address) > 0)));
1597 if (pwalletMain->mapAddressBook.count(address))
1598 ret.push_back(Pair("account", pwalletMain->mapAddressBook[address]));
1604 Value getwork(const Array& params, bool fHelp)
1606 if (fHelp || params.size() > 1)
1607 throw runtime_error(
1609 "If [data] is not specified, returns formatted hash data to work on:\n"
1610 " \"midstate\" : precomputed hash state after hashing the first half of the data (DEPRECATED)\n" // deprecated
1611 " \"data\" : block data\n"
1612 " \"hash1\" : formatted hash buffer for second hash (DEPRECATED)\n" // deprecated
1613 " \"target\" : little endian hash target\n"
1614 "If [data] is specified, tries to solve the block and returns true if it was successful.");
1617 throw JSONRPCError(-9, "Bitcoin is not connected!");
1619 if (IsInitialBlockDownload())
1620 throw JSONRPCError(-10, "Bitcoin is downloading blocks...");
1622 typedef map<uint256, pair<CBlock*, CScript> > mapNewBlock_t;
1623 static mapNewBlock_t mapNewBlock;
1624 static vector<CBlock*> vNewBlock;
1625 static CReserveKey reservekey(pwalletMain);
1627 if (params.size() == 0)
1630 static unsigned int nTransactionsUpdatedLast;
1631 static CBlockIndex* pindexPrev;
1632 static int64 nStart;
1633 static CBlock* pblock;
1634 if (pindexPrev != pindexBest ||
1635 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60))
1637 if (pindexPrev != pindexBest)
1639 // Deallocate old blocks since they're obsolete now
1640 mapNewBlock.clear();
1641 BOOST_FOREACH(CBlock* pblock, vNewBlock)
1645 nTransactionsUpdatedLast = nTransactionsUpdated;
1646 pindexPrev = pindexBest;
1650 pblock = CreateNewBlock(reservekey);
1652 throw JSONRPCError(-7, "Out of memory");
1653 vNewBlock.push_back(pblock);
1657 pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
1660 // Update nExtraNonce
1661 static unsigned int nExtraNonce = 0;
1662 IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
1665 mapNewBlock[pblock->hashMerkleRoot] = make_pair(pblock, pblock->vtx[0].vin[0].scriptSig);
1667 // Prebuild hash buffers
1671 FormatHashBuffers(pblock, pmidstate, pdata, phash1);
1673 uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
1676 result.push_back(Pair("midstate", HexStr(BEGIN(pmidstate), END(pmidstate)))); // deprecated
1677 result.push_back(Pair("data", HexStr(BEGIN(pdata), END(pdata))));
1678 result.push_back(Pair("hash1", HexStr(BEGIN(phash1), END(phash1)))); // deprecated
1679 result.push_back(Pair("target", HexStr(BEGIN(hashTarget), END(hashTarget))));
1685 vector<unsigned char> vchData = ParseHex(params[0].get_str());
1686 if (vchData.size() != 128)
1687 throw JSONRPCError(-8, "Invalid parameter");
1688 CBlock* pdata = (CBlock*)&vchData[0];
1691 for (int i = 0; i < 128/4; i++)
1692 ((unsigned int*)pdata)[i] = ByteReverse(((unsigned int*)pdata)[i]);
1695 if (!mapNewBlock.count(pdata->hashMerkleRoot))
1697 CBlock* pblock = mapNewBlock[pdata->hashMerkleRoot].first;
1699 pblock->nTime = pdata->nTime;
1700 pblock->nNonce = pdata->nNonce;
1701 pblock->vtx[0].vin[0].scriptSig = mapNewBlock[pdata->hashMerkleRoot].second;
1702 pblock->hashMerkleRoot = pblock->BuildMerkleTree();
1704 return CheckWork(pblock, *pwalletMain, reservekey);
1709 Value getmemorypool(const Array& params, bool fHelp)
1711 if (fHelp || params.size() > 1)
1712 throw runtime_error(
1713 "getmemorypool [data]\n"
1714 "If [data] is not specified, returns data needed to construct a block to work on:\n"
1715 " \"version\" : block version\n"
1716 " \"previousblockhash\" : hash of current highest block\n"
1717 " \"transactions\" : contents of non-coinbase transactions that should be included in the next block\n"
1718 " \"coinbasevalue\" : maximum allowable input to coinbase transaction, including the generation award and transaction fees\n"
1719 " \"time\" : timestamp appropriate for next block\n"
1720 " \"bits\" : compressed target of next block\n"
1721 "If [data] is specified, tries to solve the block and returns true if it was successful.");
1723 if (params.size() == 0)
1726 throw JSONRPCError(-9, "Bitcoin is not connected!");
1728 if (IsInitialBlockDownload())
1729 throw JSONRPCError(-10, "Bitcoin is downloading blocks...");
1731 static CReserveKey reservekey(pwalletMain);
1734 static unsigned int nTransactionsUpdatedLast;
1735 static CBlockIndex* pindexPrev;
1736 static int64 nStart;
1737 static CBlock* pblock;
1738 if (pindexPrev != pindexBest ||
1739 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 5))
1741 nTransactionsUpdatedLast = nTransactionsUpdated;
1742 pindexPrev = pindexBest;
1748 pblock = CreateNewBlock(reservekey);
1750 throw JSONRPCError(-7, "Out of memory");
1754 pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
1758 BOOST_FOREACH(CTransaction tx, pblock->vtx) {
1765 transactions.push_back(HexStr(ssTx.begin(), ssTx.end()));
1769 result.push_back(Pair("version", pblock->nVersion));
1770 result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex()));
1771 result.push_back(Pair("transactions", transactions));
1772 result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue));
1773 result.push_back(Pair("time", (int64_t)pblock->nTime));
1779 uBits.nBits = htonl((int32_t)pblock->nBits);
1780 result.push_back(Pair("bits", HexStr(BEGIN(uBits.cBits), END(uBits.cBits))));
1787 CDataStream ssBlock(ParseHex(params[0].get_str()));
1791 return ProcessBlock(NULL, &pblock);
1809 pair<string, rpcfn_type> pCallTable[] =
1811 make_pair("help", &help),
1812 make_pair("stop", &stop),
1813 make_pair("getblockcount", &getblockcount),
1814 make_pair("getblocknumber", &getblocknumber),
1815 make_pair("getconnectioncount", &getconnectioncount),
1816 make_pair("getdifficulty", &getdifficulty),
1817 make_pair("getgenerate", &getgenerate),
1818 make_pair("setgenerate", &setgenerate),
1819 make_pair("gethashespersec", &gethashespersec),
1820 make_pair("getinfo", &getinfo),
1821 make_pair("getnewaddress", &getnewaddress),
1822 make_pair("getaccountaddress", &getaccountaddress),
1823 make_pair("setaccount", &setaccount),
1824 make_pair("getaccount", &getaccount),
1825 make_pair("getaddressesbyaccount", &getaddressesbyaccount),
1826 make_pair("sendtoaddress", &sendtoaddress),
1827 make_pair("getreceivedbyaddress", &getreceivedbyaddress),
1828 make_pair("getreceivedbyaccount", &getreceivedbyaccount),
1829 make_pair("listreceivedbyaddress", &listreceivedbyaddress),
1830 make_pair("listreceivedbyaccount", &listreceivedbyaccount),
1831 make_pair("backupwallet", &backupwallet),
1832 make_pair("keypoolrefill", &keypoolrefill),
1833 make_pair("walletpassphrase", &walletpassphrase),
1834 make_pair("walletpassphrasechange", &walletpassphrasechange),
1835 make_pair("walletlock", &walletlock),
1836 make_pair("encryptwallet", &encryptwallet),
1837 make_pair("validateaddress", &validateaddress),
1838 make_pair("getbalance", &getbalance),
1839 make_pair("move", &movecmd),
1840 make_pair("sendfrom", &sendfrom),
1841 make_pair("sendmany", &sendmany),
1842 make_pair("gettransaction", &gettransaction),
1843 make_pair("listtransactions", &listtransactions),
1844 make_pair("signmessage", &signmessage),
1845 make_pair("verifymessage", &verifymessage),
1846 make_pair("getwork", &getwork),
1847 make_pair("listaccounts", &listaccounts),
1848 make_pair("settxfee", &settxfee),
1849 make_pair("getmemorypool", &getmemorypool),
1850 make_pair("listsinceblock", &listsinceblock),
1852 map<string, rpcfn_type> mapCallTable(pCallTable, pCallTable + sizeof(pCallTable)/sizeof(pCallTable[0]));
1854 string pAllowInSafeMode[] =
1860 "getconnectioncount",
1867 "getaccountaddress",
1869 "getaddressesbyaccount",
1878 set<string> setAllowInSafeMode(pAllowInSafeMode, pAllowInSafeMode + sizeof(pAllowInSafeMode)/sizeof(pAllowInSafeMode[0]));
1886 // This ain't Apache. We're just using HTTP header for the length field
1887 // and to be compatible with other JSON-RPC implementations.
1890 string HTTPPost(const string& strMsg, const map<string,string>& mapRequestHeaders)
1893 s << "POST / HTTP/1.1\r\n"
1894 << "User-Agent: bitcoin-json-rpc/" << FormatFullVersion() << "\r\n"
1895 << "Host: 127.0.0.1\r\n"
1896 << "Content-Type: application/json\r\n"
1897 << "Content-Length: " << strMsg.size() << "\r\n"
1898 << "Connection: close\r\n"
1899 << "Accept: application/json\r\n";
1900 BOOST_FOREACH(const PAIRTYPE(string, string)& item, mapRequestHeaders)
1901 s << item.first << ": " << item.second << "\r\n";
1902 s << "\r\n" << strMsg;
1907 string rfc1123Time()
1912 struct tm* now_gmt = gmtime(&now);
1913 string locale(setlocale(LC_TIME, NULL));
1914 setlocale(LC_TIME, "C"); // we want posix (aka "C") weekday/month strings
1915 strftime(buffer, sizeof(buffer), "%a, %d %b %Y %H:%M:%S +0000", now_gmt);
1916 setlocale(LC_TIME, locale.c_str());
1917 return string(buffer);
1920 static string HTTPReply(int nStatus, const string& strMsg)
1923 return strprintf("HTTP/1.0 401 Authorization Required\r\n"
1925 "Server: bitcoin-json-rpc/%s\r\n"
1926 "WWW-Authenticate: Basic realm=\"jsonrpc\"\r\n"
1927 "Content-Type: text/html\r\n"
1928 "Content-Length: 296\r\n"
1930 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\r\n"
1931 "\"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd\">\r\n"
1934 "<TITLE>Error</TITLE>\r\n"
1935 "<META HTTP-EQUIV='Content-Type' CONTENT='text/html; charset=ISO-8859-1'>\r\n"
1937 "<BODY><H1>401 Unauthorized.</H1></BODY>\r\n"
1938 "</HTML>\r\n", rfc1123Time().c_str(), FormatFullVersion().c_str());
1939 const char *cStatus;
1940 if (nStatus == 200) cStatus = "OK";
1941 else if (nStatus == 400) cStatus = "Bad Request";
1942 else if (nStatus == 403) cStatus = "Forbidden";
1943 else if (nStatus == 404) cStatus = "Not Found";
1944 else if (nStatus == 500) cStatus = "Internal Server Error";
1947 "HTTP/1.1 %d %s\r\n"
1949 "Connection: close\r\n"
1950 "Content-Length: %d\r\n"
1951 "Content-Type: application/json\r\n"
1952 "Server: bitcoin-json-rpc/%s\r\n"
1957 rfc1123Time().c_str(),
1959 FormatFullVersion().c_str(),
1963 int ReadHTTPStatus(std::basic_istream<char>& stream)
1966 getline(stream, str);
1967 vector<string> vWords;
1968 boost::split(vWords, str, boost::is_any_of(" "));
1969 if (vWords.size() < 2)
1971 return atoi(vWords[1].c_str());
1974 int ReadHTTPHeader(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet)
1980 std::getline(stream, str);
1981 if (str.empty() || str == "\r")
1983 string::size_type nColon = str.find(":");
1984 if (nColon != string::npos)
1986 string strHeader = str.substr(0, nColon);
1987 boost::trim(strHeader);
1988 boost::to_lower(strHeader);
1989 string strValue = str.substr(nColon+1);
1990 boost::trim(strValue);
1991 mapHeadersRet[strHeader] = strValue;
1992 if (strHeader == "content-length")
1993 nLen = atoi(strValue.c_str());
1999 int ReadHTTP(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet, string& strMessageRet)
2001 mapHeadersRet.clear();
2005 int nStatus = ReadHTTPStatus(stream);
2008 int nLen = ReadHTTPHeader(stream, mapHeadersRet);
2009 if (nLen < 0 || nLen > MAX_SIZE)
2015 vector<char> vch(nLen);
2016 stream.read(&vch[0], nLen);
2017 strMessageRet = string(vch.begin(), vch.end());
2023 bool HTTPAuthorized(map<string, string>& mapHeaders)
2025 string strAuth = mapHeaders["authorization"];
2026 if (strAuth.substr(0,6) != "Basic ")
2028 string strUserPass64 = strAuth.substr(6); boost::trim(strUserPass64);
2029 string strUserPass = DecodeBase64(strUserPass64);
2030 string::size_type nColon = strUserPass.find(":");
2031 if (nColon == string::npos)
2033 string strUser = strUserPass.substr(0, nColon);
2034 string strPassword = strUserPass.substr(nColon+1);
2035 return (strUser == mapArgs["-rpcuser"] && strPassword == mapArgs["-rpcpassword"]);
2039 // JSON-RPC protocol. Bitcoin speaks version 1.0 for maximum compatibility,
2040 // but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
2041 // unspecified (HTTP errors and contents of 'error').
2043 // 1.0 spec: http://json-rpc.org/wiki/specification
2044 // 1.2 spec: http://groups.google.com/group/json-rpc/web/json-rpc-over-http
2045 // http://www.codeproject.com/KB/recipes/JSON_Spirit.aspx
2048 string JSONRPCRequest(const string& strMethod, const Array& params, const Value& id)
2051 request.push_back(Pair("method", strMethod));
2052 request.push_back(Pair("params", params));
2053 request.push_back(Pair("id", id));
2054 return write_string(Value(request), false) + "\n";
2057 string JSONRPCReply(const Value& result, const Value& error, const Value& id)
2060 if (error.type() != null_type)
2061 reply.push_back(Pair("result", Value::null));
2063 reply.push_back(Pair("result", result));
2064 reply.push_back(Pair("error", error));
2065 reply.push_back(Pair("id", id));
2066 return write_string(Value(reply), false) + "\n";
2069 void ErrorReply(std::ostream& stream, const Object& objError, const Value& id)
2071 // Send error reply from json-rpc error object
2073 int code = find_value(objError, "code").get_int();
2074 if (code == -32600) nStatus = 400;
2075 else if (code == -32601) nStatus = 404;
2076 string strReply = JSONRPCReply(Value::null, objError, id);
2077 stream << HTTPReply(nStatus, strReply) << std::flush;
2080 bool ClientAllowed(const string& strAddress)
2082 if (strAddress == asio::ip::address_v4::loopback().to_string())
2084 const vector<string>& vAllow = mapMultiArgs["-rpcallowip"];
2085 BOOST_FOREACH(string strAllow, vAllow)
2086 if (WildcardMatch(strAddress, strAllow))
2093 // IOStream device that speaks SSL but can also speak non-SSL
2095 class SSLIOStreamDevice : public iostreams::device<iostreams::bidirectional> {
2097 SSLIOStreamDevice(SSLStream &streamIn, bool fUseSSLIn) : stream(streamIn)
2099 fUseSSL = fUseSSLIn;
2100 fNeedHandshake = fUseSSLIn;
2103 void handshake(ssl::stream_base::handshake_type role)
2105 if (!fNeedHandshake) return;
2106 fNeedHandshake = false;
2107 stream.handshake(role);
2109 std::streamsize read(char* s, std::streamsize n)
2111 handshake(ssl::stream_base::server); // HTTPS servers read first
2112 if (fUseSSL) return stream.read_some(asio::buffer(s, n));
2113 return stream.next_layer().read_some(asio::buffer(s, n));
2115 std::streamsize write(const char* s, std::streamsize n)
2117 handshake(ssl::stream_base::client); // HTTPS clients write first
2118 if (fUseSSL) return asio::write(stream, asio::buffer(s, n));
2119 return asio::write(stream.next_layer(), asio::buffer(s, n));
2121 bool connect(const std::string& server, const std::string& port)
2123 ip::tcp::resolver resolver(stream.get_io_service());
2124 ip::tcp::resolver::query query(server.c_str(), port.c_str());
2125 ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
2126 ip::tcp::resolver::iterator end;
2127 boost::system::error_code error = asio::error::host_not_found;
2128 while (error && endpoint_iterator != end)
2130 stream.lowest_layer().close();
2131 stream.lowest_layer().connect(*endpoint_iterator++, error);
2139 bool fNeedHandshake;
2145 void ThreadRPCServer(void* parg)
2147 IMPLEMENT_RANDOMIZE_STACK(ThreadRPCServer(parg));
2150 vnThreadsRunning[4]++;
2151 ThreadRPCServer2(parg);
2152 vnThreadsRunning[4]--;
2154 catch (std::exception& e) {
2155 vnThreadsRunning[4]--;
2156 PrintException(&e, "ThreadRPCServer()");
2158 vnThreadsRunning[4]--;
2159 PrintException(NULL, "ThreadRPCServer()");
2161 printf("ThreadRPCServer exiting\n");
2164 void ThreadRPCServer2(void* parg)
2166 printf("ThreadRPCServer started\n");
2168 if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
2170 unsigned char rand_pwd[32];
2171 RAND_bytes(rand_pwd, 32);
2172 string strWhatAmI = "To use bitcoind";
2173 if (mapArgs.count("-server"))
2174 strWhatAmI = strprintf(_("To use the %s option"), "\"-server\"");
2175 else if (mapArgs.count("-daemon"))
2176 strWhatAmI = strprintf(_("To use the %s option"), "\"-daemon\"");
2178 _("Error: %s, you must set a rpcpassword in the configuration file:\n %s\n"
2179 "It is recommended you use the following random password:\n"
2180 "rpcuser=bitcoinrpc\n"
2182 "(you do not need to remember this password)\n"
2183 "If the file does not exist, create it with owner-readable-only file permissions.\n"),
2185 GetConfigFile().c_str(),
2186 EncodeBase58(&rand_pwd[0],&rand_pwd[0]+32).c_str());
2188 CreateThread(Shutdown, NULL);
2193 bool fUseSSL = GetBoolArg("-rpcssl");
2194 asio::ip::address bindAddress = mapArgs.count("-rpcallowip") ? asio::ip::address_v4::any() : asio::ip::address_v4::loopback();
2196 asio::io_service io_service;
2197 ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", 8332));
2198 ip::tcp::acceptor acceptor(io_service, endpoint);
2200 acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
2203 ssl::context context(io_service, ssl::context::sslv23);
2206 context.set_options(ssl::context::no_sslv2);
2207 filesystem::path certfile = GetArg("-rpcsslcertificatechainfile", "server.cert");
2208 if (!certfile.is_complete()) certfile = filesystem::path(GetDataDir()) / certfile;
2209 if (filesystem::exists(certfile)) context.use_certificate_chain_file(certfile.string().c_str());
2210 else printf("ThreadRPCServer ERROR: missing server certificate file %s\n", certfile.string().c_str());
2211 filesystem::path pkfile = GetArg("-rpcsslprivatekeyfile", "server.pem");
2212 if (!pkfile.is_complete()) pkfile = filesystem::path(GetDataDir()) / pkfile;
2213 if (filesystem::exists(pkfile)) context.use_private_key_file(pkfile.string().c_str(), ssl::context::pem);
2214 else printf("ThreadRPCServer ERROR: missing server private key file %s\n", pkfile.string().c_str());
2216 string ciphers = GetArg("-rpcsslciphers",
2217 "TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH");
2218 SSL_CTX_set_cipher_list(context.impl(), ciphers.c_str());
2222 throw runtime_error("-rpcssl=1, but bitcoin compiled without full openssl libraries.");
2227 // Accept connection
2229 SSLStream sslStream(io_service, context);
2230 SSLIOStreamDevice d(sslStream, fUseSSL);
2231 iostreams::stream<SSLIOStreamDevice> stream(d);
2233 ip::tcp::iostream stream;
2236 ip::tcp::endpoint peer;
2237 vnThreadsRunning[4]--;
2239 acceptor.accept(sslStream.lowest_layer(), peer);
2241 acceptor.accept(*stream.rdbuf(), peer);
2243 vnThreadsRunning[4]++;
2247 // Restrict callers by IP
2248 if (!ClientAllowed(peer.address().to_string()))
2250 // Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake.
2252 stream << HTTPReply(403, "") << std::flush;
2256 map<string, string> mapHeaders;
2259 boost::thread api_caller(ReadHTTP, boost::ref(stream), boost::ref(mapHeaders), boost::ref(strRequest));
2260 if (!api_caller.timed_join(boost::posix_time::seconds(GetArg("-rpctimeout", 30))))
2263 printf("ThreadRPCServer ReadHTTP timeout\n");
2267 // Check authorization
2268 if (mapHeaders.count("authorization") == 0)
2270 stream << HTTPReply(401, "") << std::flush;
2273 if (!HTTPAuthorized(mapHeaders))
2275 printf("ThreadRPCServer incorrect password attempt from %s\n",peer.address().to_string().c_str());
2276 /* Deter brute-forcing short passwords.
2277 If this results in a DOS the user really
2278 shouldn't have their RPC port exposed.*/
2279 if (mapArgs["-rpcpassword"].size() < 20)
2282 stream << HTTPReply(401, "") << std::flush;
2286 Value id = Value::null;
2291 if (!read_string(strRequest, valRequest) || valRequest.type() != obj_type)
2292 throw JSONRPCError(-32700, "Parse error");
2293 const Object& request = valRequest.get_obj();
2295 // Parse id now so errors from here on will have the id
2296 id = find_value(request, "id");
2299 Value valMethod = find_value(request, "method");
2300 if (valMethod.type() == null_type)
2301 throw JSONRPCError(-32600, "Missing method");
2302 if (valMethod.type() != str_type)
2303 throw JSONRPCError(-32600, "Method must be a string");
2304 string strMethod = valMethod.get_str();
2305 if (strMethod != "getwork" && strMethod != "getmemorypool")
2306 printf("ThreadRPCServer method=%s\n", strMethod.c_str());
2309 Value valParams = find_value(request, "params");
2311 if (valParams.type() == array_type)
2312 params = valParams.get_array();
2313 else if (valParams.type() == null_type)
2316 throw JSONRPCError(-32600, "Params must be an array");
2319 map<string, rpcfn_type>::iterator mi = mapCallTable.find(strMethod);
2320 if (mi == mapCallTable.end())
2321 throw JSONRPCError(-32601, "Method not found");
2323 // Observe safe mode
2324 string strWarning = GetWarnings("rpc");
2325 if (strWarning != "" && !GetBoolArg("-disablesafemode") && !setAllowInSafeMode.count(strMethod))
2326 throw JSONRPCError(-2, string("Safe mode: ") + strWarning);
2332 CRITICAL_BLOCK(cs_main)
2333 CRITICAL_BLOCK(pwalletMain->cs_wallet)
2334 result = (*(*mi).second)(params, false);
2337 string strReply = JSONRPCReply(result, Value::null, id);
2338 stream << HTTPReply(200, strReply) << std::flush;
2340 catch (std::exception& e)
2342 ErrorReply(stream, JSONRPCError(-1, e.what()), id);
2345 catch (Object& objError)
2347 ErrorReply(stream, objError, id);
2349 catch (std::exception& e)
2351 ErrorReply(stream, JSONRPCError(-32700, e.what()), id);
2359 Object CallRPC(const string& strMethod, const Array& params)
2361 if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
2362 throw runtime_error(strprintf(
2363 _("You must set rpcpassword=<password> in the configuration file:\n%s\n"
2364 "If the file does not exist, create it with owner-readable-only file permissions."),
2365 GetConfigFile().c_str()));
2367 // Connect to localhost
2368 bool fUseSSL = GetBoolArg("-rpcssl");
2370 asio::io_service io_service;
2371 ssl::context context(io_service, ssl::context::sslv23);
2372 context.set_options(ssl::context::no_sslv2);
2373 SSLStream sslStream(io_service, context);
2374 SSLIOStreamDevice d(sslStream, fUseSSL);
2375 iostreams::stream<SSLIOStreamDevice> stream(d);
2376 if (!d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332")))
2377 throw runtime_error("couldn't connect to server");
2380 throw runtime_error("-rpcssl=1, but bitcoin compiled without full openssl libraries.");
2382 ip::tcp::iostream stream(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332"));
2384 throw runtime_error("couldn't connect to server");
2388 // HTTP basic authentication
2389 string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
2390 map<string, string> mapRequestHeaders;
2391 mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64;
2394 string strRequest = JSONRPCRequest(strMethod, params, 1);
2395 string strPost = HTTPPost(strRequest, mapRequestHeaders);
2396 stream << strPost << std::flush;
2399 map<string, string> mapHeaders;
2401 int nStatus = ReadHTTP(stream, mapHeaders, strReply);
2403 throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
2404 else if (nStatus >= 400 && nStatus != 400 && nStatus != 404 && nStatus != 500)
2405 throw runtime_error(strprintf("server returned HTTP error %d", nStatus));
2406 else if (strReply.empty())
2407 throw runtime_error("no response from server");
2411 if (!read_string(strReply, valReply))
2412 throw runtime_error("couldn't parse reply from server");
2413 const Object& reply = valReply.get_obj();
2415 throw runtime_error("expected reply to have result, error and id properties");
2423 template<typename T>
2424 void ConvertTo(Value& value)
2426 if (value.type() == str_type)
2428 // reinterpret string as unquoted json value
2430 if (!read_string(value.get_str(), value2))
2431 throw runtime_error("type mismatch");
2432 value = value2.get_value<T>();
2436 value = value.get_value<T>();
2440 int CommandLineRPC(int argc, char *argv[])
2447 while (argc > 1 && IsSwitchChar(argv[1][0]))
2455 throw runtime_error("too few parameters");
2456 string strMethod = argv[1];
2458 // Parameters default to strings
2460 for (int i = 2; i < argc; i++)
2461 params.push_back(argv[i]);
2462 int n = params.size();
2465 // Special case non-string parameter types
2467 if (strMethod == "setgenerate" && n > 0) ConvertTo<bool>(params[0]);
2468 if (strMethod == "setgenerate" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2469 if (strMethod == "sendtoaddress" && n > 1) ConvertTo<double>(params[1]);
2470 if (strMethod == "settxfee" && n > 0) ConvertTo<double>(params[0]);
2471 if (strMethod == "getreceivedbyaddress" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2472 if (strMethod == "getreceivedbyaccount" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2473 if (strMethod == "listreceivedbyaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2474 if (strMethod == "listreceivedbyaddress" && n > 1) ConvertTo<bool>(params[1]);
2475 if (strMethod == "listreceivedbyaccount" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2476 if (strMethod == "listreceivedbyaccount" && n > 1) ConvertTo<bool>(params[1]);
2477 if (strMethod == "getbalance" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2478 if (strMethod == "move" && n > 2) ConvertTo<double>(params[2]);
2479 if (strMethod == "move" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2480 if (strMethod == "sendfrom" && n > 2) ConvertTo<double>(params[2]);
2481 if (strMethod == "sendfrom" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2482 if (strMethod == "listtransactions" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2483 if (strMethod == "listtransactions" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2484 if (strMethod == "listaccounts" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2485 if (strMethod == "walletpassphrase" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2486 if (strMethod == "listsinceblock" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2487 if (strMethod == "sendmany" && n > 1)
2489 string s = params[1].get_str();
2491 if (!read_string(s, v) || v.type() != obj_type)
2492 throw runtime_error("type mismatch");
2493 params[1] = v.get_obj();
2495 if (strMethod == "sendmany" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2498 Object reply = CallRPC(strMethod, params);
2501 const Value& result = find_value(reply, "result");
2502 const Value& error = find_value(reply, "error");
2504 if (error.type() != null_type)
2507 strPrint = "error: " + write_string(error, false);
2508 int code = find_value(error.get_obj(), "code").get_int();
2514 if (result.type() == null_type)
2516 else if (result.type() == str_type)
2517 strPrint = result.get_str();
2519 strPrint = write_string(result, true);
2522 catch (std::exception& e)
2524 strPrint = string("error: ") + e.what();
2529 PrintException(NULL, "CommandLineRPC()");
2534 fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
2543 int main(int argc, char *argv[])
2546 // Turn off microsoft heap dump noise
2547 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
2548 _CrtSetReportFile(_CRT_WARN, CreateFile("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0));
2550 setbuf(stdin, NULL);
2551 setbuf(stdout, NULL);
2552 setbuf(stderr, NULL);
2556 if (argc >= 2 && string(argv[1]) == "-server")
2558 printf("server ready\n");
2559 ThreadRPCServer(NULL);
2563 return CommandLineRPC(argc, argv);
2566 catch (std::exception& e) {
2567 PrintException(&e, "main()");
2569 PrintException(NULL, "main()");