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>
15 #include <boost/lexical_cast.hpp>
17 #include <boost/asio/ssl.hpp>
18 #include <boost/filesystem.hpp>
19 #include <boost/filesystem/fstream.hpp>
20 typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> SSLStream;
22 #include "json/json_spirit_reader_template.h"
23 #include "json/json_spirit_writer_template.h"
24 #include "json/json_spirit_utils.h"
25 #define printf OutputDebugStringF
26 // MinGW 3.4.5 gets "fatal error: had to relocate PCH" if the json headers are
27 // precompiled in headers.h. The problem might be when the pch file goes over
28 // a certain size around 145MB. If we need access to json_spirit outside this
29 // file, we could use the compiled json_spirit option.
32 using namespace boost;
33 using namespace boost::asio;
34 using namespace json_spirit;
36 void ThreadRPCServer2(void* parg);
37 typedef Value(*rpcfn_type)(const Array& params, bool fHelp);
38 extern map<string, rpcfn_type> mapCallTable;
40 static std::string strRPCUserColonPass;
42 static int64 nWalletUnlockTime;
43 static CCriticalSection cs_nWalletUnlockTime;
46 Object JSONRPCError(int code, const string& message)
49 error.push_back(Pair("code", code));
50 error.push_back(Pair("message", message));
55 void PrintConsole(const std::string &format, ...)
58 int limit = sizeof(buffer);
60 va_start(arg_ptr, format);
61 int ret = _vsnprintf(buffer, limit, format.c_str(), arg_ptr);
63 if (ret < 0 || ret >= limit)
69 fprintf(stdout, "%s", buffer);
73 int64 AmountFromValue(const Value& value)
75 double dAmount = value.get_real();
76 if (dAmount <= 0.0 || dAmount > 21000000.0)
77 throw JSONRPCError(-3, "Invalid amount");
78 int64 nAmount = roundint64(dAmount * COIN);
79 if (!MoneyRange(nAmount))
80 throw JSONRPCError(-3, "Invalid amount");
84 Value ValueFromAmount(int64 amount)
86 return (double)amount / (double)COIN;
89 void WalletTxToJSON(const CWalletTx& wtx, Object& entry)
91 entry.push_back(Pair("confirmations", wtx.GetDepthInMainChain()));
92 entry.push_back(Pair("txid", wtx.GetHash().GetHex()));
93 entry.push_back(Pair("time", (boost::int64_t)wtx.GetTxTime()));
94 BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue)
95 entry.push_back(Pair(item.first, item.second));
98 string AccountFromValue(const Value& value)
100 string strAccount = value.get_str();
101 if (strAccount == "*")
102 throw JSONRPCError(-11, "Invalid account name");
109 /// Note: This interface may still be subject to change.
113 Value help(const Array& params, bool fHelp)
115 if (fHelp || params.size() > 1)
118 "List commands, or get help for a command.");
121 if (params.size() > 0)
122 strCommand = params[0].get_str();
125 set<rpcfn_type> setDone;
126 for (map<string, rpcfn_type>::iterator mi = mapCallTable.begin(); mi != mapCallTable.end(); ++mi)
128 string strMethod = (*mi).first;
129 // We already filter duplicates, but these deprecated screw up the sort order
130 if (strMethod == "getamountreceived" ||
131 strMethod == "getallreceived" ||
132 strMethod == "getblocknumber" || // deprecated
133 (strMethod.find("label") != string::npos))
135 if (strCommand != "" && strMethod != strCommand)
140 rpcfn_type pfn = (*mi).second;
141 if (setDone.insert(pfn).second)
142 (*pfn)(params, true);
144 catch (std::exception& e)
146 // Help text is returned in an exception
147 string strHelp = string(e.what());
148 if (strCommand == "")
149 if (strHelp.find('\n') != -1)
150 strHelp = strHelp.substr(0, strHelp.find('\n'));
151 strRet += strHelp + "\n";
155 strRet = strprintf("help: unknown command: %s\n", strCommand.c_str());
156 strRet = strRet.substr(0,strRet.size()-1);
161 Value stop(const Array& params, bool fHelp)
163 if (fHelp || params.size() != 0)
166 "Stop bitcoin server.");
168 // Shutdown will take long enough that the response should get back
169 CreateThread(Shutdown, NULL);
170 return "bitcoin server stopping";
172 throw runtime_error("NYI: cannot shut down GUI with RPC command");
177 Value getblockcount(const Array& params, bool fHelp)
179 if (fHelp || params.size() != 0)
182 "Returns the number of blocks in the longest block chain.");
189 Value getblocknumber(const Array& params, bool fHelp)
191 if (fHelp || params.size() != 0)
194 "Deprecated. Use getblockcount.");
200 Value getconnectioncount(const Array& params, bool fHelp)
202 if (fHelp || params.size() != 0)
204 "getconnectioncount\n"
205 "Returns the number of connections to other nodes.");
207 return (int)vNodes.size();
211 double GetDifficulty()
213 // Floating point number that is a multiple of the minimum difficulty,
214 // minimum difficulty = 1.0.
216 if (pindexBest == NULL)
218 int nShift = (pindexBest->nBits >> 24) & 0xff;
221 (double)0x0000ffff / (double)(pindexBest->nBits & 0x00ffffff);
237 Value getdifficulty(const Array& params, bool fHelp)
239 if (fHelp || params.size() != 0)
242 "Returns the proof-of-work difficulty as a multiple of the minimum difficulty.");
244 return GetDifficulty();
248 Value getgenerate(const Array& params, bool fHelp)
250 if (fHelp || params.size() != 0)
253 "Returns true or false.");
255 return (bool)fGenerateBitcoins;
259 Value setgenerate(const Array& params, bool fHelp)
261 if (fHelp || params.size() < 1 || params.size() > 2)
263 "setgenerate <generate> [genproclimit]\n"
264 "<generate> is true or false to turn generation on or off.\n"
265 "Generation is limited to [genproclimit] processors, -1 is unlimited.");
267 bool fGenerate = true;
268 if (params.size() > 0)
269 fGenerate = params[0].get_bool();
271 if (params.size() > 1)
273 int nGenProcLimit = params[1].get_int();
274 fLimitProcessors = (nGenProcLimit != -1);
275 WriteSetting("fLimitProcessors", fLimitProcessors);
276 if (nGenProcLimit != -1)
277 WriteSetting("nLimitProcessors", nLimitProcessors = nGenProcLimit);
278 if (nGenProcLimit == 0)
282 GenerateBitcoins(fGenerate, pwalletMain);
287 Value gethashespersec(const Array& params, bool fHelp)
289 if (fHelp || params.size() != 0)
292 "Returns a recent hashes per second performance measurement while generating.");
294 if (GetTimeMillis() - nHPSTimerStart > 8000)
295 return (boost::int64_t)0;
296 return (boost::int64_t)dHashesPerSec;
300 Value getinfo(const Array& params, bool fHelp)
302 if (fHelp || params.size() != 0)
305 "Returns an object containing various state info.");
308 obj.push_back(Pair("version", (int)VERSION));
309 obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance())));
310 obj.push_back(Pair("blocks", (int)nBestHeight));
311 obj.push_back(Pair("connections", (int)vNodes.size()));
312 obj.push_back(Pair("proxy", (fUseProxy ? addrProxy.ToStringIPPort() : string())));
313 obj.push_back(Pair("generate", (bool)fGenerateBitcoins));
314 obj.push_back(Pair("genproclimit", (int)(fLimitProcessors ? nLimitProcessors : -1)));
315 obj.push_back(Pair("difficulty", (double)GetDifficulty()));
316 obj.push_back(Pair("hashespersec", gethashespersec(params, false)));
317 obj.push_back(Pair("testnet", fTestNet));
318 obj.push_back(Pair("keypoololdest", (boost::int64_t)pwalletMain->GetOldestKeyPoolTime()));
319 obj.push_back(Pair("keypoolsize", pwalletMain->GetKeyPoolSize()));
320 obj.push_back(Pair("paytxfee", ValueFromAmount(nTransactionFee)));
321 if (pwalletMain->IsCrypted())
322 obj.push_back(Pair("unlocked_until", (boost::int64_t)nWalletUnlockTime));
323 obj.push_back(Pair("errors", GetWarnings("statusbar")));
328 Value getnewaddress(const Array& params, bool fHelp)
330 if (fHelp || params.size() > 1)
332 "getnewaddress [account]\n"
333 "Returns a new bitcoin address for receiving payments. "
334 "If [account] is specified (recommended), it is added to the address book "
335 "so payments received with the address will be credited to [account].");
337 // Parse the account first so we don't generate a key if there's an error
339 if (params.size() > 0)
340 strAccount = AccountFromValue(params[0]);
342 if (!pwalletMain->IsLocked())
343 pwalletMain->TopUpKeyPool();
345 // Generate a new key that is added to wallet
346 std::vector<unsigned char> newKey;
347 if (!pwalletMain->GetKeyFromPool(newKey, false))
348 throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
349 CBitcoinAddress address(newKey);
351 pwalletMain->SetAddressBookName(address, strAccount);
353 return address.ToString();
357 CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false)
359 CWalletDB walletdb(pwalletMain->strWalletFile);
362 walletdb.ReadAccount(strAccount, account);
364 bool bKeyUsed = false;
366 // Check if the current key has been used
367 if (!account.vchPubKey.empty())
369 CScript scriptPubKey;
370 scriptPubKey.SetBitcoinAddress(account.vchPubKey);
371 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
372 it != pwalletMain->mapWallet.end() && !account.vchPubKey.empty();
375 const CWalletTx& wtx = (*it).second;
376 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
377 if (txout.scriptPubKey == scriptPubKey)
382 // Generate a new key
383 if (account.vchPubKey.empty() || bForceNew || bKeyUsed)
385 if (!pwalletMain->GetKeyFromPool(account.vchPubKey, false))
386 throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
388 pwalletMain->SetAddressBookName(CBitcoinAddress(account.vchPubKey), strAccount);
389 walletdb.WriteAccount(strAccount, account);
392 return CBitcoinAddress(account.vchPubKey);
395 Value getaccountaddress(const Array& params, bool fHelp)
397 if (fHelp || params.size() != 1)
399 "getaccountaddress <account>\n"
400 "Returns the current bitcoin address for receiving payments to this account.");
402 // Parse the account first so we don't generate a key if there's an error
403 string strAccount = AccountFromValue(params[0]);
407 ret = GetAccountAddress(strAccount).ToString();
414 Value setaccount(const Array& params, bool fHelp)
416 if (fHelp || params.size() < 1 || params.size() > 2)
418 "setaccount <bitcoinaddress> <account>\n"
419 "Sets the account associated with the given address.");
421 CBitcoinAddress address(params[0].get_str());
422 if (!address.IsValid())
423 throw JSONRPCError(-5, "Invalid bitcoin address");
427 if (params.size() > 1)
428 strAccount = AccountFromValue(params[1]);
430 // Detect when changing the account of an address that is the 'unused current key' of another account:
431 if (pwalletMain->mapAddressBook.count(address))
433 string strOldAccount = pwalletMain->mapAddressBook[address];
434 if (address == GetAccountAddress(strOldAccount))
435 GetAccountAddress(strOldAccount, true);
438 pwalletMain->SetAddressBookName(address, strAccount);
444 Value getaccount(const Array& params, bool fHelp)
446 if (fHelp || params.size() != 1)
448 "getaccount <bitcoinaddress>\n"
449 "Returns the account associated with the given address.");
451 CBitcoinAddress address(params[0].get_str());
452 if (!address.IsValid())
453 throw JSONRPCError(-5, "Invalid bitcoin address");
456 map<CBitcoinAddress, string>::iterator mi = pwalletMain->mapAddressBook.find(address);
457 if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.empty())
458 strAccount = (*mi).second;
463 Value getaddressesbyaccount(const Array& params, bool fHelp)
465 if (fHelp || params.size() != 1)
467 "getaddressesbyaccount <account>\n"
468 "Returns the list of addresses for the given account.");
470 string strAccount = AccountFromValue(params[0]);
472 // Find all addresses that have the given account
474 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
476 const CBitcoinAddress& address = item.first;
477 const string& strName = item.second;
478 if (strName == strAccount)
479 ret.push_back(address.ToString());
484 Value settxfee(const Array& params, bool fHelp)
486 if (fHelp || params.size() < 1 || params.size() > 1)
488 "settxfee <amount>\n"
489 "<amount> is a real and is rounded to the nearest 0.00000001");
493 if (params[0].get_real() != 0.0)
494 nAmount = AmountFromValue(params[0]); // rejects 0.0 amounts
496 nTransactionFee = nAmount;
500 Value sendtoaddress(const Array& params, bool fHelp)
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\n"
506 "requires wallet passphrase to be set with walletpassphrase first");
507 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
509 "sendtoaddress <bitcoinaddress> <amount> [comment] [comment-to]\n"
510 "<amount> is a real and is rounded to the nearest 0.00000001");
512 CBitcoinAddress address(params[0].get_str());
513 if (!address.IsValid())
514 throw JSONRPCError(-5, "Invalid bitcoin address");
517 int64 nAmount = AmountFromValue(params[1]);
521 if (params.size() > 2 && params[2].type() != null_type && !params[2].get_str().empty())
522 wtx.mapValue["comment"] = params[2].get_str();
523 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
524 wtx.mapValue["to"] = params[3].get_str();
526 if (pwalletMain->IsLocked())
527 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
529 string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
531 throw JSONRPCError(-4, strError);
533 return wtx.GetHash().GetHex();
536 static const string strMessageMagic = "Bitcoin Signed Message:\n";
538 Value signmessage(const Array& params, bool fHelp)
540 if (fHelp || params.size() != 2)
542 "signmessage <bitcoinaddress> <message>\n"
543 "Sign a message with the private key of an address");
545 if (pwalletMain->IsLocked())
546 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
548 string strAddress = params[0].get_str();
549 string strMessage = params[1].get_str();
551 CBitcoinAddress addr(strAddress);
553 throw JSONRPCError(-3, "Invalid address");
556 if (!pwalletMain->GetKey(addr, key))
557 throw JSONRPCError(-4, "Private key not available");
559 CDataStream ss(SER_GETHASH);
560 ss << strMessageMagic;
563 vector<unsigned char> vchSig;
564 if (!key.SignCompact(Hash(ss.begin(), ss.end()), vchSig))
565 throw JSONRPCError(-5, "Sign failed");
567 return EncodeBase64(&vchSig[0], vchSig.size());
570 Value verifymessage(const Array& params, bool fHelp)
572 if (fHelp || params.size() != 3)
574 "verifymessage <bitcoinaddress> <signature> <message>\n"
575 "Verify a signed message");
577 string strAddress = params[0].get_str();
578 string strSign = params[1].get_str();
579 string strMessage = params[2].get_str();
581 CBitcoinAddress addr(strAddress);
583 throw JSONRPCError(-3, "Invalid address");
585 bool fInvalid = false;
586 vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid);
589 throw JSONRPCError(-5, "Malformed base64 encoding");
591 CDataStream ss(SER_GETHASH);
592 ss << strMessageMagic;
596 if (!key.SetCompactSignature(Hash(ss.begin(), ss.end()), vchSig))
599 return (CBitcoinAddress(key.GetPubKey()) == addr);
603 Value getreceivedbyaddress(const Array& params, bool fHelp)
605 if (fHelp || params.size() < 1 || params.size() > 2)
607 "getreceivedbyaddress <bitcoinaddress> [minconf=1]\n"
608 "Returns the total amount received by <bitcoinaddress> in transactions with at least [minconf] confirmations.");
611 CBitcoinAddress address = CBitcoinAddress(params[0].get_str());
612 CScript scriptPubKey;
613 if (!address.IsValid())
614 throw JSONRPCError(-5, "Invalid bitcoin address");
615 scriptPubKey.SetBitcoinAddress(address);
616 if (!IsMine(*pwalletMain,scriptPubKey))
619 // Minimum confirmations
621 if (params.size() > 1)
622 nMinDepth = params[1].get_int();
626 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
628 const CWalletTx& wtx = (*it).second;
629 if (wtx.IsCoinBase() || !wtx.IsFinal())
632 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
633 if (txout.scriptPubKey == scriptPubKey)
634 if (wtx.GetDepthInMainChain() >= nMinDepth)
635 nAmount += txout.nValue;
638 return ValueFromAmount(nAmount);
642 void GetAccountAddresses(string strAccount, set<CBitcoinAddress>& setAddress)
644 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
646 const CBitcoinAddress& address = item.first;
647 const string& strName = item.second;
648 if (strName == strAccount)
649 setAddress.insert(address);
654 Value getreceivedbyaccount(const Array& params, bool fHelp)
656 if (fHelp || params.size() < 1 || params.size() > 2)
658 "getreceivedbyaccount <account> [minconf=1]\n"
659 "Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.");
661 // Minimum confirmations
663 if (params.size() > 1)
664 nMinDepth = params[1].get_int();
666 // Get the set of pub keys that have the label
667 string strAccount = AccountFromValue(params[0]);
668 set<CBitcoinAddress> setAddress;
669 GetAccountAddresses(strAccount, setAddress);
673 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
675 const CWalletTx& wtx = (*it).second;
676 if (wtx.IsCoinBase() || !wtx.IsFinal())
679 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
681 CBitcoinAddress address;
682 if (ExtractAddress(txout.scriptPubKey, pwalletMain, address) && setAddress.count(address))
683 if (wtx.GetDepthInMainChain() >= nMinDepth)
684 nAmount += txout.nValue;
688 return (double)nAmount / (double)COIN;
692 int64 GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth)
696 // Tally wallet transactions
697 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
699 const CWalletTx& wtx = (*it).second;
703 int64 nGenerated, nReceived, nSent, nFee;
704 wtx.GetAccountAmounts(strAccount, nGenerated, nReceived, nSent, nFee);
706 if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
707 nBalance += nReceived;
708 nBalance += nGenerated - nSent - nFee;
711 // Tally internal accounting entries
712 nBalance += walletdb.GetAccountCreditDebit(strAccount);
717 int64 GetAccountBalance(const string& strAccount, int nMinDepth)
719 CWalletDB walletdb(pwalletMain->strWalletFile);
720 return GetAccountBalance(walletdb, strAccount, nMinDepth);
724 Value getbalance(const Array& params, bool fHelp)
726 if (fHelp || params.size() > 2)
728 "getbalance [account] [minconf=1]\n"
729 "If [account] is not specified, returns the server's total available balance.\n"
730 "If [account] is specified, returns the balance in the account.");
732 if (params.size() == 0)
733 return ValueFromAmount(pwalletMain->GetBalance());
736 if (params.size() > 1)
737 nMinDepth = params[1].get_int();
739 if (params[0].get_str() == "*") {
740 // Calculate total balance a different way from GetBalance()
741 // (GetBalance() sums up all unspent TxOuts)
742 // getbalance and getbalance '*' should always return the same number.
744 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
746 const CWalletTx& wtx = (*it).second;
750 int64 allGeneratedImmature, allGeneratedMature, allFee;
751 allGeneratedImmature = allGeneratedMature = allFee = 0;
752 string strSentAccount;
753 list<pair<CBitcoinAddress, int64> > listReceived;
754 list<pair<CBitcoinAddress, int64> > listSent;
755 wtx.GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount);
756 if (wtx.GetDepthInMainChain() >= nMinDepth)
757 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listReceived)
758 nBalance += r.second;
759 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listSent)
760 nBalance -= r.second;
762 nBalance += allGeneratedMature;
764 return ValueFromAmount(nBalance);
767 string strAccount = AccountFromValue(params[0]);
769 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
771 return ValueFromAmount(nBalance);
775 Value movecmd(const Array& params, bool fHelp)
777 if (fHelp || params.size() < 3 || params.size() > 5)
779 "move <fromaccount> <toaccount> <amount> [minconf=1] [comment]\n"
780 "Move from one account in your wallet to another.");
782 string strFrom = AccountFromValue(params[0]);
783 string strTo = AccountFromValue(params[1]);
784 int64 nAmount = AmountFromValue(params[2]);
785 if (params.size() > 3)
786 // unused parameter, used to be nMinDepth, keep type-checking it though
787 (void)params[3].get_int();
789 if (params.size() > 4)
790 strComment = params[4].get_str();
792 CWalletDB walletdb(pwalletMain->strWalletFile);
795 int64 nNow = GetAdjustedTime();
798 CAccountingEntry debit;
799 debit.strAccount = strFrom;
800 debit.nCreditDebit = -nAmount;
802 debit.strOtherAccount = strTo;
803 debit.strComment = strComment;
804 walletdb.WriteAccountingEntry(debit);
807 CAccountingEntry credit;
808 credit.strAccount = strTo;
809 credit.nCreditDebit = nAmount;
811 credit.strOtherAccount = strFrom;
812 credit.strComment = strComment;
813 walletdb.WriteAccountingEntry(credit);
815 walletdb.TxnCommit();
821 Value sendfrom(const Array& params, bool fHelp)
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\n"
827 "requires wallet passphrase to be set with walletpassphrase first");
828 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
830 "sendfrom <fromaccount> <tobitcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
831 "<amount> is a real and is rounded to the nearest 0.00000001");
833 string strAccount = AccountFromValue(params[0]);
834 CBitcoinAddress address(params[1].get_str());
835 if (!address.IsValid())
836 throw JSONRPCError(-5, "Invalid bitcoin address");
837 int64 nAmount = AmountFromValue(params[2]);
839 if (params.size() > 3)
840 nMinDepth = params[3].get_int();
843 wtx.strFromAccount = strAccount;
844 if (params.size() > 4 && params[4].type() != null_type && !params[4].get_str().empty())
845 wtx.mapValue["comment"] = params[4].get_str();
846 if (params.size() > 5 && params[5].type() != null_type && !params[5].get_str().empty())
847 wtx.mapValue["to"] = params[5].get_str();
849 if (pwalletMain->IsLocked())
850 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
853 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
854 if (nAmount > nBalance)
855 throw JSONRPCError(-6, "Account has insufficient funds");
858 string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
860 throw JSONRPCError(-4, strError);
862 return wtx.GetHash().GetHex();
866 Value sendmany(const Array& params, bool fHelp)
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\n"
872 "requires wallet passphrase to be set with walletpassphrase first");
873 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
875 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
876 "amounts are double-precision floating point numbers");
878 string strAccount = AccountFromValue(params[0]);
879 Object sendTo = params[1].get_obj();
881 if (params.size() > 2)
882 nMinDepth = params[2].get_int();
885 wtx.strFromAccount = strAccount;
886 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
887 wtx.mapValue["comment"] = params[3].get_str();
889 set<CBitcoinAddress> setAddress;
890 vector<pair<CScript, int64> > vecSend;
892 int64 totalAmount = 0;
893 BOOST_FOREACH(const Pair& s, sendTo)
895 CBitcoinAddress address(s.name_);
896 if (!address.IsValid())
897 throw JSONRPCError(-5, string("Invalid bitcoin address:")+s.name_);
899 if (setAddress.count(address))
900 throw JSONRPCError(-8, string("Invalid parameter, duplicated address: ")+s.name_);
901 setAddress.insert(address);
903 CScript scriptPubKey;
904 scriptPubKey.SetBitcoinAddress(address);
905 int64 nAmount = AmountFromValue(s.value_);
906 totalAmount += nAmount;
908 vecSend.push_back(make_pair(scriptPubKey, nAmount));
911 if (pwalletMain->IsLocked())
912 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
915 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
916 if (totalAmount > nBalance)
917 throw JSONRPCError(-6, "Account has insufficient funds");
920 CReserveKey keyChange(pwalletMain);
921 int64 nFeeRequired = 0;
922 bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired);
925 if (totalAmount + nFeeRequired > pwalletMain->GetBalance())
926 throw JSONRPCError(-6, "Insufficient funds");
927 throw JSONRPCError(-4, "Transaction creation failed");
929 if (!pwalletMain->CommitTransaction(wtx, keyChange))
930 throw JSONRPCError(-4, "Transaction commit failed");
932 return wtx.GetHash().GetHex();
947 Value ListReceived(const Array& params, bool fByAccounts)
949 // Minimum confirmations
951 if (params.size() > 0)
952 nMinDepth = params[0].get_int();
954 // Whether to include empty accounts
955 bool fIncludeEmpty = false;
956 if (params.size() > 1)
957 fIncludeEmpty = params[1].get_bool();
960 map<CBitcoinAddress, tallyitem> mapTally;
961 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
963 const CWalletTx& wtx = (*it).second;
964 if (wtx.IsCoinBase() || !wtx.IsFinal())
967 int nDepth = wtx.GetDepthInMainChain();
968 if (nDepth < nMinDepth)
971 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
973 CBitcoinAddress address;
974 if (!ExtractAddress(txout.scriptPubKey, pwalletMain, address) || !address.IsValid())
977 tallyitem& item = mapTally[address];
978 item.nAmount += txout.nValue;
979 item.nConf = min(item.nConf, nDepth);
985 map<string, tallyitem> mapAccountTally;
986 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
988 const CBitcoinAddress& address = item.first;
989 const string& strAccount = item.second;
990 map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
991 if (it == mapTally.end() && !fIncludeEmpty)
996 if (it != mapTally.end())
998 nAmount = (*it).second.nAmount;
999 nConf = (*it).second.nConf;
1004 tallyitem& item = mapAccountTally[strAccount];
1005 item.nAmount += nAmount;
1006 item.nConf = min(item.nConf, nConf);
1011 obj.push_back(Pair("address", address.ToString()));
1012 obj.push_back(Pair("account", strAccount));
1013 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1014 obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf)));
1021 for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
1023 int64 nAmount = (*it).second.nAmount;
1024 int nConf = (*it).second.nConf;
1026 obj.push_back(Pair("account", (*it).first));
1027 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1028 obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf)));
1036 Value listreceivedbyaddress(const Array& params, bool fHelp)
1038 if (fHelp || params.size() > 2)
1039 throw runtime_error(
1040 "listreceivedbyaddress [minconf=1] [includeempty=false]\n"
1041 "[minconf] is the minimum number of confirmations before payments are included.\n"
1042 "[includeempty] whether to include addresses that haven't received any payments.\n"
1043 "Returns an array of objects containing:\n"
1044 " \"address\" : receiving address\n"
1045 " \"account\" : the account of the receiving address\n"
1046 " \"amount\" : total amount received by the address\n"
1047 " \"confirmations\" : number of confirmations of the most recent transaction included");
1049 return ListReceived(params, false);
1052 Value listreceivedbyaccount(const Array& params, bool fHelp)
1054 if (fHelp || params.size() > 2)
1055 throw runtime_error(
1056 "listreceivedbyaccount [minconf=1] [includeempty=false]\n"
1057 "[minconf] is the minimum number of confirmations before payments are included.\n"
1058 "[includeempty] whether to include accounts that haven't received any payments.\n"
1059 "Returns an array of objects containing:\n"
1060 " \"account\" : the account of the receiving addresses\n"
1061 " \"amount\" : total amount received by addresses with this account\n"
1062 " \"confirmations\" : number of confirmations of the most recent transaction included");
1064 return ListReceived(params, true);
1067 void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret)
1069 int64 nGeneratedImmature, nGeneratedMature, nFee;
1070 string strSentAccount;
1071 list<pair<CBitcoinAddress, int64> > listReceived;
1072 list<pair<CBitcoinAddress, int64> > listSent;
1073 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1075 bool fAllAccounts = (strAccount == string("*"));
1077 // Generated blocks assigned to account ""
1078 if ((nGeneratedMature+nGeneratedImmature) != 0 && (fAllAccounts || strAccount == ""))
1081 entry.push_back(Pair("account", string("")));
1082 if (nGeneratedImmature)
1084 entry.push_back(Pair("category", wtx.GetDepthInMainChain() ? "immature" : "orphan"));
1085 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedImmature)));
1089 entry.push_back(Pair("category", "generate"));
1090 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedMature)));
1093 WalletTxToJSON(wtx, entry);
1094 ret.push_back(entry);
1098 if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
1100 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1103 entry.push_back(Pair("account", strSentAccount));
1104 entry.push_back(Pair("address", s.first.ToString()));
1105 entry.push_back(Pair("category", "send"));
1106 entry.push_back(Pair("amount", ValueFromAmount(-s.second)));
1107 entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
1109 WalletTxToJSON(wtx, entry);
1110 ret.push_back(entry);
1115 if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
1116 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1119 if (pwalletMain->mapAddressBook.count(r.first))
1120 account = pwalletMain->mapAddressBook[r.first];
1121 if (fAllAccounts || (account == strAccount))
1124 entry.push_back(Pair("account", account));
1125 entry.push_back(Pair("address", r.first.ToString()));
1126 entry.push_back(Pair("category", "receive"));
1127 entry.push_back(Pair("amount", ValueFromAmount(r.second)));
1129 WalletTxToJSON(wtx, entry);
1130 ret.push_back(entry);
1135 void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret)
1137 bool fAllAccounts = (strAccount == string("*"));
1139 if (fAllAccounts || acentry.strAccount == strAccount)
1142 entry.push_back(Pair("account", acentry.strAccount));
1143 entry.push_back(Pair("category", "move"));
1144 entry.push_back(Pair("time", (boost::int64_t)acentry.nTime));
1145 entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
1146 entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
1147 entry.push_back(Pair("comment", acentry.strComment));
1148 ret.push_back(entry);
1152 Value listtransactions(const Array& params, bool fHelp)
1154 if (fHelp || params.size() > 3)
1155 throw runtime_error(
1156 "listtransactions [account] [count=10] [from=0]\n"
1157 "Returns up to [count] most recent transactions skipping the first [from] transactions for account [account].");
1159 string strAccount = "*";
1160 if (params.size() > 0)
1161 strAccount = params[0].get_str();
1163 if (params.size() > 1)
1164 nCount = params[1].get_int();
1166 if (params.size() > 2)
1167 nFrom = params[2].get_int();
1170 CWalletDB walletdb(pwalletMain->strWalletFile);
1172 // Firs: get all CWalletTx and CAccountingEntry into a sorted-by-time multimap:
1173 typedef pair<CWalletTx*, CAccountingEntry*> TxPair;
1174 typedef multimap<int64, TxPair > TxItems;
1177 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1179 CWalletTx* wtx = &((*it).second);
1180 txByTime.insert(make_pair(wtx->GetTxTime(), TxPair(wtx, (CAccountingEntry*)0)));
1182 list<CAccountingEntry> acentries;
1183 walletdb.ListAccountCreditDebit(strAccount, acentries);
1184 BOOST_FOREACH(CAccountingEntry& entry, acentries)
1186 txByTime.insert(make_pair(entry.nTime, TxPair((CWalletTx*)0, &entry)));
1189 // Now: iterate backwards until we have nCount items to return:
1190 TxItems::reverse_iterator it = txByTime.rbegin();
1191 if (txByTime.size() > nFrom) std::advance(it, nFrom);
1192 for (; it != txByTime.rend(); ++it)
1194 CWalletTx *const pwtx = (*it).second.first;
1196 ListTransactions(*pwtx, strAccount, 0, true, ret);
1197 CAccountingEntry *const pacentry = (*it).second.second;
1199 AcentryToJSON(*pacentry, strAccount, ret);
1201 if (ret.size() >= nCount) break;
1203 // ret is now newest to oldest
1205 // Make sure we return only last nCount items (sends-to-self might give us an extra):
1206 if (ret.size() > nCount)
1208 Array::iterator last = ret.begin();
1209 std::advance(last, nCount);
1210 ret.erase(last, ret.end());
1212 std::reverse(ret.begin(), ret.end()); // oldest to newest
1217 Value listaccounts(const Array& params, bool fHelp)
1219 if (fHelp || params.size() > 1)
1220 throw runtime_error(
1221 "listaccounts [minconf=1]\n"
1222 "Returns Object that has account names as keys, account balances as values.");
1225 if (params.size() > 0)
1226 nMinDepth = params[0].get_int();
1228 map<string, int64> mapAccountBalances;
1229 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& entry, pwalletMain->mapAddressBook) {
1230 if (pwalletMain->HaveKey(entry.first)) // This address belongs to me
1231 mapAccountBalances[entry.second] = 0;
1234 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1236 const CWalletTx& wtx = (*it).second;
1237 int64 nGeneratedImmature, nGeneratedMature, nFee;
1238 string strSentAccount;
1239 list<pair<CBitcoinAddress, int64> > listReceived;
1240 list<pair<CBitcoinAddress, int64> > listSent;
1241 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1242 mapAccountBalances[strSentAccount] -= nFee;
1243 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1244 mapAccountBalances[strSentAccount] -= s.second;
1245 if (wtx.GetDepthInMainChain() >= nMinDepth)
1247 mapAccountBalances[""] += nGeneratedMature;
1248 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1249 if (pwalletMain->mapAddressBook.count(r.first))
1250 mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second;
1252 mapAccountBalances[""] += r.second;
1256 list<CAccountingEntry> acentries;
1257 CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
1258 BOOST_FOREACH(const CAccountingEntry& entry, acentries)
1259 mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
1262 BOOST_FOREACH(const PAIRTYPE(string, int64)& accountBalance, mapAccountBalances) {
1263 ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
1268 Value listsinceblock(const Array& params, bool fHelp)
1271 throw runtime_error(
1272 "listsinceblock [blockid] [target-confirmations]\n"
1273 "Get all transactions in blocks since block [blockid], or all transactions if omitted");
1275 CBlockIndex *pindex = NULL;
1276 int target_confirms = 1;
1278 if (params.size() > 0)
1280 uint256 blockId = 0;
1282 blockId.SetHex(params[0].get_str());
1283 pindex = CBlockLocator(blockId).GetBlockIndex();
1286 if (params.size() > 1)
1288 target_confirms = params[1].get_int();
1290 if (target_confirms < 1)
1291 throw JSONRPCError(-8, "Invalid parameter");
1294 int depth = pindex ? (1 + nBestHeight - pindex->nHeight) : -1;
1298 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++)
1300 CWalletTx tx = (*it).second;
1302 if (depth == -1 || tx.GetDepthInMainChain() < depth)
1303 ListTransactions(tx, "*", 0, true, transactions);
1308 if (target_confirms == 1)
1311 lastblock = hashBestChain;
1315 int target_height = pindexBest->nHeight + 1 - target_confirms;
1318 for (block = pindexBest;
1319 block && block->nHeight > target_height;
1320 block = block->pprev);
1322 lastblock = block ? block->GetBlockHash() : 0;
1326 ret.push_back(Pair("transactions", transactions));
1327 ret.push_back(Pair("lastblock", lastblock.GetHex()));
1332 Value gettransaction(const Array& params, bool fHelp)
1334 if (fHelp || params.size() != 1)
1335 throw runtime_error(
1336 "gettransaction <txid>\n"
1337 "Get detailed information about <txid>");
1340 hash.SetHex(params[0].get_str());
1344 if (!pwalletMain->mapWallet.count(hash))
1345 throw JSONRPCError(-5, "Invalid or non-wallet transaction id");
1346 const CWalletTx& wtx = pwalletMain->mapWallet[hash];
1348 int64 nCredit = wtx.GetCredit();
1349 int64 nDebit = wtx.GetDebit();
1350 int64 nNet = nCredit - nDebit;
1351 int64 nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0);
1353 entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
1355 entry.push_back(Pair("fee", ValueFromAmount(nFee)));
1357 WalletTxToJSON(pwalletMain->mapWallet[hash], entry);
1360 ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details);
1361 entry.push_back(Pair("details", details));
1367 Value backupwallet(const Array& params, bool fHelp)
1369 if (fHelp || params.size() != 1)
1370 throw runtime_error(
1371 "backupwallet <destination>\n"
1372 "Safely copies wallet.dat to destination, which can be a directory or a path with filename.");
1374 string strDest = params[0].get_str();
1375 BackupWallet(*pwalletMain, strDest);
1381 Value keypoolrefill(const Array& params, bool fHelp)
1383 if (pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1384 throw runtime_error(
1386 "Fills the keypool, requires wallet passphrase to be set.");
1387 if (!pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1388 throw runtime_error(
1390 "Fills the keypool.");
1392 if (pwalletMain->IsLocked())
1393 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
1395 pwalletMain->TopUpKeyPool();
1397 if (pwalletMain->GetKeyPoolSize() < GetArg("-keypool", 100))
1398 throw JSONRPCError(-4, "Error refreshing keypool.");
1404 void ThreadTopUpKeyPool(void* parg)
1406 pwalletMain->TopUpKeyPool();
1409 void ThreadCleanWalletPassphrase(void* parg)
1411 int64 nMyWakeTime = GetTime() + *((int*)parg);
1413 if (nWalletUnlockTime == 0)
1415 CRITICAL_BLOCK(cs_nWalletUnlockTime)
1417 nWalletUnlockTime = nMyWakeTime;
1420 while (GetTime() < nWalletUnlockTime)
1421 Sleep(GetTime() - nWalletUnlockTime);
1423 CRITICAL_BLOCK(cs_nWalletUnlockTime)
1425 nWalletUnlockTime = 0;
1430 CRITICAL_BLOCK(cs_nWalletUnlockTime)
1432 if (nWalletUnlockTime < nMyWakeTime)
1433 nWalletUnlockTime = nMyWakeTime;
1439 pwalletMain->Lock();
1444 Value walletpassphrase(const Array& params, bool fHelp)
1446 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1447 throw runtime_error(
1448 "walletpassphrase <passphrase> <timeout>\n"
1449 "Stores the wallet decryption key in memory for <timeout> seconds.");
1452 if (!pwalletMain->IsCrypted())
1453 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
1455 if (!pwalletMain->IsLocked())
1456 throw JSONRPCError(-17, "Error: Wallet is already unlocked.");
1458 // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
1459 SecureString strWalletPass;
1460 strWalletPass.reserve(100);
1461 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1462 // Alternately, find a way to make params[0] mlock()'d to begin with.
1463 strWalletPass = params[0].get_str().c_str();
1465 if (strWalletPass.length() > 0)
1467 if (!pwalletMain->Unlock(strWalletPass))
1468 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1471 throw runtime_error(
1472 "walletpassphrase <passphrase> <timeout>\n"
1473 "Stores the wallet decryption key in memory for <timeout> seconds.");
1475 CreateThread(ThreadTopUpKeyPool, NULL);
1476 int* pnSleepTime = new int(params[1].get_int());
1477 CreateThread(ThreadCleanWalletPassphrase, pnSleepTime);
1483 Value walletpassphrasechange(const Array& params, bool fHelp)
1485 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1486 throw runtime_error(
1487 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1488 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1491 if (!pwalletMain->IsCrypted())
1492 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
1494 // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
1495 // Alternately, find a way to make params[0] mlock()'d to begin with.
1496 SecureString strOldWalletPass;
1497 strOldWalletPass.reserve(100);
1498 strOldWalletPass = params[0].get_str().c_str();
1500 SecureString strNewWalletPass;
1501 strNewWalletPass.reserve(100);
1502 strNewWalletPass = params[1].get_str().c_str();
1504 if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
1505 throw runtime_error(
1506 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1507 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1509 if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
1510 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1516 Value walletlock(const Array& params, bool fHelp)
1518 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
1519 throw runtime_error(
1521 "Removes the wallet encryption key from memory, locking the wallet.\n"
1522 "After calling this method, you will need to call walletpassphrase again\n"
1523 "before being able to call any methods which require the wallet to be unlocked.");
1526 if (!pwalletMain->IsCrypted())
1527 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletlock was called.");
1529 pwalletMain->Lock();
1530 CRITICAL_BLOCK(cs_nWalletUnlockTime)
1532 nWalletUnlockTime = 0;
1539 Value encryptwallet(const Array& params, bool fHelp)
1541 if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
1542 throw runtime_error(
1543 "encryptwallet <passphrase>\n"
1544 "Encrypts the wallet with <passphrase>.");
1547 if (pwalletMain->IsCrypted())
1548 throw JSONRPCError(-15, "Error: running with an encrypted wallet, but encryptwallet was called.");
1551 // shutting down via RPC while the GUI is running does not work (yet):
1552 throw runtime_error("Not Yet Implemented: use GUI to encrypt wallet, not RPC command");
1555 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1556 // Alternately, find a way to make params[0] mlock()'d to begin with.
1557 SecureString strWalletPass;
1558 strWalletPass.reserve(100);
1559 strWalletPass = params[0].get_str().c_str();
1561 if (strWalletPass.length() < 1)
1562 throw runtime_error(
1563 "encryptwallet <passphrase>\n"
1564 "Encrypts the wallet with <passphrase>.");
1566 if (!pwalletMain->EncryptWallet(strWalletPass))
1567 throw JSONRPCError(-16, "Error: Failed to encrypt the wallet.");
1569 // BDB seems to have a bad habit of writing old data into
1570 // slack space in .dat files; that is bad if the old data is
1571 // unencrypted private keys. So:
1572 CreateThread(Shutdown, NULL);
1573 return "wallet encrypted; bitcoin server stopping, restart to run with encrypted wallet";
1577 Value validateaddress(const Array& params, bool fHelp)
1579 if (fHelp || params.size() != 1)
1580 throw runtime_error(
1581 "validateaddress <bitcoinaddress>\n"
1582 "Return information about <bitcoinaddress>.");
1584 CBitcoinAddress address(params[0].get_str());
1585 bool isValid = address.IsValid();
1588 ret.push_back(Pair("isvalid", isValid));
1591 // Call Hash160ToAddress() so we always return current ADDRESSVERSION
1592 // version of the address:
1593 string currentAddress = address.ToString();
1594 ret.push_back(Pair("address", currentAddress));
1595 ret.push_back(Pair("ismine", (pwalletMain->HaveKey(address) > 0)));
1596 if (pwalletMain->mapAddressBook.count(address))
1597 ret.push_back(Pair("account", pwalletMain->mapAddressBook[address]));
1603 Value getwork(const Array& params, bool fHelp)
1605 if (fHelp || params.size() > 1)
1606 throw runtime_error(
1608 "If [data] is not specified, returns formatted hash data to work on:\n"
1609 " \"midstate\" : precomputed hash state after hashing the first half of the data (DEPRECATED)\n" // deprecated
1610 " \"data\" : block data\n"
1611 " \"hash1\" : formatted hash buffer for second hash (DEPRECATED)\n" // deprecated
1612 " \"target\" : little endian hash target\n"
1613 "If [data] is specified, tries to solve the block and returns true if it was successful.");
1616 throw JSONRPCError(-9, "Bitcoin is not connected!");
1618 if (IsInitialBlockDownload())
1619 throw JSONRPCError(-10, "Bitcoin is downloading blocks...");
1621 typedef map<uint256, pair<CBlock*, CScript> > mapNewBlock_t;
1622 static mapNewBlock_t mapNewBlock;
1623 static vector<CBlock*> vNewBlock;
1624 static CReserveKey reservekey(pwalletMain);
1626 if (params.size() == 0)
1629 static unsigned int nTransactionsUpdatedLast;
1630 static CBlockIndex* pindexPrev;
1631 static int64 nStart;
1632 static CBlock* pblock;
1633 if (pindexPrev != pindexBest ||
1634 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60))
1636 if (pindexPrev != pindexBest)
1638 // Deallocate old blocks since they're obsolete now
1639 mapNewBlock.clear();
1640 BOOST_FOREACH(CBlock* pblock, vNewBlock)
1644 nTransactionsUpdatedLast = nTransactionsUpdated;
1645 pindexPrev = pindexBest;
1649 pblock = CreateNewBlock(reservekey);
1651 throw JSONRPCError(-7, "Out of memory");
1652 vNewBlock.push_back(pblock);
1656 pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
1659 // Update nExtraNonce
1660 static unsigned int nExtraNonce = 0;
1661 IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
1664 mapNewBlock[pblock->hashMerkleRoot] = make_pair(pblock, pblock->vtx[0].vin[0].scriptSig);
1666 // Prebuild hash buffers
1670 FormatHashBuffers(pblock, pmidstate, pdata, phash1);
1672 uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
1675 result.push_back(Pair("midstate", HexStr(BEGIN(pmidstate), END(pmidstate)))); // deprecated
1676 result.push_back(Pair("data", HexStr(BEGIN(pdata), END(pdata))));
1677 result.push_back(Pair("hash1", HexStr(BEGIN(phash1), END(phash1)))); // deprecated
1678 result.push_back(Pair("target", HexStr(BEGIN(hashTarget), END(hashTarget))));
1684 vector<unsigned char> vchData = ParseHex(params[0].get_str());
1685 if (vchData.size() != 128)
1686 throw JSONRPCError(-8, "Invalid parameter");
1687 CBlock* pdata = (CBlock*)&vchData[0];
1690 for (int i = 0; i < 128/4; i++)
1691 ((unsigned int*)pdata)[i] = ByteReverse(((unsigned int*)pdata)[i]);
1694 if (!mapNewBlock.count(pdata->hashMerkleRoot))
1696 CBlock* pblock = mapNewBlock[pdata->hashMerkleRoot].first;
1698 pblock->nTime = pdata->nTime;
1699 pblock->nNonce = pdata->nNonce;
1700 pblock->vtx[0].vin[0].scriptSig = mapNewBlock[pdata->hashMerkleRoot].second;
1701 pblock->hashMerkleRoot = pblock->BuildMerkleTree();
1703 return CheckWork(pblock, *pwalletMain, reservekey);
1708 Value getmemorypool(const Array& params, bool fHelp)
1710 if (fHelp || params.size() > 1)
1711 throw runtime_error(
1712 "getmemorypool [data]\n"
1713 "If [data] is not specified, returns data needed to construct a block to work on:\n"
1714 " \"version\" : block version\n"
1715 " \"previousblockhash\" : hash of current highest block\n"
1716 " \"transactions\" : contents of non-coinbase transactions that should be included in the next block\n"
1717 " \"coinbasevalue\" : maximum allowable input to coinbase transaction, including the generation award and transaction fees\n"
1718 " \"time\" : timestamp appropriate for next block\n"
1719 " \"bits\" : compressed target of next block\n"
1720 "If [data] is specified, tries to solve the block and returns true if it was successful.");
1722 if (params.size() == 0)
1725 throw JSONRPCError(-9, "Bitcoin is not connected!");
1727 if (IsInitialBlockDownload())
1728 throw JSONRPCError(-10, "Bitcoin is downloading blocks...");
1730 static CReserveKey reservekey(pwalletMain);
1733 static unsigned int nTransactionsUpdatedLast;
1734 static CBlockIndex* pindexPrev;
1735 static int64 nStart;
1736 static CBlock* pblock;
1737 if (pindexPrev != pindexBest ||
1738 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 5))
1740 nTransactionsUpdatedLast = nTransactionsUpdated;
1741 pindexPrev = pindexBest;
1747 pblock = CreateNewBlock(reservekey);
1749 throw JSONRPCError(-7, "Out of memory");
1753 pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
1757 BOOST_FOREACH(CTransaction tx, pblock->vtx) {
1764 transactions.push_back(HexStr(ssTx.begin(), ssTx.end()));
1768 result.push_back(Pair("version", pblock->nVersion));
1769 result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex()));
1770 result.push_back(Pair("transactions", transactions));
1771 result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue));
1772 result.push_back(Pair("time", (int64_t)pblock->nTime));
1778 uBits.nBits = htonl((int32_t)pblock->nBits);
1779 result.push_back(Pair("bits", HexStr(BEGIN(uBits.cBits), END(uBits.cBits))));
1786 CDataStream ssBlock(ParseHex(params[0].get_str()));
1790 return ProcessBlock(NULL, &pblock);
1808 pair<string, rpcfn_type> pCallTable[] =
1810 make_pair("help", &help),
1811 make_pair("stop", &stop),
1812 make_pair("getblockcount", &getblockcount),
1813 make_pair("getblocknumber", &getblocknumber),
1814 make_pair("getconnectioncount", &getconnectioncount),
1815 make_pair("getdifficulty", &getdifficulty),
1816 make_pair("getgenerate", &getgenerate),
1817 make_pair("setgenerate", &setgenerate),
1818 make_pair("gethashespersec", &gethashespersec),
1819 make_pair("getinfo", &getinfo),
1820 make_pair("getnewaddress", &getnewaddress),
1821 make_pair("getaccountaddress", &getaccountaddress),
1822 make_pair("setaccount", &setaccount),
1823 make_pair("getaccount", &getaccount),
1824 make_pair("getaddressesbyaccount", &getaddressesbyaccount),
1825 make_pair("sendtoaddress", &sendtoaddress),
1826 make_pair("getreceivedbyaddress", &getreceivedbyaddress),
1827 make_pair("getreceivedbyaccount", &getreceivedbyaccount),
1828 make_pair("listreceivedbyaddress", &listreceivedbyaddress),
1829 make_pair("listreceivedbyaccount", &listreceivedbyaccount),
1830 make_pair("backupwallet", &backupwallet),
1831 make_pair("keypoolrefill", &keypoolrefill),
1832 make_pair("walletpassphrase", &walletpassphrase),
1833 make_pair("walletpassphrasechange", &walletpassphrasechange),
1834 make_pair("walletlock", &walletlock),
1835 make_pair("encryptwallet", &encryptwallet),
1836 make_pair("validateaddress", &validateaddress),
1837 make_pair("getbalance", &getbalance),
1838 make_pair("move", &movecmd),
1839 make_pair("sendfrom", &sendfrom),
1840 make_pair("sendmany", &sendmany),
1841 make_pair("gettransaction", &gettransaction),
1842 make_pair("listtransactions", &listtransactions),
1843 make_pair("signmessage", &signmessage),
1844 make_pair("verifymessage", &verifymessage),
1845 make_pair("getwork", &getwork),
1846 make_pair("listaccounts", &listaccounts),
1847 make_pair("settxfee", &settxfee),
1848 make_pair("getmemorypool", &getmemorypool),
1849 make_pair("listsinceblock", &listsinceblock),
1851 map<string, rpcfn_type> mapCallTable(pCallTable, pCallTable + sizeof(pCallTable)/sizeof(pCallTable[0]));
1853 string pAllowInSafeMode[] =
1858 "getblocknumber", // deprecated
1859 "getconnectioncount",
1866 "getaccountaddress",
1868 "getaddressesbyaccount",
1877 set<string> setAllowInSafeMode(pAllowInSafeMode, pAllowInSafeMode + sizeof(pAllowInSafeMode)/sizeof(pAllowInSafeMode[0]));
1885 // This ain't Apache. We're just using HTTP header for the length field
1886 // and to be compatible with other JSON-RPC implementations.
1889 string HTTPPost(const string& strMsg, const map<string,string>& mapRequestHeaders)
1892 s << "POST / HTTP/1.1\r\n"
1893 << "User-Agent: bitcoin-json-rpc/" << FormatFullVersion() << "\r\n"
1894 << "Host: 127.0.0.1\r\n"
1895 << "Content-Type: application/json\r\n"
1896 << "Content-Length: " << strMsg.size() << "\r\n"
1897 << "Connection: close\r\n"
1898 << "Accept: application/json\r\n";
1899 BOOST_FOREACH(const PAIRTYPE(string, string)& item, mapRequestHeaders)
1900 s << item.first << ": " << item.second << "\r\n";
1901 s << "\r\n" << strMsg;
1906 string rfc1123Time()
1911 struct tm* now_gmt = gmtime(&now);
1912 string locale(setlocale(LC_TIME, NULL));
1913 setlocale(LC_TIME, "C"); // we want posix (aka "C") weekday/month strings
1914 strftime(buffer, sizeof(buffer), "%a, %d %b %Y %H:%M:%S +0000", now_gmt);
1915 setlocale(LC_TIME, locale.c_str());
1916 return string(buffer);
1919 static string HTTPReply(int nStatus, const string& strMsg)
1922 return strprintf("HTTP/1.0 401 Authorization Required\r\n"
1924 "Server: bitcoin-json-rpc/%s\r\n"
1925 "WWW-Authenticate: Basic realm=\"jsonrpc\"\r\n"
1926 "Content-Type: text/html\r\n"
1927 "Content-Length: 296\r\n"
1929 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\r\n"
1930 "\"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd\">\r\n"
1933 "<TITLE>Error</TITLE>\r\n"
1934 "<META HTTP-EQUIV='Content-Type' CONTENT='text/html; charset=ISO-8859-1'>\r\n"
1936 "<BODY><H1>401 Unauthorized.</H1></BODY>\r\n"
1937 "</HTML>\r\n", rfc1123Time().c_str(), FormatFullVersion().c_str());
1938 const char *cStatus;
1939 if (nStatus == 200) cStatus = "OK";
1940 else if (nStatus == 400) cStatus = "Bad Request";
1941 else if (nStatus == 403) cStatus = "Forbidden";
1942 else if (nStatus == 404) cStatus = "Not Found";
1943 else if (nStatus == 500) cStatus = "Internal Server Error";
1946 "HTTP/1.1 %d %s\r\n"
1948 "Connection: close\r\n"
1949 "Content-Length: %d\r\n"
1950 "Content-Type: application/json\r\n"
1951 "Server: bitcoin-json-rpc/%s\r\n"
1956 rfc1123Time().c_str(),
1958 FormatFullVersion().c_str(),
1962 int ReadHTTPStatus(std::basic_istream<char>& stream)
1965 getline(stream, str);
1966 vector<string> vWords;
1967 boost::split(vWords, str, boost::is_any_of(" "));
1968 if (vWords.size() < 2)
1970 return atoi(vWords[1].c_str());
1973 int ReadHTTPHeader(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet)
1979 std::getline(stream, str);
1980 if (str.empty() || str == "\r")
1982 string::size_type nColon = str.find(":");
1983 if (nColon != string::npos)
1985 string strHeader = str.substr(0, nColon);
1986 boost::trim(strHeader);
1987 boost::to_lower(strHeader);
1988 string strValue = str.substr(nColon+1);
1989 boost::trim(strValue);
1990 mapHeadersRet[strHeader] = strValue;
1991 if (strHeader == "content-length")
1992 nLen = atoi(strValue.c_str());
1998 int ReadHTTP(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet, string& strMessageRet)
2000 mapHeadersRet.clear();
2004 int nStatus = ReadHTTPStatus(stream);
2007 int nLen = ReadHTTPHeader(stream, mapHeadersRet);
2008 if (nLen < 0 || nLen > MAX_SIZE)
2014 vector<char> vch(nLen);
2015 stream.read(&vch[0], nLen);
2016 strMessageRet = string(vch.begin(), vch.end());
2022 bool HTTPAuthorized(map<string, string>& mapHeaders)
2024 string strAuth = mapHeaders["authorization"];
2025 if (strAuth.substr(0,6) != "Basic ")
2027 string strUserPass64 = strAuth.substr(6); boost::trim(strUserPass64);
2028 string strUserPass = DecodeBase64(strUserPass64);
2029 return strUserPass == strRPCUserColonPass;
2033 // JSON-RPC protocol. Bitcoin speaks version 1.0 for maximum compatibility,
2034 // but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
2035 // unspecified (HTTP errors and contents of 'error').
2037 // 1.0 spec: http://json-rpc.org/wiki/specification
2038 // 1.2 spec: http://groups.google.com/group/json-rpc/web/json-rpc-over-http
2039 // http://www.codeproject.com/KB/recipes/JSON_Spirit.aspx
2042 string JSONRPCRequest(const string& strMethod, const Array& params, const Value& id)
2045 request.push_back(Pair("method", strMethod));
2046 request.push_back(Pair("params", params));
2047 request.push_back(Pair("id", id));
2048 return write_string(Value(request), false) + "\n";
2051 string JSONRPCReply(const Value& result, const Value& error, const Value& id)
2054 if (error.type() != null_type)
2055 reply.push_back(Pair("result", Value::null));
2057 reply.push_back(Pair("result", result));
2058 reply.push_back(Pair("error", error));
2059 reply.push_back(Pair("id", id));
2060 return write_string(Value(reply), false) + "\n";
2063 void ErrorReply(std::ostream& stream, const Object& objError, const Value& id)
2065 // Send error reply from json-rpc error object
2067 int code = find_value(objError, "code").get_int();
2068 if (code == -32600) nStatus = 400;
2069 else if (code == -32601) nStatus = 404;
2070 string strReply = JSONRPCReply(Value::null, objError, id);
2071 stream << HTTPReply(nStatus, strReply) << std::flush;
2074 bool ClientAllowed(const string& strAddress)
2076 if (strAddress == asio::ip::address_v4::loopback().to_string())
2078 const vector<string>& vAllow = mapMultiArgs["-rpcallowip"];
2079 BOOST_FOREACH(string strAllow, vAllow)
2080 if (WildcardMatch(strAddress, strAllow))
2087 // IOStream device that speaks SSL but can also speak non-SSL
2089 class SSLIOStreamDevice : public iostreams::device<iostreams::bidirectional> {
2091 SSLIOStreamDevice(SSLStream &streamIn, bool fUseSSLIn) : stream(streamIn)
2093 fUseSSL = fUseSSLIn;
2094 fNeedHandshake = fUseSSLIn;
2097 void handshake(ssl::stream_base::handshake_type role)
2099 if (!fNeedHandshake) return;
2100 fNeedHandshake = false;
2101 stream.handshake(role);
2103 std::streamsize read(char* s, std::streamsize n)
2105 handshake(ssl::stream_base::server); // HTTPS servers read first
2106 if (fUseSSL) return stream.read_some(asio::buffer(s, n));
2107 return stream.next_layer().read_some(asio::buffer(s, n));
2109 std::streamsize write(const char* s, std::streamsize n)
2111 handshake(ssl::stream_base::client); // HTTPS clients write first
2112 if (fUseSSL) return asio::write(stream, asio::buffer(s, n));
2113 return asio::write(stream.next_layer(), asio::buffer(s, n));
2115 bool connect(const std::string& server, const std::string& port)
2117 ip::tcp::resolver resolver(stream.get_io_service());
2118 ip::tcp::resolver::query query(server.c_str(), port.c_str());
2119 ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
2120 ip::tcp::resolver::iterator end;
2121 boost::system::error_code error = asio::error::host_not_found;
2122 while (error && endpoint_iterator != end)
2124 stream.lowest_layer().close();
2125 stream.lowest_layer().connect(*endpoint_iterator++, error);
2133 bool fNeedHandshake;
2139 void ThreadRPCServer(void* parg)
2141 IMPLEMENT_RANDOMIZE_STACK(ThreadRPCServer(parg));
2144 vnThreadsRunning[4]++;
2145 ThreadRPCServer2(parg);
2146 vnThreadsRunning[4]--;
2148 catch (std::exception& e) {
2149 vnThreadsRunning[4]--;
2150 PrintException(&e, "ThreadRPCServer()");
2152 vnThreadsRunning[4]--;
2153 PrintException(NULL, "ThreadRPCServer()");
2155 printf("ThreadRPCServer exiting\n");
2158 void ThreadRPCServer2(void* parg)
2160 printf("ThreadRPCServer started\n");
2162 strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"];
2163 if (strRPCUserColonPass == ":")
2165 string strWhatAmI = "To use bitcoind";
2166 if (mapArgs.count("-server"))
2167 strWhatAmI = strprintf(_("To use the %s option"), "\"-server\"");
2168 else if (mapArgs.count("-daemon"))
2169 strWhatAmI = strprintf(_("To use the %s option"), "\"-daemon\"");
2171 _("Error: %s, you must set rpcpassword=<password>\nin the configuration file: %s\n"
2172 "If the file does not exist, create it with owner-readable-only file permissions.\n"),
2174 GetConfigFile().c_str());
2176 CreateThread(Shutdown, NULL);
2181 bool fUseSSL = GetBoolArg("-rpcssl");
2182 asio::ip::address bindAddress = mapArgs.count("-rpcallowip") ? asio::ip::address_v4::any() : asio::ip::address_v4::loopback();
2184 asio::io_service io_service;
2185 ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", 8332));
2186 ip::tcp::acceptor acceptor(io_service, endpoint);
2188 acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
2191 ssl::context context(io_service, ssl::context::sslv23);
2194 context.set_options(ssl::context::no_sslv2);
2195 filesystem::path certfile = GetArg("-rpcsslcertificatechainfile", "server.cert");
2196 if (!certfile.is_complete()) certfile = filesystem::path(GetDataDir()) / certfile;
2197 if (filesystem::exists(certfile)) context.use_certificate_chain_file(certfile.string().c_str());
2198 else printf("ThreadRPCServer ERROR: missing server certificate file %s\n", certfile.string().c_str());
2199 filesystem::path pkfile = GetArg("-rpcsslprivatekeyfile", "server.pem");
2200 if (!pkfile.is_complete()) pkfile = filesystem::path(GetDataDir()) / pkfile;
2201 if (filesystem::exists(pkfile)) context.use_private_key_file(pkfile.string().c_str(), ssl::context::pem);
2202 else printf("ThreadRPCServer ERROR: missing server private key file %s\n", pkfile.string().c_str());
2204 string ciphers = GetArg("-rpcsslciphers",
2205 "TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH");
2206 SSL_CTX_set_cipher_list(context.impl(), ciphers.c_str());
2210 throw runtime_error("-rpcssl=1, but bitcoin compiled without full openssl libraries.");
2215 // Accept connection
2217 SSLStream sslStream(io_service, context);
2218 SSLIOStreamDevice d(sslStream, fUseSSL);
2219 iostreams::stream<SSLIOStreamDevice> stream(d);
2221 ip::tcp::iostream stream;
2224 ip::tcp::endpoint peer;
2225 vnThreadsRunning[4]--;
2227 acceptor.accept(sslStream.lowest_layer(), peer);
2229 acceptor.accept(*stream.rdbuf(), peer);
2231 vnThreadsRunning[4]++;
2235 // Restrict callers by IP
2236 if (!ClientAllowed(peer.address().to_string()))
2238 // Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake.
2240 stream << HTTPReply(403, "") << std::flush;
2244 map<string, string> mapHeaders;
2247 boost::thread api_caller(ReadHTTP, boost::ref(stream), boost::ref(mapHeaders), boost::ref(strRequest));
2248 if (!api_caller.timed_join(boost::posix_time::seconds(GetArg("-rpctimeout", 30))))
2251 printf("ThreadRPCServer ReadHTTP timeout\n");
2255 // Check authorization
2256 if (mapHeaders.count("authorization") == 0)
2258 stream << HTTPReply(401, "") << std::flush;
2261 if (!HTTPAuthorized(mapHeaders))
2263 // Deter brute-forcing short passwords
2264 if (mapArgs["-rpcpassword"].size() < 15)
2267 stream << HTTPReply(401, "") << std::flush;
2268 printf("ThreadRPCServer incorrect password attempt\n");
2272 Value id = Value::null;
2277 if (!read_string(strRequest, valRequest) || valRequest.type() != obj_type)
2278 throw JSONRPCError(-32700, "Parse error");
2279 const Object& request = valRequest.get_obj();
2281 // Parse id now so errors from here on will have the id
2282 id = find_value(request, "id");
2285 Value valMethod = find_value(request, "method");
2286 if (valMethod.type() == null_type)
2287 throw JSONRPCError(-32600, "Missing method");
2288 if (valMethod.type() != str_type)
2289 throw JSONRPCError(-32600, "Method must be a string");
2290 string strMethod = valMethod.get_str();
2291 if (strMethod != "getwork" && strMethod != "getmemorypool")
2292 printf("ThreadRPCServer method=%s\n", strMethod.c_str());
2295 Value valParams = find_value(request, "params");
2297 if (valParams.type() == array_type)
2298 params = valParams.get_array();
2299 else if (valParams.type() == null_type)
2302 throw JSONRPCError(-32600, "Params must be an array");
2305 map<string, rpcfn_type>::iterator mi = mapCallTable.find(strMethod);
2306 if (mi == mapCallTable.end())
2307 throw JSONRPCError(-32601, "Method not found");
2309 // Observe safe mode
2310 string strWarning = GetWarnings("rpc");
2311 if (strWarning != "" && !GetBoolArg("-disablesafemode") && !setAllowInSafeMode.count(strMethod))
2312 throw JSONRPCError(-2, string("Safe mode: ") + strWarning);
2318 CRITICAL_BLOCK(cs_main)
2319 CRITICAL_BLOCK(pwalletMain->cs_wallet)
2320 result = (*(*mi).second)(params, false);
2323 string strReply = JSONRPCReply(result, Value::null, id);
2324 stream << HTTPReply(200, strReply) << std::flush;
2326 catch (std::exception& e)
2328 ErrorReply(stream, JSONRPCError(-1, e.what()), id);
2331 catch (Object& objError)
2333 ErrorReply(stream, objError, id);
2335 catch (std::exception& e)
2337 ErrorReply(stream, JSONRPCError(-32700, e.what()), id);
2345 Object CallRPC(const string& strMethod, const Array& params)
2347 if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
2348 throw runtime_error(strprintf(
2349 _("You must set rpcpassword=<password> in the configuration file:\n%s\n"
2350 "If the file does not exist, create it with owner-readable-only file permissions."),
2351 GetConfigFile().c_str()));
2353 // Connect to localhost
2354 bool fUseSSL = GetBoolArg("-rpcssl");
2356 asio::io_service io_service;
2357 ssl::context context(io_service, ssl::context::sslv23);
2358 context.set_options(ssl::context::no_sslv2);
2359 SSLStream sslStream(io_service, context);
2360 SSLIOStreamDevice d(sslStream, fUseSSL);
2361 iostreams::stream<SSLIOStreamDevice> stream(d);
2362 if (!d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332")))
2363 throw runtime_error("couldn't connect to server");
2366 throw runtime_error("-rpcssl=1, but bitcoin compiled without full openssl libraries.");
2368 ip::tcp::iostream stream(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332"));
2370 throw runtime_error("couldn't connect to server");
2374 // HTTP basic authentication
2375 string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
2376 map<string, string> mapRequestHeaders;
2377 mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64;
2380 string strRequest = JSONRPCRequest(strMethod, params, 1);
2381 string strPost = HTTPPost(strRequest, mapRequestHeaders);
2382 stream << strPost << std::flush;
2385 map<string, string> mapHeaders;
2387 int nStatus = ReadHTTP(stream, mapHeaders, strReply);
2389 throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
2390 else if (nStatus >= 400 && nStatus != 400 && nStatus != 404 && nStatus != 500)
2391 throw runtime_error(strprintf("server returned HTTP error %d", nStatus));
2392 else if (strReply.empty())
2393 throw runtime_error("no response from server");
2397 if (!read_string(strReply, valReply))
2398 throw runtime_error("couldn't parse reply from server");
2399 const Object& reply = valReply.get_obj();
2401 throw runtime_error("expected reply to have result, error and id properties");
2409 template<typename T>
2410 void ConvertTo(Value& value)
2412 if (value.type() == str_type)
2414 // reinterpret string as unquoted json value
2416 if (!read_string(value.get_str(), value2))
2417 throw runtime_error("type mismatch");
2418 value = value2.get_value<T>();
2422 value = value.get_value<T>();
2426 int CommandLineRPC(int argc, char *argv[])
2433 while (argc > 1 && IsSwitchChar(argv[1][0]))
2441 throw runtime_error("too few parameters");
2442 string strMethod = argv[1];
2444 // Parameters default to strings
2446 for (int i = 2; i < argc; i++)
2447 params.push_back(argv[i]);
2448 int n = params.size();
2451 // Special case non-string parameter types
2453 if (strMethod == "setgenerate" && n > 0) ConvertTo<bool>(params[0]);
2454 if (strMethod == "setgenerate" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2455 if (strMethod == "sendtoaddress" && n > 1) ConvertTo<double>(params[1]);
2456 if (strMethod == "settxfee" && n > 0) ConvertTo<double>(params[0]);
2457 if (strMethod == "getreceivedbyaddress" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2458 if (strMethod == "getreceivedbyaccount" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2459 if (strMethod == "listreceivedbyaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2460 if (strMethod == "listreceivedbyaddress" && n > 1) ConvertTo<bool>(params[1]);
2461 if (strMethod == "listreceivedbyaccount" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2462 if (strMethod == "listreceivedbyaccount" && n > 1) ConvertTo<bool>(params[1]);
2463 if (strMethod == "getbalance" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2464 if (strMethod == "move" && n > 2) ConvertTo<double>(params[2]);
2465 if (strMethod == "move" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2466 if (strMethod == "sendfrom" && n > 2) ConvertTo<double>(params[2]);
2467 if (strMethod == "sendfrom" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2468 if (strMethod == "listtransactions" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2469 if (strMethod == "listtransactions" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2470 if (strMethod == "listaccounts" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2471 if (strMethod == "walletpassphrase" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2472 if (strMethod == "listsinceblock" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2473 if (strMethod == "sendmany" && n > 1)
2475 string s = params[1].get_str();
2477 if (!read_string(s, v) || v.type() != obj_type)
2478 throw runtime_error("type mismatch");
2479 params[1] = v.get_obj();
2481 if (strMethod == "sendmany" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2484 Object reply = CallRPC(strMethod, params);
2487 const Value& result = find_value(reply, "result");
2488 const Value& error = find_value(reply, "error");
2490 if (error.type() != null_type)
2493 strPrint = "error: " + write_string(error, false);
2494 int code = find_value(error.get_obj(), "code").get_int();
2500 if (result.type() == null_type)
2502 else if (result.type() == str_type)
2503 strPrint = result.get_str();
2505 strPrint = write_string(result, true);
2508 catch (std::exception& e)
2510 strPrint = string("error: ") + e.what();
2515 PrintException(NULL, "CommandLineRPC()");
2520 fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
2529 int main(int argc, char *argv[])
2532 // Turn off microsoft heap dump noise
2533 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
2534 _CrtSetReportFile(_CRT_WARN, CreateFile("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0));
2536 setbuf(stdin, NULL);
2537 setbuf(stdout, NULL);
2538 setbuf(stderr, NULL);
2542 if (argc >= 2 && string(argv[1]) == "-server")
2544 printf("server ready\n");
2545 ThreadRPCServer(NULL);
2549 return CommandLineRPC(argc, argv);
2552 catch (std::exception& e) {
2553 PrintException(&e, "main()");
2555 PrintException(NULL, "main()");