1 // Copyright (c) 2010 Satoshi Nakamoto
2 // Copyright (c) 2011 The Bitcoin developers
3 // Distributed under the MIT/X11 software license, see the accompanying
4 // file license.txt or http://www.opensource.org/licenses/mit-license.php.
11 #include <boost/asio.hpp>
12 #include <boost/iostreams/concepts.hpp>
13 #include <boost/iostreams/stream.hpp>
14 #include <boost/algorithm/string.hpp>
16 #include <boost/asio/ssl.hpp>
17 #include <boost/filesystem.hpp>
18 #include <boost/filesystem/fstream.hpp>
19 typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> SSLStream;
21 #include "json/json_spirit_reader_template.h"
22 #include "json/json_spirit_writer_template.h"
23 #include "json/json_spirit_utils.h"
24 #define printf OutputDebugStringF
25 // MinGW 3.4.5 gets "fatal error: had to relocate PCH" if the json headers are
26 // precompiled in headers.h. The problem might be when the pch file goes over
27 // a certain size around 145MB. If we need access to json_spirit outside this
28 // file, we could use the compiled json_spirit option.
31 using namespace boost;
32 using namespace boost::asio;
33 using namespace json_spirit;
35 void ThreadRPCServer2(void* parg);
36 typedef Value(*rpcfn_type)(const Array& params, bool fHelp);
37 extern map<string, rpcfn_type> mapCallTable;
39 static int64 nWalletUnlockTime;
40 static CCriticalSection cs_nWalletUnlockTime;
43 Object JSONRPCError(int code, const string& message)
46 error.push_back(Pair("code", code));
47 error.push_back(Pair("message", message));
52 void PrintConsole(const std::string &format, ...)
55 int limit = sizeof(buffer);
57 va_start(arg_ptr, format);
58 int ret = _vsnprintf(buffer, limit, format.c_str(), arg_ptr);
60 if (ret < 0 || ret >= limit)
66 fprintf(stdout, "%s", buffer);
70 int64 AmountFromValue(const Value& value)
72 double dAmount = value.get_real();
73 if (dAmount <= 0.0 || dAmount > 21000000.0)
74 throw JSONRPCError(-3, "Invalid amount");
75 int64 nAmount = roundint64(dAmount * COIN);
76 if (!MoneyRange(nAmount))
77 throw JSONRPCError(-3, "Invalid amount");
81 Value ValueFromAmount(int64 amount)
83 return (double)amount / (double)COIN;
86 void WalletTxToJSON(const CWalletTx& wtx, Object& entry)
88 entry.push_back(Pair("confirmations", wtx.GetDepthInMainChain()));
89 entry.push_back(Pair("txid", wtx.GetHash().GetHex()));
90 entry.push_back(Pair("time", (boost::int64_t)wtx.GetTxTime()));
91 BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue)
92 entry.push_back(Pair(item.first, item.second));
95 string AccountFromValue(const Value& value)
97 string strAccount = value.get_str();
98 if (strAccount == "*")
99 throw JSONRPCError(-11, "Invalid account name");
106 /// Note: This interface may still be subject to change.
110 Value help(const Array& params, bool fHelp)
112 if (fHelp || params.size() > 1)
115 "List commands, or get help for a command.");
118 if (params.size() > 0)
119 strCommand = params[0].get_str();
122 set<rpcfn_type> setDone;
123 for (map<string, rpcfn_type>::iterator mi = mapCallTable.begin(); mi != mapCallTable.end(); ++mi)
125 string strMethod = (*mi).first;
126 // We already filter duplicates, but these deprecated screw up the sort order
127 if (strMethod == "getamountreceived" ||
128 strMethod == "getallreceived" ||
129 strMethod == "getblocknumber" || // deprecated
130 (strMethod.find("label") != string::npos))
132 if (strCommand != "" && strMethod != strCommand)
137 rpcfn_type pfn = (*mi).second;
138 if (setDone.insert(pfn).second)
139 (*pfn)(params, true);
141 catch (std::exception& e)
143 // Help text is returned in an exception
144 string strHelp = string(e.what());
145 if (strCommand == "")
146 if (strHelp.find('\n') != -1)
147 strHelp = strHelp.substr(0, strHelp.find('\n'));
148 strRet += strHelp + "\n";
152 strRet = strprintf("help: unknown command: %s\n", strCommand.c_str());
153 strRet = strRet.substr(0,strRet.size()-1);
158 Value stop(const Array& params, bool fHelp)
160 if (fHelp || params.size() != 0)
163 "Stop bitcoin server.");
165 // Shutdown will take long enough that the response should get back
166 CreateThread(Shutdown, NULL);
167 return "bitcoin server stopping";
169 throw runtime_error("NYI: cannot shut down GUI with RPC command");
174 Value getblockcount(const Array& params, bool fHelp)
176 if (fHelp || params.size() != 0)
179 "Returns the number of blocks in the longest block chain.");
186 Value getblocknumber(const Array& params, bool fHelp)
188 if (fHelp || params.size() != 0)
191 "Deprecated. Use getblockcount.");
197 Value getconnectioncount(const Array& params, bool fHelp)
199 if (fHelp || params.size() != 0)
201 "getconnectioncount\n"
202 "Returns the number of connections to other nodes.");
204 return (int)vNodes.size();
208 double GetDifficulty()
210 // Floating point number that is a multiple of the minimum difficulty,
211 // minimum difficulty = 1.0.
213 if (pindexBest == NULL)
215 int nShift = (pindexBest->nBits >> 24) & 0xff;
218 (double)0x0000ffff / (double)(pindexBest->nBits & 0x00ffffff);
234 Value getdifficulty(const Array& params, bool fHelp)
236 if (fHelp || params.size() != 0)
239 "Returns the proof-of-work difficulty as a multiple of the minimum difficulty.");
241 return GetDifficulty();
245 Value getgenerate(const Array& params, bool fHelp)
247 if (fHelp || params.size() != 0)
250 "Returns true or false.");
252 return (bool)fGenerateBitcoins;
256 Value setgenerate(const Array& params, bool fHelp)
258 if (fHelp || params.size() < 1 || params.size() > 2)
260 "setgenerate <generate> [genproclimit]\n"
261 "<generate> is true or false to turn generation on or off.\n"
262 "Generation is limited to [genproclimit] processors, -1 is unlimited.");
264 bool fGenerate = true;
265 if (params.size() > 0)
266 fGenerate = params[0].get_bool();
268 if (params.size() > 1)
270 int nGenProcLimit = params[1].get_int();
271 fLimitProcessors = (nGenProcLimit != -1);
272 WriteSetting("fLimitProcessors", fLimitProcessors);
273 if (nGenProcLimit != -1)
274 WriteSetting("nLimitProcessors", nLimitProcessors = nGenProcLimit);
275 if (nGenProcLimit == 0)
279 GenerateBitcoins(fGenerate, pwalletMain);
284 Value gethashespersec(const Array& params, bool fHelp)
286 if (fHelp || params.size() != 0)
289 "Returns a recent hashes per second performance measurement while generating.");
291 if (GetTimeMillis() - nHPSTimerStart > 8000)
292 return (boost::int64_t)0;
293 return (boost::int64_t)dHashesPerSec;
297 Value getinfo(const Array& params, bool fHelp)
299 if (fHelp || params.size() != 0)
302 "Returns an object containing various state info.");
305 obj.push_back(Pair("version", (int)VERSION));
306 obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance())));
307 obj.push_back(Pair("blocks", (int)nBestHeight));
308 obj.push_back(Pair("connections", (int)vNodes.size()));
309 obj.push_back(Pair("proxy", (fUseProxy ? addrProxy.ToStringIPPort() : string())));
310 obj.push_back(Pair("generate", (bool)fGenerateBitcoins));
311 obj.push_back(Pair("genproclimit", (int)(fLimitProcessors ? nLimitProcessors : -1)));
312 obj.push_back(Pair("difficulty", (double)GetDifficulty()));
313 obj.push_back(Pair("hashespersec", gethashespersec(params, false)));
314 obj.push_back(Pair("testnet", fTestNet));
315 obj.push_back(Pair("keypoololdest", (boost::int64_t)pwalletMain->GetOldestKeyPoolTime()));
316 obj.push_back(Pair("keypoolsize", pwalletMain->GetKeyPoolSize()));
317 obj.push_back(Pair("paytxfee", ValueFromAmount(nTransactionFee)));
318 if (pwalletMain->IsCrypted())
319 obj.push_back(Pair("unlocked_until", (boost::int64_t)nWalletUnlockTime));
320 obj.push_back(Pair("errors", GetWarnings("statusbar")));
325 Value getnewaddress(const Array& params, bool fHelp)
327 if (fHelp || params.size() > 1)
329 "getnewaddress [account]\n"
330 "Returns a new bitcoin address for receiving payments. "
331 "If [account] is specified (recommended), it is added to the address book "
332 "so payments received with the address will be credited to [account].");
334 // Parse the account first so we don't generate a key if there's an error
336 if (params.size() > 0)
337 strAccount = AccountFromValue(params[0]);
339 if (!pwalletMain->IsLocked())
340 pwalletMain->TopUpKeyPool();
342 // Generate a new key that is added to wallet
343 std::vector<unsigned char> newKey;
344 if (!pwalletMain->GetKeyFromPool(newKey, false))
345 throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
346 CBitcoinAddress address(newKey);
348 pwalletMain->SetAddressBookName(address, strAccount);
350 return address.ToString();
354 CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false)
356 CWalletDB walletdb(pwalletMain->strWalletFile);
359 walletdb.ReadAccount(strAccount, account);
361 bool bKeyUsed = false;
363 // Check if the current key has been used
364 if (!account.vchPubKey.empty())
366 CScript scriptPubKey;
367 scriptPubKey.SetBitcoinAddress(account.vchPubKey);
368 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
369 it != pwalletMain->mapWallet.end() && !account.vchPubKey.empty();
372 const CWalletTx& wtx = (*it).second;
373 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
374 if (txout.scriptPubKey == scriptPubKey)
379 // Generate a new key
380 if (account.vchPubKey.empty() || bForceNew || bKeyUsed)
382 if (!pwalletMain->GetKeyFromPool(account.vchPubKey, false))
383 throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
385 pwalletMain->SetAddressBookName(CBitcoinAddress(account.vchPubKey), strAccount);
386 walletdb.WriteAccount(strAccount, account);
389 return CBitcoinAddress(account.vchPubKey);
392 Value getaccountaddress(const Array& params, bool fHelp)
394 if (fHelp || params.size() != 1)
396 "getaccountaddress <account>\n"
397 "Returns the current bitcoin address for receiving payments to this account.");
399 // Parse the account first so we don't generate a key if there's an error
400 string strAccount = AccountFromValue(params[0]);
404 ret = GetAccountAddress(strAccount).ToString();
411 Value setaccount(const Array& params, bool fHelp)
413 if (fHelp || params.size() < 1 || params.size() > 2)
415 "setaccount <bitcoinaddress> <account>\n"
416 "Sets the account associated with the given address.");
418 CBitcoinAddress address(params[0].get_str());
419 if (!address.IsValid())
420 throw JSONRPCError(-5, "Invalid bitcoin address");
424 if (params.size() > 1)
425 strAccount = AccountFromValue(params[1]);
427 // Detect when changing the account of an address that is the 'unused current key' of another account:
428 if (pwalletMain->mapAddressBook.count(address))
430 string strOldAccount = pwalletMain->mapAddressBook[address];
431 if (address == GetAccountAddress(strOldAccount))
432 GetAccountAddress(strOldAccount, true);
435 pwalletMain->SetAddressBookName(address, strAccount);
441 Value getaccount(const Array& params, bool fHelp)
443 if (fHelp || params.size() != 1)
445 "getaccount <bitcoinaddress>\n"
446 "Returns the account associated with the given address.");
448 CBitcoinAddress address(params[0].get_str());
449 if (!address.IsValid())
450 throw JSONRPCError(-5, "Invalid bitcoin address");
453 map<CBitcoinAddress, string>::iterator mi = pwalletMain->mapAddressBook.find(address);
454 if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.empty())
455 strAccount = (*mi).second;
460 Value getaddressesbyaccount(const Array& params, bool fHelp)
462 if (fHelp || params.size() != 1)
464 "getaddressesbyaccount <account>\n"
465 "Returns the list of addresses for the given account.");
467 string strAccount = AccountFromValue(params[0]);
469 // Find all addresses that have the given account
471 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
473 const CBitcoinAddress& address = item.first;
474 const string& strName = item.second;
475 if (strName == strAccount)
476 ret.push_back(address.ToString());
481 Value settxfee(const Array& params, bool fHelp)
483 if (fHelp || params.size() < 1 || params.size() > 1)
485 "settxfee <amount>\n"
486 "<amount> is a real and is rounded to the nearest 0.00000001");
490 if (params[0].get_real() != 0.0)
491 nAmount = AmountFromValue(params[0]); // rejects 0.0 amounts
493 nTransactionFee = nAmount;
497 Value sendtoaddress(const Array& params, bool fHelp)
499 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
501 "sendtoaddress <bitcoinaddress> <amount> [comment] [comment-to]\n"
502 "<amount> is a real and is rounded to the nearest 0.00000001\n"
503 "requires wallet passphrase to be set with walletpassphrase first");
504 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
506 "sendtoaddress <bitcoinaddress> <amount> [comment] [comment-to]\n"
507 "<amount> is a real and is rounded to the nearest 0.00000001");
509 CBitcoinAddress address(params[0].get_str());
510 if (!address.IsValid())
511 throw JSONRPCError(-5, "Invalid bitcoin address");
514 int64 nAmount = AmountFromValue(params[1]);
518 if (params.size() > 2 && params[2].type() != null_type && !params[2].get_str().empty())
519 wtx.mapValue["comment"] = params[2].get_str();
520 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
521 wtx.mapValue["to"] = params[3].get_str();
523 if (pwalletMain->IsLocked())
524 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
526 string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
528 throw JSONRPCError(-4, strError);
530 return wtx.GetHash().GetHex();
533 static const string strMessageMagic = "Bitcoin Signed Message:\n";
535 Value signmessage(const Array& params, bool fHelp)
537 if (fHelp || params.size() != 2)
539 "signmessage <bitcoinaddress> <message>\n"
540 "Sign a message with the private key of an address");
542 if (pwalletMain->IsLocked())
543 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
545 string strAddress = params[0].get_str();
546 string strMessage = params[1].get_str();
548 CBitcoinAddress addr(strAddress);
550 throw JSONRPCError(-3, "Invalid address");
553 if (!pwalletMain->GetKey(addr, key))
554 throw JSONRPCError(-4, "Private key not available");
556 CDataStream ss(SER_GETHASH);
557 ss << strMessageMagic;
560 vector<unsigned char> vchSig;
561 if (!key.SignCompact(Hash(ss.begin(), ss.end()), vchSig))
562 throw JSONRPCError(-5, "Sign failed");
564 return EncodeBase64(&vchSig[0], vchSig.size());
567 Value verifymessage(const Array& params, bool fHelp)
569 if (fHelp || params.size() != 3)
571 "verifymessage <bitcoinaddress> <signature> <message>\n"
572 "Verify a signed message");
574 string strAddress = params[0].get_str();
575 string strSign = params[1].get_str();
576 string strMessage = params[2].get_str();
578 CBitcoinAddress addr(strAddress);
580 throw JSONRPCError(-3, "Invalid address");
582 bool fInvalid = false;
583 vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid);
586 throw JSONRPCError(-5, "Malformed base64 encoding");
588 CDataStream ss(SER_GETHASH);
589 ss << strMessageMagic;
593 if (!key.SetCompactSignature(Hash(ss.begin(), ss.end()), vchSig))
596 return (key.GetAddress() == addr);
600 Value getreceivedbyaddress(const Array& params, bool fHelp)
602 if (fHelp || params.size() < 1 || params.size() > 2)
604 "getreceivedbyaddress <bitcoinaddress> [minconf=1]\n"
605 "Returns the total amount received by <bitcoinaddress> in transactions with at least [minconf] confirmations.");
608 CBitcoinAddress address = CBitcoinAddress(params[0].get_str());
609 CScript scriptPubKey;
610 if (!address.IsValid())
611 throw JSONRPCError(-5, "Invalid bitcoin address");
612 scriptPubKey.SetBitcoinAddress(address);
613 if (!IsMine(*pwalletMain,scriptPubKey))
616 // Minimum confirmations
618 if (params.size() > 1)
619 nMinDepth = params[1].get_int();
623 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
625 const CWalletTx& wtx = (*it).second;
626 if (wtx.IsCoinBase() || !wtx.IsFinal())
629 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
630 if (txout.scriptPubKey == scriptPubKey)
631 if (wtx.GetDepthInMainChain() >= nMinDepth)
632 nAmount += txout.nValue;
635 return ValueFromAmount(nAmount);
639 void GetAccountAddresses(string strAccount, set<CBitcoinAddress>& setAddress)
641 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
643 const CBitcoinAddress& address = item.first;
644 const string& strName = item.second;
645 if (strName == strAccount)
646 setAddress.insert(address);
651 Value getreceivedbyaccount(const Array& params, bool fHelp)
653 if (fHelp || params.size() < 1 || params.size() > 2)
655 "getreceivedbyaccount <account> [minconf=1]\n"
656 "Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.");
658 // Minimum confirmations
660 if (params.size() > 1)
661 nMinDepth = params[1].get_int();
663 // Get the set of pub keys that have the label
664 string strAccount = AccountFromValue(params[0]);
665 set<CBitcoinAddress> setAddress;
666 GetAccountAddresses(strAccount, setAddress);
670 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
672 const CWalletTx& wtx = (*it).second;
673 if (wtx.IsCoinBase() || !wtx.IsFinal())
676 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
678 CBitcoinAddress address;
679 if (ExtractAddress(txout.scriptPubKey, pwalletMain, address) && setAddress.count(address))
680 if (wtx.GetDepthInMainChain() >= nMinDepth)
681 nAmount += txout.nValue;
685 return (double)nAmount / (double)COIN;
689 int64 GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth)
693 // Tally wallet transactions
694 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
696 const CWalletTx& wtx = (*it).second;
700 int64 nGenerated, nReceived, nSent, nFee;
701 wtx.GetAccountAmounts(strAccount, nGenerated, nReceived, nSent, nFee);
703 if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
704 nBalance += nReceived;
705 nBalance += nGenerated - nSent - nFee;
708 // Tally internal accounting entries
709 nBalance += walletdb.GetAccountCreditDebit(strAccount);
714 int64 GetAccountBalance(const string& strAccount, int nMinDepth)
716 CWalletDB walletdb(pwalletMain->strWalletFile);
717 return GetAccountBalance(walletdb, strAccount, nMinDepth);
721 Value getbalance(const Array& params, bool fHelp)
723 if (fHelp || params.size() > 2)
725 "getbalance [account] [minconf=1]\n"
726 "If [account] is not specified, returns the server's total available balance.\n"
727 "If [account] is specified, returns the balance in the account.");
729 if (params.size() == 0)
730 return ValueFromAmount(pwalletMain->GetBalance());
733 if (params.size() > 1)
734 nMinDepth = params[1].get_int();
736 if (params[0].get_str() == "*") {
737 // Calculate total balance a different way from GetBalance()
738 // (GetBalance() sums up all unspent TxOuts)
739 // getbalance and getbalance '*' should always return the same number.
741 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
743 const CWalletTx& wtx = (*it).second;
747 int64 allGeneratedImmature, allGeneratedMature, allFee;
748 allGeneratedImmature = allGeneratedMature = allFee = 0;
749 string strSentAccount;
750 list<pair<CBitcoinAddress, int64> > listReceived;
751 list<pair<CBitcoinAddress, int64> > listSent;
752 wtx.GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount);
753 if (wtx.GetDepthInMainChain() >= nMinDepth)
754 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listReceived)
755 nBalance += r.second;
756 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listSent)
757 nBalance -= r.second;
759 nBalance += allGeneratedMature;
761 return ValueFromAmount(nBalance);
764 string strAccount = AccountFromValue(params[0]);
766 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
768 return ValueFromAmount(nBalance);
772 Value movecmd(const Array& params, bool fHelp)
774 if (fHelp || params.size() < 3 || params.size() > 5)
776 "move <fromaccount> <toaccount> <amount> [minconf=1] [comment]\n"
777 "Move from one account in your wallet to another.");
779 string strFrom = AccountFromValue(params[0]);
780 string strTo = AccountFromValue(params[1]);
781 int64 nAmount = AmountFromValue(params[2]);
782 if (params.size() > 3)
783 // unused parameter, used to be nMinDepth, keep type-checking it though
784 (void)params[3].get_int();
786 if (params.size() > 4)
787 strComment = params[4].get_str();
789 CWalletDB walletdb(pwalletMain->strWalletFile);
792 int64 nNow = GetAdjustedTime();
795 CAccountingEntry debit;
796 debit.strAccount = strFrom;
797 debit.nCreditDebit = -nAmount;
799 debit.strOtherAccount = strTo;
800 debit.strComment = strComment;
801 walletdb.WriteAccountingEntry(debit);
804 CAccountingEntry credit;
805 credit.strAccount = strTo;
806 credit.nCreditDebit = nAmount;
808 credit.strOtherAccount = strFrom;
809 credit.strComment = strComment;
810 walletdb.WriteAccountingEntry(credit);
812 walletdb.TxnCommit();
818 Value sendfrom(const Array& params, bool fHelp)
820 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
822 "sendfrom <fromaccount> <tobitcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
823 "<amount> is a real and is rounded to the nearest 0.00000001\n"
824 "requires wallet passphrase to be set with walletpassphrase first");
825 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
827 "sendfrom <fromaccount> <tobitcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
828 "<amount> is a real and is rounded to the nearest 0.00000001");
830 string strAccount = AccountFromValue(params[0]);
831 CBitcoinAddress address(params[1].get_str());
832 if (!address.IsValid())
833 throw JSONRPCError(-5, "Invalid bitcoin address");
834 int64 nAmount = AmountFromValue(params[2]);
836 if (params.size() > 3)
837 nMinDepth = params[3].get_int();
840 wtx.strFromAccount = strAccount;
841 if (params.size() > 4 && params[4].type() != null_type && !params[4].get_str().empty())
842 wtx.mapValue["comment"] = params[4].get_str();
843 if (params.size() > 5 && params[5].type() != null_type && !params[5].get_str().empty())
844 wtx.mapValue["to"] = params[5].get_str();
846 if (pwalletMain->IsLocked())
847 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
850 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
851 if (nAmount > nBalance)
852 throw JSONRPCError(-6, "Account has insufficient funds");
855 string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
857 throw JSONRPCError(-4, strError);
859 return wtx.GetHash().GetHex();
863 Value sendmany(const Array& params, bool fHelp)
865 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
867 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
868 "amounts are double-precision floating point numbers\n"
869 "requires wallet passphrase to be set with walletpassphrase first");
870 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
872 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
873 "amounts are double-precision floating point numbers");
875 string strAccount = AccountFromValue(params[0]);
876 Object sendTo = params[1].get_obj();
878 if (params.size() > 2)
879 nMinDepth = params[2].get_int();
882 wtx.strFromAccount = strAccount;
883 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
884 wtx.mapValue["comment"] = params[3].get_str();
886 set<CBitcoinAddress> setAddress;
887 vector<pair<CScript, int64> > vecSend;
889 int64 totalAmount = 0;
890 BOOST_FOREACH(const Pair& s, sendTo)
892 CBitcoinAddress address(s.name_);
893 if (!address.IsValid())
894 throw JSONRPCError(-5, string("Invalid bitcoin address:")+s.name_);
896 if (setAddress.count(address))
897 throw JSONRPCError(-8, string("Invalid parameter, duplicated address: ")+s.name_);
898 setAddress.insert(address);
900 CScript scriptPubKey;
901 scriptPubKey.SetBitcoinAddress(address);
902 int64 nAmount = AmountFromValue(s.value_);
903 totalAmount += nAmount;
905 vecSend.push_back(make_pair(scriptPubKey, nAmount));
908 if (pwalletMain->IsLocked())
909 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
912 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
913 if (totalAmount > nBalance)
914 throw JSONRPCError(-6, "Account has insufficient funds");
917 CReserveKey keyChange(pwalletMain);
918 int64 nFeeRequired = 0;
919 bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired);
922 if (totalAmount + nFeeRequired > pwalletMain->GetBalance())
923 throw JSONRPCError(-6, "Insufficient funds");
924 throw JSONRPCError(-4, "Transaction creation failed");
926 if (!pwalletMain->CommitTransaction(wtx, keyChange))
927 throw JSONRPCError(-4, "Transaction commit failed");
929 return wtx.GetHash().GetHex();
944 Value ListReceived(const Array& params, bool fByAccounts)
946 // Minimum confirmations
948 if (params.size() > 0)
949 nMinDepth = params[0].get_int();
951 // Whether to include empty accounts
952 bool fIncludeEmpty = false;
953 if (params.size() > 1)
954 fIncludeEmpty = params[1].get_bool();
957 map<CBitcoinAddress, tallyitem> mapTally;
958 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
960 const CWalletTx& wtx = (*it).second;
961 if (wtx.IsCoinBase() || !wtx.IsFinal())
964 int nDepth = wtx.GetDepthInMainChain();
965 if (nDepth < nMinDepth)
968 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
970 CBitcoinAddress address;
971 if (!ExtractAddress(txout.scriptPubKey, pwalletMain, address) || !address.IsValid())
974 tallyitem& item = mapTally[address];
975 item.nAmount += txout.nValue;
976 item.nConf = min(item.nConf, nDepth);
982 map<string, tallyitem> mapAccountTally;
983 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
985 const CBitcoinAddress& address = item.first;
986 const string& strAccount = item.second;
987 map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
988 if (it == mapTally.end() && !fIncludeEmpty)
993 if (it != mapTally.end())
995 nAmount = (*it).second.nAmount;
996 nConf = (*it).second.nConf;
1001 tallyitem& item = mapAccountTally[strAccount];
1002 item.nAmount += nAmount;
1003 item.nConf = min(item.nConf, nConf);
1008 obj.push_back(Pair("address", address.ToString()));
1009 obj.push_back(Pair("account", strAccount));
1010 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1011 obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf)));
1018 for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
1020 int64 nAmount = (*it).second.nAmount;
1021 int nConf = (*it).second.nConf;
1023 obj.push_back(Pair("account", (*it).first));
1024 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1025 obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf)));
1033 Value listreceivedbyaddress(const Array& params, bool fHelp)
1035 if (fHelp || params.size() > 2)
1036 throw runtime_error(
1037 "listreceivedbyaddress [minconf=1] [includeempty=false]\n"
1038 "[minconf] is the minimum number of confirmations before payments are included.\n"
1039 "[includeempty] whether to include addresses that haven't received any payments.\n"
1040 "Returns an array of objects containing:\n"
1041 " \"address\" : receiving address\n"
1042 " \"account\" : the account of the receiving address\n"
1043 " \"amount\" : total amount received by the address\n"
1044 " \"confirmations\" : number of confirmations of the most recent transaction included");
1046 return ListReceived(params, false);
1049 Value listreceivedbyaccount(const Array& params, bool fHelp)
1051 if (fHelp || params.size() > 2)
1052 throw runtime_error(
1053 "listreceivedbyaccount [minconf=1] [includeempty=false]\n"
1054 "[minconf] is the minimum number of confirmations before payments are included.\n"
1055 "[includeempty] whether to include accounts that haven't received any payments.\n"
1056 "Returns an array of objects containing:\n"
1057 " \"account\" : the account of the receiving addresses\n"
1058 " \"amount\" : total amount received by addresses with this account\n"
1059 " \"confirmations\" : number of confirmations of the most recent transaction included");
1061 return ListReceived(params, true);
1064 void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret)
1066 int64 nGeneratedImmature, nGeneratedMature, nFee;
1067 string strSentAccount;
1068 list<pair<CBitcoinAddress, int64> > listReceived;
1069 list<pair<CBitcoinAddress, int64> > listSent;
1070 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1072 bool fAllAccounts = (strAccount == string("*"));
1074 // Generated blocks assigned to account ""
1075 if ((nGeneratedMature+nGeneratedImmature) != 0 && (fAllAccounts || strAccount == ""))
1078 entry.push_back(Pair("account", string("")));
1079 if (nGeneratedImmature)
1081 entry.push_back(Pair("category", wtx.GetDepthInMainChain() ? "immature" : "orphan"));
1082 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedImmature)));
1086 entry.push_back(Pair("category", "generate"));
1087 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedMature)));
1090 WalletTxToJSON(wtx, entry);
1091 ret.push_back(entry);
1095 if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
1097 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1100 entry.push_back(Pair("account", strSentAccount));
1101 entry.push_back(Pair("address", s.first.ToString()));
1102 entry.push_back(Pair("category", "send"));
1103 entry.push_back(Pair("amount", ValueFromAmount(-s.second)));
1104 entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
1106 WalletTxToJSON(wtx, entry);
1107 ret.push_back(entry);
1112 if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
1113 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1116 if (pwalletMain->mapAddressBook.count(r.first))
1117 account = pwalletMain->mapAddressBook[r.first];
1118 if (fAllAccounts || (account == strAccount))
1121 entry.push_back(Pair("account", account));
1122 entry.push_back(Pair("address", r.first.ToString()));
1123 entry.push_back(Pair("category", "receive"));
1124 entry.push_back(Pair("amount", ValueFromAmount(r.second)));
1126 WalletTxToJSON(wtx, entry);
1127 ret.push_back(entry);
1132 void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret)
1134 bool fAllAccounts = (strAccount == string("*"));
1136 if (fAllAccounts || acentry.strAccount == strAccount)
1139 entry.push_back(Pair("account", acentry.strAccount));
1140 entry.push_back(Pair("category", "move"));
1141 entry.push_back(Pair("time", (boost::int64_t)acentry.nTime));
1142 entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
1143 entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
1144 entry.push_back(Pair("comment", acentry.strComment));
1145 ret.push_back(entry);
1149 Value listtransactions(const Array& params, bool fHelp)
1151 if (fHelp || params.size() > 3)
1152 throw runtime_error(
1153 "listtransactions [account] [count=10] [from=0]\n"
1154 "Returns up to [count] most recent transactions skipping the first [from] transactions for account [account].");
1156 string strAccount = "*";
1157 if (params.size() > 0)
1158 strAccount = params[0].get_str();
1160 if (params.size() > 1)
1161 nCount = params[1].get_int();
1163 if (params.size() > 2)
1164 nFrom = params[2].get_int();
1167 CWalletDB walletdb(pwalletMain->strWalletFile);
1169 // Firs: get all CWalletTx and CAccountingEntry into a sorted-by-time multimap:
1170 typedef pair<CWalletTx*, CAccountingEntry*> TxPair;
1171 typedef multimap<int64, TxPair > TxItems;
1174 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1176 CWalletTx* wtx = &((*it).second);
1177 txByTime.insert(make_pair(wtx->GetTxTime(), TxPair(wtx, (CAccountingEntry*)0)));
1179 list<CAccountingEntry> acentries;
1180 walletdb.ListAccountCreditDebit(strAccount, acentries);
1181 BOOST_FOREACH(CAccountingEntry& entry, acentries)
1183 txByTime.insert(make_pair(entry.nTime, TxPair((CWalletTx*)0, &entry)));
1186 // Now: iterate backwards until we have nCount items to return:
1187 TxItems::reverse_iterator it = txByTime.rbegin();
1188 if (txByTime.size() > nFrom) std::advance(it, nFrom);
1189 for (; it != txByTime.rend(); ++it)
1191 CWalletTx *const pwtx = (*it).second.first;
1193 ListTransactions(*pwtx, strAccount, 0, true, ret);
1194 CAccountingEntry *const pacentry = (*it).second.second;
1196 AcentryToJSON(*pacentry, strAccount, ret);
1198 if (ret.size() >= nCount) break;
1200 // ret is now newest to oldest
1202 // Make sure we return only last nCount items (sends-to-self might give us an extra):
1203 if (ret.size() > nCount)
1205 Array::iterator last = ret.begin();
1206 std::advance(last, nCount);
1207 ret.erase(last, ret.end());
1209 std::reverse(ret.begin(), ret.end()); // oldest to newest
1214 Value listaccounts(const Array& params, bool fHelp)
1216 if (fHelp || params.size() > 1)
1217 throw runtime_error(
1218 "listaccounts [minconf=1]\n"
1219 "Returns Object that has account names as keys, account balances as values.");
1222 if (params.size() > 0)
1223 nMinDepth = params[0].get_int();
1225 map<string, int64> mapAccountBalances;
1226 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& entry, pwalletMain->mapAddressBook) {
1227 if (pwalletMain->HaveKey(entry.first)) // This address belongs to me
1228 mapAccountBalances[entry.second] = 0;
1231 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1233 const CWalletTx& wtx = (*it).second;
1234 int64 nGeneratedImmature, nGeneratedMature, nFee;
1235 string strSentAccount;
1236 list<pair<CBitcoinAddress, int64> > listReceived;
1237 list<pair<CBitcoinAddress, int64> > listSent;
1238 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1239 mapAccountBalances[strSentAccount] -= nFee;
1240 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1241 mapAccountBalances[strSentAccount] -= s.second;
1242 if (wtx.GetDepthInMainChain() >= nMinDepth)
1244 mapAccountBalances[""] += nGeneratedMature;
1245 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1246 if (pwalletMain->mapAddressBook.count(r.first))
1247 mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second;
1249 mapAccountBalances[""] += r.second;
1253 list<CAccountingEntry> acentries;
1254 CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
1255 BOOST_FOREACH(const CAccountingEntry& entry, acentries)
1256 mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
1259 BOOST_FOREACH(const PAIRTYPE(string, int64)& accountBalance, mapAccountBalances) {
1260 ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
1265 Value listsinceblock(const Array& params, bool fHelp)
1268 throw runtime_error(
1269 "listsinceblock [blockid] [target-confirmations]\n"
1270 "Get all transactions in blocks since block [blockid], or all transactions if omitted");
1272 CBlockIndex *pindex = NULL;
1273 int target_confirms = 1;
1275 if (params.size() > 0)
1277 uint256 blockId = 0;
1279 blockId.SetHex(params[0].get_str());
1280 pindex = CBlockLocator(blockId).GetBlockIndex();
1283 if (params.size() > 1)
1285 target_confirms = params[1].get_int();
1287 if (target_confirms < 1)
1288 throw JSONRPCError(-8, "Invalid parameter");
1291 int depth = pindex ? (1 + nBestHeight - pindex->nHeight) : -1;
1295 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++)
1297 CWalletTx tx = (*it).second;
1299 if (depth == -1 || tx.GetDepthInMainChain() < depth)
1300 ListTransactions(tx, "*", 0, true, transactions);
1305 if (target_confirms == 1)
1308 lastblock = hashBestChain;
1312 int target_height = pindexBest->nHeight + 1 - target_confirms;
1315 for (block = pindexBest;
1316 block && block->nHeight > target_height;
1317 block = block->pprev);
1319 lastblock = block ? block->GetBlockHash() : 0;
1323 ret.push_back(Pair("transactions", transactions));
1324 ret.push_back(Pair("lastblock", lastblock.GetHex()));
1329 Value gettransaction(const Array& params, bool fHelp)
1331 if (fHelp || params.size() != 1)
1332 throw runtime_error(
1333 "gettransaction <txid>\n"
1334 "Get detailed information about <txid>");
1337 hash.SetHex(params[0].get_str());
1341 if (!pwalletMain->mapWallet.count(hash))
1342 throw JSONRPCError(-5, "Invalid or non-wallet transaction id");
1343 const CWalletTx& wtx = pwalletMain->mapWallet[hash];
1345 int64 nCredit = wtx.GetCredit();
1346 int64 nDebit = wtx.GetDebit();
1347 int64 nNet = nCredit - nDebit;
1348 int64 nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0);
1350 entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
1352 entry.push_back(Pair("fee", ValueFromAmount(nFee)));
1354 WalletTxToJSON(pwalletMain->mapWallet[hash], entry);
1357 ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details);
1358 entry.push_back(Pair("details", details));
1364 Value backupwallet(const Array& params, bool fHelp)
1366 if (fHelp || params.size() != 1)
1367 throw runtime_error(
1368 "backupwallet <destination>\n"
1369 "Safely copies wallet.dat to destination, which can be a directory or a path with filename.");
1371 string strDest = params[0].get_str();
1372 BackupWallet(*pwalletMain, strDest);
1378 Value keypoolrefill(const Array& params, bool fHelp)
1380 if (pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1381 throw runtime_error(
1383 "Fills the keypool, requires wallet passphrase to be set.");
1384 if (!pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1385 throw runtime_error(
1387 "Fills the keypool.");
1389 if (pwalletMain->IsLocked())
1390 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
1392 pwalletMain->TopUpKeyPool();
1394 if (pwalletMain->GetKeyPoolSize() < GetArg("-keypool", 100))
1395 throw JSONRPCError(-4, "Error refreshing keypool.");
1401 void ThreadTopUpKeyPool(void* parg)
1403 pwalletMain->TopUpKeyPool();
1406 void ThreadCleanWalletPassphrase(void* parg)
1408 int64 nMyWakeTime = GetTime() + *((int*)parg);
1410 if (nWalletUnlockTime == 0)
1412 CRITICAL_BLOCK(cs_nWalletUnlockTime)
1414 nWalletUnlockTime = nMyWakeTime;
1417 while (GetTime() < nWalletUnlockTime)
1418 Sleep(GetTime() - nWalletUnlockTime);
1420 CRITICAL_BLOCK(cs_nWalletUnlockTime)
1422 nWalletUnlockTime = 0;
1427 CRITICAL_BLOCK(cs_nWalletUnlockTime)
1429 if (nWalletUnlockTime < nMyWakeTime)
1430 nWalletUnlockTime = nMyWakeTime;
1436 pwalletMain->Lock();
1441 Value walletpassphrase(const Array& params, bool fHelp)
1443 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1444 throw runtime_error(
1445 "walletpassphrase <passphrase> <timeout>\n"
1446 "Stores the wallet decryption key in memory for <timeout> seconds.");
1449 if (!pwalletMain->IsCrypted())
1450 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
1452 if (!pwalletMain->IsLocked())
1453 throw JSONRPCError(-17, "Error: Wallet is already unlocked.");
1455 // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
1456 SecureString strWalletPass;
1457 strWalletPass.reserve(100);
1458 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1459 // Alternately, find a way to make params[0] mlock()'d to begin with.
1460 strWalletPass = params[0].get_str().c_str();
1462 if (strWalletPass.length() > 0)
1464 if (!pwalletMain->Unlock(strWalletPass))
1465 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1468 throw runtime_error(
1469 "walletpassphrase <passphrase> <timeout>\n"
1470 "Stores the wallet decryption key in memory for <timeout> seconds.");
1472 CreateThread(ThreadTopUpKeyPool, NULL);
1473 int* pnSleepTime = new int(params[1].get_int());
1474 CreateThread(ThreadCleanWalletPassphrase, pnSleepTime);
1480 Value walletpassphrasechange(const Array& params, bool fHelp)
1482 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1483 throw runtime_error(
1484 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1485 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1488 if (!pwalletMain->IsCrypted())
1489 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
1491 // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
1492 // Alternately, find a way to make params[0] mlock()'d to begin with.
1493 SecureString strOldWalletPass;
1494 strOldWalletPass.reserve(100);
1495 strOldWalletPass = params[0].get_str().c_str();
1497 SecureString strNewWalletPass;
1498 strNewWalletPass.reserve(100);
1499 strNewWalletPass = params[1].get_str().c_str();
1501 if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
1502 throw runtime_error(
1503 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1504 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1506 if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
1507 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1513 Value walletlock(const Array& params, bool fHelp)
1515 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
1516 throw runtime_error(
1518 "Removes the wallet encryption key from memory, locking the wallet.\n"
1519 "After calling this method, you will need to call walletpassphrase again\n"
1520 "before being able to call any methods which require the wallet to be unlocked.");
1523 if (!pwalletMain->IsCrypted())
1524 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletlock was called.");
1526 pwalletMain->Lock();
1527 CRITICAL_BLOCK(cs_nWalletUnlockTime)
1529 nWalletUnlockTime = 0;
1536 Value encryptwallet(const Array& params, bool fHelp)
1538 if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
1539 throw runtime_error(
1540 "encryptwallet <passphrase>\n"
1541 "Encrypts the wallet with <passphrase>.");
1544 if (pwalletMain->IsCrypted())
1545 throw JSONRPCError(-15, "Error: running with an encrypted wallet, but encryptwallet was called.");
1548 // shutting down via RPC while the GUI is running does not work (yet):
1549 throw runtime_error("Not Yet Implemented: use GUI to encrypt wallet, not RPC command");
1552 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1553 // Alternately, find a way to make params[0] mlock()'d to begin with.
1554 SecureString strWalletPass;
1555 strWalletPass.reserve(100);
1556 strWalletPass = params[0].get_str().c_str();
1558 if (strWalletPass.length() < 1)
1559 throw runtime_error(
1560 "encryptwallet <passphrase>\n"
1561 "Encrypts the wallet with <passphrase>.");
1563 if (!pwalletMain->EncryptWallet(strWalletPass))
1564 throw JSONRPCError(-16, "Error: Failed to encrypt the wallet.");
1566 // BDB seems to have a bad habit of writing old data into
1567 // slack space in .dat files; that is bad if the old data is
1568 // unencrypted private keys. So:
1569 CreateThread(Shutdown, NULL);
1570 return "wallet encrypted; bitcoin server stopping, restart to run with encrypted wallet";
1574 Value validateaddress(const Array& params, bool fHelp)
1576 if (fHelp || params.size() != 1)
1577 throw runtime_error(
1578 "validateaddress <bitcoinaddress>\n"
1579 "Return information about <bitcoinaddress>.");
1581 CBitcoinAddress address(params[0].get_str());
1582 bool isValid = address.IsValid();
1585 ret.push_back(Pair("isvalid", isValid));
1588 // Call Hash160ToAddress() so we always return current ADDRESSVERSION
1589 // version of the address:
1590 string currentAddress = address.ToString();
1591 ret.push_back(Pair("address", currentAddress));
1592 ret.push_back(Pair("ismine", (pwalletMain->HaveKey(address) > 0)));
1593 if (pwalletMain->mapAddressBook.count(address))
1594 ret.push_back(Pair("account", pwalletMain->mapAddressBook[address]));
1600 Value getwork(const Array& params, bool fHelp)
1602 if (fHelp || params.size() > 1)
1603 throw runtime_error(
1605 "If [data] is not specified, returns formatted hash data to work on:\n"
1606 " \"midstate\" : precomputed hash state after hashing the first half of the data (DEPRECATED)\n" // deprecated
1607 " \"data\" : block data\n"
1608 " \"hash1\" : formatted hash buffer for second hash (DEPRECATED)\n" // deprecated
1609 " \"target\" : little endian hash target\n"
1610 "If [data] is specified, tries to solve the block and returns true if it was successful.");
1613 throw JSONRPCError(-9, "Bitcoin is not connected!");
1615 if (IsInitialBlockDownload())
1616 throw JSONRPCError(-10, "Bitcoin is downloading blocks...");
1618 typedef map<uint256, pair<CBlock*, CScript> > mapNewBlock_t;
1619 static mapNewBlock_t mapNewBlock;
1620 static vector<CBlock*> vNewBlock;
1621 static CReserveKey reservekey(pwalletMain);
1623 if (params.size() == 0)
1626 static unsigned int nTransactionsUpdatedLast;
1627 static CBlockIndex* pindexPrev;
1628 static int64 nStart;
1629 static CBlock* pblock;
1630 if (pindexPrev != pindexBest ||
1631 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60))
1633 if (pindexPrev != pindexBest)
1635 // Deallocate old blocks since they're obsolete now
1636 mapNewBlock.clear();
1637 BOOST_FOREACH(CBlock* pblock, vNewBlock)
1641 nTransactionsUpdatedLast = nTransactionsUpdated;
1642 pindexPrev = pindexBest;
1646 pblock = CreateNewBlock(reservekey);
1648 throw JSONRPCError(-7, "Out of memory");
1649 vNewBlock.push_back(pblock);
1653 pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
1656 // Update nExtraNonce
1657 static unsigned int nExtraNonce = 0;
1658 IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
1661 mapNewBlock[pblock->hashMerkleRoot] = make_pair(pblock, pblock->vtx[0].vin[0].scriptSig);
1663 // Prebuild hash buffers
1667 FormatHashBuffers(pblock, pmidstate, pdata, phash1);
1669 uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
1672 result.push_back(Pair("midstate", HexStr(BEGIN(pmidstate), END(pmidstate)))); // deprecated
1673 result.push_back(Pair("data", HexStr(BEGIN(pdata), END(pdata))));
1674 result.push_back(Pair("hash1", HexStr(BEGIN(phash1), END(phash1)))); // deprecated
1675 result.push_back(Pair("target", HexStr(BEGIN(hashTarget), END(hashTarget))));
1681 vector<unsigned char> vchData = ParseHex(params[0].get_str());
1682 if (vchData.size() != 128)
1683 throw JSONRPCError(-8, "Invalid parameter");
1684 CBlock* pdata = (CBlock*)&vchData[0];
1687 for (int i = 0; i < 128/4; i++)
1688 ((unsigned int*)pdata)[i] = ByteReverse(((unsigned int*)pdata)[i]);
1691 if (!mapNewBlock.count(pdata->hashMerkleRoot))
1693 CBlock* pblock = mapNewBlock[pdata->hashMerkleRoot].first;
1695 pblock->nTime = pdata->nTime;
1696 pblock->nNonce = pdata->nNonce;
1697 pblock->vtx[0].vin[0].scriptSig = mapNewBlock[pdata->hashMerkleRoot].second;
1698 pblock->hashMerkleRoot = pblock->BuildMerkleTree();
1700 return CheckWork(pblock, *pwalletMain, reservekey);
1705 Value getmemorypool(const Array& params, bool fHelp)
1707 if (fHelp || params.size() > 1)
1708 throw runtime_error(
1709 "getmemorypool [data]\n"
1710 "If [data] is not specified, returns data needed to construct a block to work on:\n"
1711 " \"version\" : block version\n"
1712 " \"previousblockhash\" : hash of current highest block\n"
1713 " \"transactions\" : contents of non-coinbase transactions that should be included in the next block\n"
1714 " \"coinbasevalue\" : maximum allowable input to coinbase transaction, including the generation award and transaction fees\n"
1715 " \"time\" : timestamp appropriate for next block\n"
1716 " \"bits\" : compressed target of next block\n"
1717 "If [data] is specified, tries to solve the block and returns true if it was successful.");
1719 if (params.size() == 0)
1722 throw JSONRPCError(-9, "Bitcoin is not connected!");
1724 if (IsInitialBlockDownload())
1725 throw JSONRPCError(-10, "Bitcoin is downloading blocks...");
1727 static CReserveKey reservekey(pwalletMain);
1730 static unsigned int nTransactionsUpdatedLast;
1731 static CBlockIndex* pindexPrev;
1732 static int64 nStart;
1733 static CBlock* pblock;
1734 if (pindexPrev != pindexBest ||
1735 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 5))
1737 nTransactionsUpdatedLast = nTransactionsUpdated;
1738 pindexPrev = pindexBest;
1744 pblock = CreateNewBlock(reservekey);
1746 throw JSONRPCError(-7, "Out of memory");
1750 pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
1754 BOOST_FOREACH(CTransaction tx, pblock->vtx) {
1761 transactions.push_back(HexStr(ssTx.begin(), ssTx.end()));
1765 result.push_back(Pair("version", pblock->nVersion));
1766 result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex()));
1767 result.push_back(Pair("transactions", transactions));
1768 result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue));
1769 result.push_back(Pair("time", (int64_t)pblock->nTime));
1775 uBits.nBits = htonl((int32_t)pblock->nBits);
1776 result.push_back(Pair("bits", HexStr(BEGIN(uBits.cBits), END(uBits.cBits))));
1783 CDataStream ssBlock(ParseHex(params[0].get_str()));
1787 return ProcessBlock(NULL, &pblock);
1805 pair<string, rpcfn_type> pCallTable[] =
1807 make_pair("help", &help),
1808 make_pair("stop", &stop),
1809 make_pair("getblockcount", &getblockcount),
1810 make_pair("getblocknumber", &getblocknumber),
1811 make_pair("getconnectioncount", &getconnectioncount),
1812 make_pair("getdifficulty", &getdifficulty),
1813 make_pair("getgenerate", &getgenerate),
1814 make_pair("setgenerate", &setgenerate),
1815 make_pair("gethashespersec", &gethashespersec),
1816 make_pair("getinfo", &getinfo),
1817 make_pair("getnewaddress", &getnewaddress),
1818 make_pair("getaccountaddress", &getaccountaddress),
1819 make_pair("setaccount", &setaccount),
1820 make_pair("getaccount", &getaccount),
1821 make_pair("getaddressesbyaccount", &getaddressesbyaccount),
1822 make_pair("sendtoaddress", &sendtoaddress),
1823 make_pair("getreceivedbyaddress", &getreceivedbyaddress),
1824 make_pair("getreceivedbyaccount", &getreceivedbyaccount),
1825 make_pair("listreceivedbyaddress", &listreceivedbyaddress),
1826 make_pair("listreceivedbyaccount", &listreceivedbyaccount),
1827 make_pair("backupwallet", &backupwallet),
1828 make_pair("keypoolrefill", &keypoolrefill),
1829 make_pair("walletpassphrase", &walletpassphrase),
1830 make_pair("walletpassphrasechange", &walletpassphrasechange),
1831 make_pair("walletlock", &walletlock),
1832 make_pair("encryptwallet", &encryptwallet),
1833 make_pair("validateaddress", &validateaddress),
1834 make_pair("getbalance", &getbalance),
1835 make_pair("move", &movecmd),
1836 make_pair("sendfrom", &sendfrom),
1837 make_pair("sendmany", &sendmany),
1838 make_pair("gettransaction", &gettransaction),
1839 make_pair("listtransactions", &listtransactions),
1840 make_pair("signmessage", &signmessage),
1841 make_pair("verifymessage", &verifymessage),
1842 make_pair("getwork", &getwork),
1843 make_pair("listaccounts", &listaccounts),
1844 make_pair("settxfee", &settxfee),
1845 make_pair("getmemorypool", &getmemorypool),
1846 make_pair("listsinceblock", &listsinceblock),
1848 map<string, rpcfn_type> mapCallTable(pCallTable, pCallTable + sizeof(pCallTable)/sizeof(pCallTable[0]));
1850 string pAllowInSafeMode[] =
1855 "getblocknumber", // deprecated
1856 "getconnectioncount",
1863 "getaccountaddress",
1865 "getaddressesbyaccount",
1874 set<string> setAllowInSafeMode(pAllowInSafeMode, pAllowInSafeMode + sizeof(pAllowInSafeMode)/sizeof(pAllowInSafeMode[0]));
1882 // This ain't Apache. We're just using HTTP header for the length field
1883 // and to be compatible with other JSON-RPC implementations.
1886 string HTTPPost(const string& strMsg, const map<string,string>& mapRequestHeaders)
1889 s << "POST / HTTP/1.1\r\n"
1890 << "User-Agent: bitcoin-json-rpc/" << FormatFullVersion() << "\r\n"
1891 << "Host: 127.0.0.1\r\n"
1892 << "Content-Type: application/json\r\n"
1893 << "Content-Length: " << strMsg.size() << "\r\n"
1894 << "Connection: close\r\n"
1895 << "Accept: application/json\r\n";
1896 BOOST_FOREACH(const PAIRTYPE(string, string)& item, mapRequestHeaders)
1897 s << item.first << ": " << item.second << "\r\n";
1898 s << "\r\n" << strMsg;
1903 string rfc1123Time()
1908 struct tm* now_gmt = gmtime(&now);
1909 string locale(setlocale(LC_TIME, NULL));
1910 setlocale(LC_TIME, "C"); // we want posix (aka "C") weekday/month strings
1911 strftime(buffer, sizeof(buffer), "%a, %d %b %Y %H:%M:%S +0000", now_gmt);
1912 setlocale(LC_TIME, locale.c_str());
1913 return string(buffer);
1916 static string HTTPReply(int nStatus, const string& strMsg)
1919 return strprintf("HTTP/1.0 401 Authorization Required\r\n"
1921 "Server: bitcoin-json-rpc/%s\r\n"
1922 "WWW-Authenticate: Basic realm=\"jsonrpc\"\r\n"
1923 "Content-Type: text/html\r\n"
1924 "Content-Length: 296\r\n"
1926 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\r\n"
1927 "\"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd\">\r\n"
1930 "<TITLE>Error</TITLE>\r\n"
1931 "<META HTTP-EQUIV='Content-Type' CONTENT='text/html; charset=ISO-8859-1'>\r\n"
1933 "<BODY><H1>401 Unauthorized.</H1></BODY>\r\n"
1934 "</HTML>\r\n", rfc1123Time().c_str(), FormatFullVersion().c_str());
1935 const char *cStatus;
1936 if (nStatus == 200) cStatus = "OK";
1937 else if (nStatus == 400) cStatus = "Bad Request";
1938 else if (nStatus == 403) cStatus = "Forbidden";
1939 else if (nStatus == 404) cStatus = "Not Found";
1940 else if (nStatus == 500) cStatus = "Internal Server Error";
1943 "HTTP/1.1 %d %s\r\n"
1945 "Connection: close\r\n"
1946 "Content-Length: %d\r\n"
1947 "Content-Type: application/json\r\n"
1948 "Server: bitcoin-json-rpc/%s\r\n"
1953 rfc1123Time().c_str(),
1955 FormatFullVersion().c_str(),
1959 int ReadHTTPStatus(std::basic_istream<char>& stream)
1962 getline(stream, str);
1963 vector<string> vWords;
1964 boost::split(vWords, str, boost::is_any_of(" "));
1965 if (vWords.size() < 2)
1967 return atoi(vWords[1].c_str());
1970 int ReadHTTPHeader(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet)
1976 std::getline(stream, str);
1977 if (str.empty() || str == "\r")
1979 string::size_type nColon = str.find(":");
1980 if (nColon != string::npos)
1982 string strHeader = str.substr(0, nColon);
1983 boost::trim(strHeader);
1984 boost::to_lower(strHeader);
1985 string strValue = str.substr(nColon+1);
1986 boost::trim(strValue);
1987 mapHeadersRet[strHeader] = strValue;
1988 if (strHeader == "content-length")
1989 nLen = atoi(strValue.c_str());
1995 int ReadHTTP(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet, string& strMessageRet)
1997 mapHeadersRet.clear();
2001 int nStatus = ReadHTTPStatus(stream);
2004 int nLen = ReadHTTPHeader(stream, mapHeadersRet);
2005 if (nLen < 0 || nLen > MAX_SIZE)
2011 vector<char> vch(nLen);
2012 stream.read(&vch[0], nLen);
2013 strMessageRet = string(vch.begin(), vch.end());
2019 bool HTTPAuthorized(map<string, string>& mapHeaders)
2021 string strAuth = mapHeaders["authorization"];
2022 if (strAuth.substr(0,6) != "Basic ")
2024 string strUserPass64 = strAuth.substr(6); boost::trim(strUserPass64);
2025 string strUserPass = DecodeBase64(strUserPass64);
2026 string::size_type nColon = strUserPass.find(":");
2027 if (nColon == string::npos)
2029 string strUser = strUserPass.substr(0, nColon);
2030 string strPassword = strUserPass.substr(nColon+1);
2031 return (strUser == mapArgs["-rpcuser"] && strPassword == mapArgs["-rpcpassword"]);
2035 // JSON-RPC protocol. Bitcoin speaks version 1.0 for maximum compatibility,
2036 // but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
2037 // unspecified (HTTP errors and contents of 'error').
2039 // 1.0 spec: http://json-rpc.org/wiki/specification
2040 // 1.2 spec: http://groups.google.com/group/json-rpc/web/json-rpc-over-http
2041 // http://www.codeproject.com/KB/recipes/JSON_Spirit.aspx
2044 string JSONRPCRequest(const string& strMethod, const Array& params, const Value& id)
2047 request.push_back(Pair("method", strMethod));
2048 request.push_back(Pair("params", params));
2049 request.push_back(Pair("id", id));
2050 return write_string(Value(request), false) + "\n";
2053 string JSONRPCReply(const Value& result, const Value& error, const Value& id)
2056 if (error.type() != null_type)
2057 reply.push_back(Pair("result", Value::null));
2059 reply.push_back(Pair("result", result));
2060 reply.push_back(Pair("error", error));
2061 reply.push_back(Pair("id", id));
2062 return write_string(Value(reply), false) + "\n";
2065 void ErrorReply(std::ostream& stream, const Object& objError, const Value& id)
2067 // Send error reply from json-rpc error object
2069 int code = find_value(objError, "code").get_int();
2070 if (code == -32600) nStatus = 400;
2071 else if (code == -32601) nStatus = 404;
2072 string strReply = JSONRPCReply(Value::null, objError, id);
2073 stream << HTTPReply(nStatus, strReply) << std::flush;
2076 bool ClientAllowed(const string& strAddress)
2078 if (strAddress == asio::ip::address_v4::loopback().to_string())
2080 const vector<string>& vAllow = mapMultiArgs["-rpcallowip"];
2081 BOOST_FOREACH(string strAllow, vAllow)
2082 if (WildcardMatch(strAddress, strAllow))
2089 // IOStream device that speaks SSL but can also speak non-SSL
2091 class SSLIOStreamDevice : public iostreams::device<iostreams::bidirectional> {
2093 SSLIOStreamDevice(SSLStream &streamIn, bool fUseSSLIn) : stream(streamIn)
2095 fUseSSL = fUseSSLIn;
2096 fNeedHandshake = fUseSSLIn;
2099 void handshake(ssl::stream_base::handshake_type role)
2101 if (!fNeedHandshake) return;
2102 fNeedHandshake = false;
2103 stream.handshake(role);
2105 std::streamsize read(char* s, std::streamsize n)
2107 handshake(ssl::stream_base::server); // HTTPS servers read first
2108 if (fUseSSL) return stream.read_some(asio::buffer(s, n));
2109 return stream.next_layer().read_some(asio::buffer(s, n));
2111 std::streamsize write(const char* s, std::streamsize n)
2113 handshake(ssl::stream_base::client); // HTTPS clients write first
2114 if (fUseSSL) return asio::write(stream, asio::buffer(s, n));
2115 return asio::write(stream.next_layer(), asio::buffer(s, n));
2117 bool connect(const std::string& server, const std::string& port)
2119 ip::tcp::resolver resolver(stream.get_io_service());
2120 ip::tcp::resolver::query query(server.c_str(), port.c_str());
2121 ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
2122 ip::tcp::resolver::iterator end;
2123 boost::system::error_code error = asio::error::host_not_found;
2124 while (error && endpoint_iterator != end)
2126 stream.lowest_layer().close();
2127 stream.lowest_layer().connect(*endpoint_iterator++, error);
2135 bool fNeedHandshake;
2141 void ThreadRPCServer(void* parg)
2143 IMPLEMENT_RANDOMIZE_STACK(ThreadRPCServer(parg));
2146 vnThreadsRunning[4]++;
2147 ThreadRPCServer2(parg);
2148 vnThreadsRunning[4]--;
2150 catch (std::exception& e) {
2151 vnThreadsRunning[4]--;
2152 PrintException(&e, "ThreadRPCServer()");
2154 vnThreadsRunning[4]--;
2155 PrintException(NULL, "ThreadRPCServer()");
2157 printf("ThreadRPCServer exiting\n");
2160 void ThreadRPCServer2(void* parg)
2162 printf("ThreadRPCServer started\n");
2164 if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
2166 string strWhatAmI = "To use bitcoind";
2167 if (mapArgs.count("-server"))
2168 strWhatAmI = strprintf(_("To use the %s option"), "\"-server\"");
2169 else if (mapArgs.count("-daemon"))
2170 strWhatAmI = strprintf(_("To use the %s option"), "\"-daemon\"");
2172 _("Error: %s, you must set rpcpassword=<password>\nin the configuration file: %s\n"
2173 "If the file does not exist, create it with owner-readable-only file permissions.\n"),
2175 GetConfigFile().c_str());
2177 CreateThread(Shutdown, NULL);
2182 bool fUseSSL = GetBoolArg("-rpcssl");
2183 asio::ip::address bindAddress = mapArgs.count("-rpcallowip") ? asio::ip::address_v4::any() : asio::ip::address_v4::loopback();
2185 asio::io_service io_service;
2186 ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", 8332));
2187 ip::tcp::acceptor acceptor(io_service, endpoint);
2189 acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
2192 ssl::context context(io_service, ssl::context::sslv23);
2195 context.set_options(ssl::context::no_sslv2);
2196 filesystem::path certfile = GetArg("-rpcsslcertificatechainfile", "server.cert");
2197 if (!certfile.is_complete()) certfile = filesystem::path(GetDataDir()) / certfile;
2198 if (filesystem::exists(certfile)) context.use_certificate_chain_file(certfile.string().c_str());
2199 else printf("ThreadRPCServer ERROR: missing server certificate file %s\n", certfile.string().c_str());
2200 filesystem::path pkfile = GetArg("-rpcsslprivatekeyfile", "server.pem");
2201 if (!pkfile.is_complete()) pkfile = filesystem::path(GetDataDir()) / pkfile;
2202 if (filesystem::exists(pkfile)) context.use_private_key_file(pkfile.string().c_str(), ssl::context::pem);
2203 else printf("ThreadRPCServer ERROR: missing server private key file %s\n", pkfile.string().c_str());
2205 string ciphers = GetArg("-rpcsslciphers",
2206 "TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH");
2207 SSL_CTX_set_cipher_list(context.impl(), ciphers.c_str());
2211 throw runtime_error("-rpcssl=1, but bitcoin compiled without full openssl libraries.");
2216 // Accept connection
2218 SSLStream sslStream(io_service, context);
2219 SSLIOStreamDevice d(sslStream, fUseSSL);
2220 iostreams::stream<SSLIOStreamDevice> stream(d);
2222 ip::tcp::iostream stream;
2225 ip::tcp::endpoint peer;
2226 vnThreadsRunning[4]--;
2228 acceptor.accept(sslStream.lowest_layer(), peer);
2230 acceptor.accept(*stream.rdbuf(), peer);
2232 vnThreadsRunning[4]++;
2236 // Restrict callers by IP
2237 if (!ClientAllowed(peer.address().to_string()))
2239 // Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake.
2241 stream << HTTPReply(403, "") << std::flush;
2245 map<string, string> mapHeaders;
2248 boost::thread api_caller(ReadHTTP, boost::ref(stream), boost::ref(mapHeaders), boost::ref(strRequest));
2249 if (!api_caller.timed_join(boost::posix_time::seconds(GetArg("-rpctimeout", 30))))
2252 printf("ThreadRPCServer ReadHTTP timeout\n");
2256 // Check authorization
2257 if (mapHeaders.count("authorization") == 0)
2259 stream << HTTPReply(401, "") << std::flush;
2262 if (!HTTPAuthorized(mapHeaders))
2264 // Deter brute-forcing short passwords
2265 if (mapArgs["-rpcpassword"].size() < 15)
2268 stream << HTTPReply(401, "") << std::flush;
2269 printf("ThreadRPCServer incorrect password attempt\n");
2273 Value id = Value::null;
2278 if (!read_string(strRequest, valRequest) || valRequest.type() != obj_type)
2279 throw JSONRPCError(-32700, "Parse error");
2280 const Object& request = valRequest.get_obj();
2282 // Parse id now so errors from here on will have the id
2283 id = find_value(request, "id");
2286 Value valMethod = find_value(request, "method");
2287 if (valMethod.type() == null_type)
2288 throw JSONRPCError(-32600, "Missing method");
2289 if (valMethod.type() != str_type)
2290 throw JSONRPCError(-32600, "Method must be a string");
2291 string strMethod = valMethod.get_str();
2292 if (strMethod != "getwork" && strMethod != "getmemorypool")
2293 printf("ThreadRPCServer method=%s\n", strMethod.c_str());
2296 Value valParams = find_value(request, "params");
2298 if (valParams.type() == array_type)
2299 params = valParams.get_array();
2300 else if (valParams.type() == null_type)
2303 throw JSONRPCError(-32600, "Params must be an array");
2306 map<string, rpcfn_type>::iterator mi = mapCallTable.find(strMethod);
2307 if (mi == mapCallTable.end())
2308 throw JSONRPCError(-32601, "Method not found");
2310 // Observe safe mode
2311 string strWarning = GetWarnings("rpc");
2312 if (strWarning != "" && !GetBoolArg("-disablesafemode") && !setAllowInSafeMode.count(strMethod))
2313 throw JSONRPCError(-2, string("Safe mode: ") + strWarning);
2319 CRITICAL_BLOCK(cs_main)
2320 CRITICAL_BLOCK(pwalletMain->cs_wallet)
2321 result = (*(*mi).second)(params, false);
2324 string strReply = JSONRPCReply(result, Value::null, id);
2325 stream << HTTPReply(200, strReply) << std::flush;
2327 catch (std::exception& e)
2329 ErrorReply(stream, JSONRPCError(-1, e.what()), id);
2332 catch (Object& objError)
2334 ErrorReply(stream, objError, id);
2336 catch (std::exception& e)
2338 ErrorReply(stream, JSONRPCError(-32700, e.what()), id);
2346 Object CallRPC(const string& strMethod, const Array& params)
2348 if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
2349 throw runtime_error(strprintf(
2350 _("You must set rpcpassword=<password> in the configuration file:\n%s\n"
2351 "If the file does not exist, create it with owner-readable-only file permissions."),
2352 GetConfigFile().c_str()));
2354 // Connect to localhost
2355 bool fUseSSL = GetBoolArg("-rpcssl");
2357 asio::io_service io_service;
2358 ssl::context context(io_service, ssl::context::sslv23);
2359 context.set_options(ssl::context::no_sslv2);
2360 SSLStream sslStream(io_service, context);
2361 SSLIOStreamDevice d(sslStream, fUseSSL);
2362 iostreams::stream<SSLIOStreamDevice> stream(d);
2363 if (!d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332")))
2364 throw runtime_error("couldn't connect to server");
2367 throw runtime_error("-rpcssl=1, but bitcoin compiled without full openssl libraries.");
2369 ip::tcp::iostream stream(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332"));
2371 throw runtime_error("couldn't connect to server");
2375 // HTTP basic authentication
2376 string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
2377 map<string, string> mapRequestHeaders;
2378 mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64;
2381 string strRequest = JSONRPCRequest(strMethod, params, 1);
2382 string strPost = HTTPPost(strRequest, mapRequestHeaders);
2383 stream << strPost << std::flush;
2386 map<string, string> mapHeaders;
2388 int nStatus = ReadHTTP(stream, mapHeaders, strReply);
2390 throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
2391 else if (nStatus >= 400 && nStatus != 400 && nStatus != 404 && nStatus != 500)
2392 throw runtime_error(strprintf("server returned HTTP error %d", nStatus));
2393 else if (strReply.empty())
2394 throw runtime_error("no response from server");
2398 if (!read_string(strReply, valReply))
2399 throw runtime_error("couldn't parse reply from server");
2400 const Object& reply = valReply.get_obj();
2402 throw runtime_error("expected reply to have result, error and id properties");
2410 template<typename T>
2411 void ConvertTo(Value& value)
2413 if (value.type() == str_type)
2415 // reinterpret string as unquoted json value
2417 if (!read_string(value.get_str(), value2))
2418 throw runtime_error("type mismatch");
2419 value = value2.get_value<T>();
2423 value = value.get_value<T>();
2427 int CommandLineRPC(int argc, char *argv[])
2434 while (argc > 1 && IsSwitchChar(argv[1][0]))
2442 throw runtime_error("too few parameters");
2443 string strMethod = argv[1];
2445 // Parameters default to strings
2447 for (int i = 2; i < argc; i++)
2448 params.push_back(argv[i]);
2449 int n = params.size();
2452 // Special case non-string parameter types
2454 if (strMethod == "setgenerate" && n > 0) ConvertTo<bool>(params[0]);
2455 if (strMethod == "setgenerate" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2456 if (strMethod == "sendtoaddress" && n > 1) ConvertTo<double>(params[1]);
2457 if (strMethod == "settxfee" && n > 0) ConvertTo<double>(params[0]);
2458 if (strMethod == "getreceivedbyaddress" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2459 if (strMethod == "getreceivedbyaccount" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2460 if (strMethod == "listreceivedbyaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2461 if (strMethod == "listreceivedbyaddress" && n > 1) ConvertTo<bool>(params[1]);
2462 if (strMethod == "listreceivedbyaccount" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2463 if (strMethod == "listreceivedbyaccount" && n > 1) ConvertTo<bool>(params[1]);
2464 if (strMethod == "getbalance" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2465 if (strMethod == "move" && n > 2) ConvertTo<double>(params[2]);
2466 if (strMethod == "move" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2467 if (strMethod == "sendfrom" && n > 2) ConvertTo<double>(params[2]);
2468 if (strMethod == "sendfrom" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2469 if (strMethod == "listtransactions" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2470 if (strMethod == "listtransactions" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2471 if (strMethod == "listaccounts" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2472 if (strMethod == "walletpassphrase" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2473 if (strMethod == "listsinceblock" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2474 if (strMethod == "sendmany" && n > 1)
2476 string s = params[1].get_str();
2478 if (!read_string(s, v) || v.type() != obj_type)
2479 throw runtime_error("type mismatch");
2480 params[1] = v.get_obj();
2482 if (strMethod == "sendmany" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2485 Object reply = CallRPC(strMethod, params);
2488 const Value& result = find_value(reply, "result");
2489 const Value& error = find_value(reply, "error");
2491 if (error.type() != null_type)
2494 strPrint = "error: " + write_string(error, false);
2495 int code = find_value(error.get_obj(), "code").get_int();
2501 if (result.type() == null_type)
2503 else if (result.type() == str_type)
2504 strPrint = result.get_str();
2506 strPrint = write_string(result, true);
2509 catch (std::exception& e)
2511 strPrint = string("error: ") + e.what();
2516 PrintException(NULL, "CommandLineRPC()");
2521 fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
2530 int main(int argc, char *argv[])
2533 // Turn off microsoft heap dump noise
2534 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
2535 _CrtSetReportFile(_CRT_WARN, CreateFile("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0));
2537 setbuf(stdin, NULL);
2538 setbuf(stdout, NULL);
2539 setbuf(stderr, NULL);
2543 if (argc >= 2 && string(argv[1]) == "-server")
2545 printf("server ready\n");
2546 ThreadRPCServer(NULL);
2550 return CommandLineRPC(argc, argv);
2553 catch (std::exception& e) {
2554 PrintException(&e, "main()");
2556 PrintException(NULL, "main()");