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/filesystem.hpp>
13 #include <boost/iostreams/concepts.hpp>
14 #include <boost/iostreams/stream.hpp>
15 #include <boost/algorithm/string.hpp>
16 #include <boost/lexical_cast.hpp>
18 #include <boost/asio/ssl.hpp>
19 #include <boost/filesystem.hpp>
20 #include <boost/filesystem/fstream.hpp>
21 typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> SSLStream;
23 #include "json/json_spirit_reader_template.h"
24 #include "json/json_spirit_writer_template.h"
25 #include "json/json_spirit_utils.h"
26 #define printf OutputDebugStringF
27 // MinGW 3.4.5 gets "fatal error: had to relocate PCH" if the json headers are
28 // precompiled in headers.h. The problem might be when the pch file goes over
29 // a certain size around 145MB. If we need access to json_spirit outside this
30 // file, we could use the compiled json_spirit option.
33 using namespace boost;
34 using namespace boost::asio;
35 using namespace json_spirit;
37 void ThreadRPCServer2(void* parg);
38 typedef Value(*rpcfn_type)(const Array& params, bool fHelp);
39 extern map<string, rpcfn_type> mapCallTable;
41 static std::string strRPCUserColonPass;
43 static int64 nWalletUnlockTime;
44 static CCriticalSection cs_nWalletUnlockTime;
46 extern Value dumpprivkey(const Array& params, bool fHelp);
47 extern Value importprivkey(const Array& params, bool fHelp);
49 Object JSONRPCError(int code, const string& message)
52 error.push_back(Pair("code", code));
53 error.push_back(Pair("message", message));
58 void PrintConsole(const std::string &format, ...)
61 int limit = sizeof(buffer);
63 va_start(arg_ptr, format);
64 int ret = _vsnprintf(buffer, limit, format.c_str(), arg_ptr);
66 if (ret < 0 || ret >= limit)
72 fprintf(stdout, "%s", buffer);
76 int64 AmountFromValue(const Value& value)
78 double dAmount = value.get_real();
79 if (dAmount <= 0.0 || dAmount > 21000000.0)
80 throw JSONRPCError(-3, "Invalid amount");
81 int64 nAmount = roundint64(dAmount * COIN);
82 if (!MoneyRange(nAmount))
83 throw JSONRPCError(-3, "Invalid amount");
87 Value ValueFromAmount(int64 amount)
89 return (double)amount / (double)COIN;
92 void WalletTxToJSON(const CWalletTx& wtx, Object& entry)
94 entry.push_back(Pair("confirmations", wtx.GetDepthInMainChain()));
95 entry.push_back(Pair("txid", wtx.GetHash().GetHex()));
96 entry.push_back(Pair("time", (boost::int64_t)wtx.GetTxTime()));
97 BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue)
98 entry.push_back(Pair(item.first, item.second));
101 string AccountFromValue(const Value& value)
103 string strAccount = value.get_str();
104 if (strAccount == "*")
105 throw JSONRPCError(-11, "Invalid account name");
112 /// Note: This interface may still be subject to change.
116 Value help(const Array& params, bool fHelp)
118 if (fHelp || params.size() > 1)
121 "List commands, or get help for a command.");
124 if (params.size() > 0)
125 strCommand = params[0].get_str();
128 set<rpcfn_type> setDone;
129 for (map<string, rpcfn_type>::iterator mi = mapCallTable.begin(); mi != mapCallTable.end(); ++mi)
131 string strMethod = (*mi).first;
132 // We already filter duplicates, but these deprecated screw up the sort order
133 if (strMethod == "getamountreceived" ||
134 strMethod == "getallreceived" ||
135 strMethod == "getblocknumber" || // deprecated
136 (strMethod.find("label") != string::npos))
138 if (strCommand != "" && strMethod != strCommand)
143 rpcfn_type pfn = (*mi).second;
144 if (setDone.insert(pfn).second)
145 (*pfn)(params, true);
147 catch (std::exception& e)
149 // Help text is returned in an exception
150 string strHelp = string(e.what());
151 if (strCommand == "")
152 if (strHelp.find('\n') != -1)
153 strHelp = strHelp.substr(0, strHelp.find('\n'));
154 strRet += strHelp + "\n";
158 strRet = strprintf("help: unknown command: %s\n", strCommand.c_str());
159 strRet = strRet.substr(0,strRet.size()-1);
164 Value stop(const Array& params, bool fHelp)
166 if (fHelp || params.size() != 0)
169 "Stop bitcoin server.");
171 // Shutdown will take long enough that the response should get back
172 CreateThread(Shutdown, NULL);
173 return "bitcoin server stopping";
175 throw runtime_error("NYI: cannot shut down GUI with RPC command");
180 Value getblockcount(const Array& params, bool fHelp)
182 if (fHelp || params.size() != 0)
185 "Returns the number of blocks in the longest block chain.");
192 Value getblocknumber(const Array& params, bool fHelp)
194 if (fHelp || params.size() != 0)
197 "Deprecated. Use getblockcount.");
203 Value getconnectioncount(const Array& params, bool fHelp)
205 if (fHelp || params.size() != 0)
207 "getconnectioncount\n"
208 "Returns the number of connections to other nodes.");
210 return (int)vNodes.size();
214 double GetDifficulty()
216 // Floating point number that is a multiple of the minimum difficulty,
217 // minimum difficulty = 1.0.
219 if (pindexBest == NULL)
221 int nShift = (pindexBest->nBits >> 24) & 0xff;
224 (double)0x0000ffff / (double)(pindexBest->nBits & 0x00ffffff);
240 Value getdifficulty(const Array& params, bool fHelp)
242 if (fHelp || params.size() != 0)
245 "Returns the proof-of-work difficulty as a multiple of the minimum difficulty.");
247 return GetDifficulty();
251 Value getgenerate(const Array& params, bool fHelp)
253 if (fHelp || params.size() != 0)
256 "Returns true or false.");
258 return (bool)fGenerateBitcoins;
262 Value setgenerate(const Array& params, bool fHelp)
264 if (fHelp || params.size() < 1 || params.size() > 2)
266 "setgenerate <generate> [genproclimit]\n"
267 "<generate> is true or false to turn generation on or off.\n"
268 "Generation is limited to [genproclimit] processors, -1 is unlimited.");
270 bool fGenerate = true;
271 if (params.size() > 0)
272 fGenerate = params[0].get_bool();
274 if (params.size() > 1)
276 int nGenProcLimit = params[1].get_int();
277 fLimitProcessors = (nGenProcLimit != -1);
278 WriteSetting("fLimitProcessors", fLimitProcessors);
279 if (nGenProcLimit != -1)
280 WriteSetting("nLimitProcessors", nLimitProcessors = nGenProcLimit);
281 if (nGenProcLimit == 0)
285 GenerateBitcoins(fGenerate, pwalletMain);
290 Value gethashespersec(const Array& params, bool fHelp)
292 if (fHelp || params.size() != 0)
295 "Returns a recent hashes per second performance measurement while generating.");
297 if (GetTimeMillis() - nHPSTimerStart > 8000)
298 return (boost::int64_t)0;
299 return (boost::int64_t)dHashesPerSec;
303 Value getinfo(const Array& params, bool fHelp)
305 if (fHelp || params.size() != 0)
308 "Returns an object containing various state info.");
311 obj.push_back(Pair("version", (int)VERSION));
312 obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance())));
313 obj.push_back(Pair("blocks", (int)nBestHeight));
314 obj.push_back(Pair("connections", (int)vNodes.size()));
315 obj.push_back(Pair("proxy", (fUseProxy ? addrProxy.ToStringIPPort() : string())));
316 obj.push_back(Pair("generate", (bool)fGenerateBitcoins));
317 obj.push_back(Pair("genproclimit", (int)(fLimitProcessors ? nLimitProcessors : -1)));
318 obj.push_back(Pair("difficulty", (double)GetDifficulty()));
319 obj.push_back(Pair("hashespersec", gethashespersec(params, false)));
320 obj.push_back(Pair("testnet", fTestNet));
321 obj.push_back(Pair("keypoololdest", (boost::int64_t)pwalletMain->GetOldestKeyPoolTime()));
322 obj.push_back(Pair("keypoolsize", pwalletMain->GetKeyPoolSize()));
323 obj.push_back(Pair("paytxfee", ValueFromAmount(nTransactionFee)));
324 if (pwalletMain->IsCrypted())
325 obj.push_back(Pair("unlocked_until", (boost::int64_t)nWalletUnlockTime));
326 obj.push_back(Pair("errors", GetWarnings("statusbar")));
331 Value getnewaddress(const Array& params, bool fHelp)
333 if (fHelp || params.size() > 1)
335 "getnewaddress [account]\n"
336 "Returns a new bitcoin address for receiving payments. "
337 "If [account] is specified (recommended), it is added to the address book "
338 "so payments received with the address will be credited to [account].");
340 // Parse the account first so we don't generate a key if there's an error
342 if (params.size() > 0)
343 strAccount = AccountFromValue(params[0]);
345 if (!pwalletMain->IsLocked())
346 pwalletMain->TopUpKeyPool();
348 // Generate a new key that is added to wallet
349 std::vector<unsigned char> newKey;
350 if (!pwalletMain->GetKeyFromPool(newKey, false))
351 throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
352 CBitcoinAddress address(newKey);
354 pwalletMain->SetAddressBookName(address, strAccount);
356 return address.ToString();
360 CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false)
362 CWalletDB walletdb(pwalletMain->strWalletFile);
365 walletdb.ReadAccount(strAccount, account);
367 bool bKeyUsed = false;
369 // Check if the current key has been used
370 if (!account.vchPubKey.empty())
372 CScript scriptPubKey;
373 scriptPubKey.SetBitcoinAddress(account.vchPubKey);
374 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
375 it != pwalletMain->mapWallet.end() && !account.vchPubKey.empty();
378 const CWalletTx& wtx = (*it).second;
379 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
380 if (txout.scriptPubKey == scriptPubKey)
385 // Generate a new key
386 if (account.vchPubKey.empty() || bForceNew || bKeyUsed)
388 if (!pwalletMain->GetKeyFromPool(account.vchPubKey, false))
389 throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
391 pwalletMain->SetAddressBookName(CBitcoinAddress(account.vchPubKey), strAccount);
392 walletdb.WriteAccount(strAccount, account);
395 return CBitcoinAddress(account.vchPubKey);
398 Value getaccountaddress(const Array& params, bool fHelp)
400 if (fHelp || params.size() != 1)
402 "getaccountaddress <account>\n"
403 "Returns the current bitcoin address for receiving payments to this account.");
405 // Parse the account first so we don't generate a key if there's an error
406 string strAccount = AccountFromValue(params[0]);
410 ret = GetAccountAddress(strAccount).ToString();
417 Value setaccount(const Array& params, bool fHelp)
419 if (fHelp || params.size() < 1 || params.size() > 2)
421 "setaccount <bitcoinaddress> <account>\n"
422 "Sets the account associated with the given address.");
424 CBitcoinAddress address(params[0].get_str());
425 if (!address.IsValid())
426 throw JSONRPCError(-5, "Invalid bitcoin address");
430 if (params.size() > 1)
431 strAccount = AccountFromValue(params[1]);
433 // Detect when changing the account of an address that is the 'unused current key' of another account:
434 if (pwalletMain->mapAddressBook.count(address))
436 string strOldAccount = pwalletMain->mapAddressBook[address];
437 if (address == GetAccountAddress(strOldAccount))
438 GetAccountAddress(strOldAccount, true);
441 pwalletMain->SetAddressBookName(address, strAccount);
447 Value getaccount(const Array& params, bool fHelp)
449 if (fHelp || params.size() != 1)
451 "getaccount <bitcoinaddress>\n"
452 "Returns the account associated with the given address.");
454 CBitcoinAddress address(params[0].get_str());
455 if (!address.IsValid())
456 throw JSONRPCError(-5, "Invalid bitcoin address");
459 map<CBitcoinAddress, string>::iterator mi = pwalletMain->mapAddressBook.find(address);
460 if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.empty())
461 strAccount = (*mi).second;
466 Value getaddressesbyaccount(const Array& params, bool fHelp)
468 if (fHelp || params.size() != 1)
470 "getaddressesbyaccount <account>\n"
471 "Returns the list of addresses for the given account.");
473 string strAccount = AccountFromValue(params[0]);
475 // Find all addresses that have the given account
477 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
479 const CBitcoinAddress& address = item.first;
480 const string& strName = item.second;
481 if (strName == strAccount)
482 ret.push_back(address.ToString());
487 Value settxfee(const Array& params, bool fHelp)
489 if (fHelp || params.size() < 1 || params.size() > 1)
491 "settxfee <amount>\n"
492 "<amount> is a real and is rounded to the nearest 0.00000001");
496 if (params[0].get_real() != 0.0)
497 nAmount = AmountFromValue(params[0]); // rejects 0.0 amounts
499 nTransactionFee = nAmount;
503 Value sendtoaddress(const Array& params, bool fHelp)
505 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
507 "sendtoaddress <bitcoinaddress> <amount> [comment] [comment-to]\n"
508 "<amount> is a real and is rounded to the nearest 0.00000001\n"
509 "requires wallet passphrase to be set with walletpassphrase first");
510 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
512 "sendtoaddress <bitcoinaddress> <amount> [comment] [comment-to]\n"
513 "<amount> is a real and is rounded to the nearest 0.00000001");
515 CBitcoinAddress address(params[0].get_str());
516 if (!address.IsValid())
517 throw JSONRPCError(-5, "Invalid bitcoin address");
520 int64 nAmount = AmountFromValue(params[1]);
524 if (params.size() > 2 && params[2].type() != null_type && !params[2].get_str().empty())
525 wtx.mapValue["comment"] = params[2].get_str();
526 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
527 wtx.mapValue["to"] = params[3].get_str();
529 if (pwalletMain->IsLocked())
530 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
532 string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
534 throw JSONRPCError(-4, strError);
536 return wtx.GetHash().GetHex();
539 static const string strMessageMagic = "Bitcoin Signed Message:\n";
541 Value signmessage(const Array& params, bool fHelp)
543 if (fHelp || params.size() != 2)
545 "signmessage <bitcoinaddress> <message>\n"
546 "Sign a message with the private key of an address");
548 if (pwalletMain->IsLocked())
549 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
551 string strAddress = params[0].get_str();
552 string strMessage = params[1].get_str();
554 CBitcoinAddress addr(strAddress);
556 throw JSONRPCError(-3, "Invalid address");
559 if (!pwalletMain->GetKey(addr, key))
560 throw JSONRPCError(-4, "Private key not available");
562 CDataStream ss(SER_GETHASH);
563 ss << strMessageMagic;
566 vector<unsigned char> vchSig;
567 if (!key.SignCompact(Hash(ss.begin(), ss.end()), vchSig))
568 throw JSONRPCError(-5, "Sign failed");
570 return EncodeBase64(&vchSig[0], vchSig.size());
573 Value verifymessage(const Array& params, bool fHelp)
575 if (fHelp || params.size() != 3)
577 "verifymessage <bitcoinaddress> <signature> <message>\n"
578 "Verify a signed message");
580 string strAddress = params[0].get_str();
581 string strSign = params[1].get_str();
582 string strMessage = params[2].get_str();
584 CBitcoinAddress addr(strAddress);
586 throw JSONRPCError(-3, "Invalid address");
588 bool fInvalid = false;
589 vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid);
592 throw JSONRPCError(-5, "Malformed base64 encoding");
594 CDataStream ss(SER_GETHASH);
595 ss << strMessageMagic;
599 if (!key.SetCompactSignature(Hash(ss.begin(), ss.end()), vchSig))
602 return (CBitcoinAddress(key.GetPubKey()) == addr);
606 Value getreceivedbyaddress(const Array& params, bool fHelp)
608 if (fHelp || params.size() < 1 || params.size() > 2)
610 "getreceivedbyaddress <bitcoinaddress> [minconf=1]\n"
611 "Returns the total amount received by <bitcoinaddress> in transactions with at least [minconf] confirmations.");
614 CBitcoinAddress address = CBitcoinAddress(params[0].get_str());
615 CScript scriptPubKey;
616 if (!address.IsValid())
617 throw JSONRPCError(-5, "Invalid bitcoin address");
618 scriptPubKey.SetBitcoinAddress(address);
619 if (!IsMine(*pwalletMain,scriptPubKey))
622 // Minimum confirmations
624 if (params.size() > 1)
625 nMinDepth = params[1].get_int();
629 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
631 const CWalletTx& wtx = (*it).second;
632 if (wtx.IsCoinBase() || !wtx.IsFinal())
635 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
636 if (txout.scriptPubKey == scriptPubKey)
637 if (wtx.GetDepthInMainChain() >= nMinDepth)
638 nAmount += txout.nValue;
641 return ValueFromAmount(nAmount);
645 void GetAccountAddresses(string strAccount, set<CBitcoinAddress>& setAddress)
647 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
649 const CBitcoinAddress& address = item.first;
650 const string& strName = item.second;
651 if (strName == strAccount)
652 setAddress.insert(address);
657 Value getreceivedbyaccount(const Array& params, bool fHelp)
659 if (fHelp || params.size() < 1 || params.size() > 2)
661 "getreceivedbyaccount <account> [minconf=1]\n"
662 "Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.");
664 // Minimum confirmations
666 if (params.size() > 1)
667 nMinDepth = params[1].get_int();
669 // Get the set of pub keys that have the label
670 string strAccount = AccountFromValue(params[0]);
671 set<CBitcoinAddress> setAddress;
672 GetAccountAddresses(strAccount, setAddress);
676 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
678 const CWalletTx& wtx = (*it).second;
679 if (wtx.IsCoinBase() || !wtx.IsFinal())
682 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
684 CBitcoinAddress address;
685 if (ExtractAddress(txout.scriptPubKey, pwalletMain, address) && setAddress.count(address))
686 if (wtx.GetDepthInMainChain() >= nMinDepth)
687 nAmount += txout.nValue;
691 return (double)nAmount / (double)COIN;
695 int64 GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth)
699 // Tally wallet transactions
700 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
702 const CWalletTx& wtx = (*it).second;
706 int64 nGenerated, nReceived, nSent, nFee;
707 wtx.GetAccountAmounts(strAccount, nGenerated, nReceived, nSent, nFee);
709 if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
710 nBalance += nReceived;
711 nBalance += nGenerated - nSent - nFee;
714 // Tally internal accounting entries
715 nBalance += walletdb.GetAccountCreditDebit(strAccount);
720 int64 GetAccountBalance(const string& strAccount, int nMinDepth)
722 CWalletDB walletdb(pwalletMain->strWalletFile);
723 return GetAccountBalance(walletdb, strAccount, nMinDepth);
727 Value getbalance(const Array& params, bool fHelp)
729 if (fHelp || params.size() > 2)
731 "getbalance [account] [minconf=1]\n"
732 "If [account] is not specified, returns the server's total available balance.\n"
733 "If [account] is specified, returns the balance in the account.");
735 if (params.size() == 0)
736 return ValueFromAmount(pwalletMain->GetBalance());
739 if (params.size() > 1)
740 nMinDepth = params[1].get_int();
742 if (params[0].get_str() == "*") {
743 // Calculate total balance a different way from GetBalance()
744 // (GetBalance() sums up all unspent TxOuts)
745 // getbalance and getbalance '*' should always return the same number.
747 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
749 const CWalletTx& wtx = (*it).second;
753 int64 allGeneratedImmature, allGeneratedMature, allFee;
754 allGeneratedImmature = allGeneratedMature = allFee = 0;
755 string strSentAccount;
756 list<pair<CBitcoinAddress, int64> > listReceived;
757 list<pair<CBitcoinAddress, int64> > listSent;
758 wtx.GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount);
759 if (wtx.GetDepthInMainChain() >= nMinDepth)
760 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listReceived)
761 nBalance += r.second;
762 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listSent)
763 nBalance -= r.second;
765 nBalance += allGeneratedMature;
767 return ValueFromAmount(nBalance);
770 string strAccount = AccountFromValue(params[0]);
772 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
774 return ValueFromAmount(nBalance);
778 Value movecmd(const Array& params, bool fHelp)
780 if (fHelp || params.size() < 3 || params.size() > 5)
782 "move <fromaccount> <toaccount> <amount> [minconf=1] [comment]\n"
783 "Move from one account in your wallet to another.");
785 string strFrom = AccountFromValue(params[0]);
786 string strTo = AccountFromValue(params[1]);
787 int64 nAmount = AmountFromValue(params[2]);
788 if (params.size() > 3)
789 // unused parameter, used to be nMinDepth, keep type-checking it though
790 (void)params[3].get_int();
792 if (params.size() > 4)
793 strComment = params[4].get_str();
795 CWalletDB walletdb(pwalletMain->strWalletFile);
798 int64 nNow = GetAdjustedTime();
801 CAccountingEntry debit;
802 debit.strAccount = strFrom;
803 debit.nCreditDebit = -nAmount;
805 debit.strOtherAccount = strTo;
806 debit.strComment = strComment;
807 walletdb.WriteAccountingEntry(debit);
810 CAccountingEntry credit;
811 credit.strAccount = strTo;
812 credit.nCreditDebit = nAmount;
814 credit.strOtherAccount = strFrom;
815 credit.strComment = strComment;
816 walletdb.WriteAccountingEntry(credit);
818 walletdb.TxnCommit();
824 Value sendfrom(const Array& params, bool fHelp)
826 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
828 "sendfrom <fromaccount> <tobitcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
829 "<amount> is a real and is rounded to the nearest 0.00000001\n"
830 "requires wallet passphrase to be set with walletpassphrase first");
831 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
833 "sendfrom <fromaccount> <tobitcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
834 "<amount> is a real and is rounded to the nearest 0.00000001");
836 string strAccount = AccountFromValue(params[0]);
837 CBitcoinAddress address(params[1].get_str());
838 if (!address.IsValid())
839 throw JSONRPCError(-5, "Invalid bitcoin address");
840 int64 nAmount = AmountFromValue(params[2]);
842 if (params.size() > 3)
843 nMinDepth = params[3].get_int();
846 wtx.strFromAccount = strAccount;
847 if (params.size() > 4 && params[4].type() != null_type && !params[4].get_str().empty())
848 wtx.mapValue["comment"] = params[4].get_str();
849 if (params.size() > 5 && params[5].type() != null_type && !params[5].get_str().empty())
850 wtx.mapValue["to"] = params[5].get_str();
852 if (pwalletMain->IsLocked())
853 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
856 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
857 if (nAmount > nBalance)
858 throw JSONRPCError(-6, "Account has insufficient funds");
861 string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
863 throw JSONRPCError(-4, strError);
865 return wtx.GetHash().GetHex();
869 Value sendmany(const Array& params, bool fHelp)
871 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
873 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
874 "amounts are double-precision floating point numbers\n"
875 "requires wallet passphrase to be set with walletpassphrase first");
876 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
878 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
879 "amounts are double-precision floating point numbers");
881 string strAccount = AccountFromValue(params[0]);
882 Object sendTo = params[1].get_obj();
884 if (params.size() > 2)
885 nMinDepth = params[2].get_int();
888 wtx.strFromAccount = strAccount;
889 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
890 wtx.mapValue["comment"] = params[3].get_str();
892 set<CBitcoinAddress> setAddress;
893 vector<pair<CScript, int64> > vecSend;
895 int64 totalAmount = 0;
896 BOOST_FOREACH(const Pair& s, sendTo)
898 CBitcoinAddress address(s.name_);
899 if (!address.IsValid())
900 throw JSONRPCError(-5, string("Invalid bitcoin address:")+s.name_);
902 if (setAddress.count(address))
903 throw JSONRPCError(-8, string("Invalid parameter, duplicated address: ")+s.name_);
904 setAddress.insert(address);
906 CScript scriptPubKey;
907 scriptPubKey.SetBitcoinAddress(address);
908 int64 nAmount = AmountFromValue(s.value_);
909 totalAmount += nAmount;
911 vecSend.push_back(make_pair(scriptPubKey, nAmount));
914 if (pwalletMain->IsLocked())
915 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
918 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
919 if (totalAmount > nBalance)
920 throw JSONRPCError(-6, "Account has insufficient funds");
923 CReserveKey keyChange(pwalletMain);
924 int64 nFeeRequired = 0;
925 bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired);
928 if (totalAmount + nFeeRequired > pwalletMain->GetBalance())
929 throw JSONRPCError(-6, "Insufficient funds");
930 throw JSONRPCError(-4, "Transaction creation failed");
932 if (!pwalletMain->CommitTransaction(wtx, keyChange))
933 throw JSONRPCError(-4, "Transaction commit failed");
935 return wtx.GetHash().GetHex();
950 Value ListReceived(const Array& params, bool fByAccounts)
952 // Minimum confirmations
954 if (params.size() > 0)
955 nMinDepth = params[0].get_int();
957 // Whether to include empty accounts
958 bool fIncludeEmpty = false;
959 if (params.size() > 1)
960 fIncludeEmpty = params[1].get_bool();
963 map<CBitcoinAddress, tallyitem> mapTally;
964 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
966 const CWalletTx& wtx = (*it).second;
967 if (wtx.IsCoinBase() || !wtx.IsFinal())
970 int nDepth = wtx.GetDepthInMainChain();
971 if (nDepth < nMinDepth)
974 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
976 CBitcoinAddress address;
977 if (!ExtractAddress(txout.scriptPubKey, pwalletMain, address) || !address.IsValid())
980 tallyitem& item = mapTally[address];
981 item.nAmount += txout.nValue;
982 item.nConf = min(item.nConf, nDepth);
988 map<string, tallyitem> mapAccountTally;
989 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
991 const CBitcoinAddress& address = item.first;
992 const string& strAccount = item.second;
993 map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
994 if (it == mapTally.end() && !fIncludeEmpty)
999 if (it != mapTally.end())
1001 nAmount = (*it).second.nAmount;
1002 nConf = (*it).second.nConf;
1007 tallyitem& item = mapAccountTally[strAccount];
1008 item.nAmount += nAmount;
1009 item.nConf = min(item.nConf, nConf);
1014 obj.push_back(Pair("address", address.ToString()));
1015 obj.push_back(Pair("account", strAccount));
1016 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1017 obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf)));
1024 for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
1026 int64 nAmount = (*it).second.nAmount;
1027 int nConf = (*it).second.nConf;
1029 obj.push_back(Pair("account", (*it).first));
1030 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1031 obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf)));
1039 Value listreceivedbyaddress(const Array& params, bool fHelp)
1041 if (fHelp || params.size() > 2)
1042 throw runtime_error(
1043 "listreceivedbyaddress [minconf=1] [includeempty=false]\n"
1044 "[minconf] is the minimum number of confirmations before payments are included.\n"
1045 "[includeempty] whether to include addresses that haven't received any payments.\n"
1046 "Returns an array of objects containing:\n"
1047 " \"address\" : receiving address\n"
1048 " \"account\" : the account of the receiving address\n"
1049 " \"amount\" : total amount received by the address\n"
1050 " \"confirmations\" : number of confirmations of the most recent transaction included");
1052 return ListReceived(params, false);
1055 Value listreceivedbyaccount(const Array& params, bool fHelp)
1057 if (fHelp || params.size() > 2)
1058 throw runtime_error(
1059 "listreceivedbyaccount [minconf=1] [includeempty=false]\n"
1060 "[minconf] is the minimum number of confirmations before payments are included.\n"
1061 "[includeempty] whether to include accounts that haven't received any payments.\n"
1062 "Returns an array of objects containing:\n"
1063 " \"account\" : the account of the receiving addresses\n"
1064 " \"amount\" : total amount received by addresses with this account\n"
1065 " \"confirmations\" : number of confirmations of the most recent transaction included");
1067 return ListReceived(params, true);
1070 void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret)
1072 int64 nGeneratedImmature, nGeneratedMature, nFee;
1073 string strSentAccount;
1074 list<pair<CBitcoinAddress, int64> > listReceived;
1075 list<pair<CBitcoinAddress, int64> > listSent;
1076 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1078 bool fAllAccounts = (strAccount == string("*"));
1080 // Generated blocks assigned to account ""
1081 if ((nGeneratedMature+nGeneratedImmature) != 0 && (fAllAccounts || strAccount == ""))
1084 entry.push_back(Pair("account", string("")));
1085 if (nGeneratedImmature)
1087 entry.push_back(Pair("category", wtx.GetDepthInMainChain() ? "immature" : "orphan"));
1088 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedImmature)));
1092 entry.push_back(Pair("category", "generate"));
1093 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedMature)));
1096 WalletTxToJSON(wtx, entry);
1097 ret.push_back(entry);
1101 if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
1103 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1106 entry.push_back(Pair("account", strSentAccount));
1107 entry.push_back(Pair("address", s.first.ToString()));
1108 entry.push_back(Pair("category", "send"));
1109 entry.push_back(Pair("amount", ValueFromAmount(-s.second)));
1110 entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
1112 WalletTxToJSON(wtx, entry);
1113 ret.push_back(entry);
1118 if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
1119 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1122 if (pwalletMain->mapAddressBook.count(r.first))
1123 account = pwalletMain->mapAddressBook[r.first];
1124 if (fAllAccounts || (account == strAccount))
1127 entry.push_back(Pair("account", account));
1128 entry.push_back(Pair("address", r.first.ToString()));
1129 entry.push_back(Pair("category", "receive"));
1130 entry.push_back(Pair("amount", ValueFromAmount(r.second)));
1132 WalletTxToJSON(wtx, entry);
1133 ret.push_back(entry);
1138 void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret)
1140 bool fAllAccounts = (strAccount == string("*"));
1142 if (fAllAccounts || acentry.strAccount == strAccount)
1145 entry.push_back(Pair("account", acentry.strAccount));
1146 entry.push_back(Pair("category", "move"));
1147 entry.push_back(Pair("time", (boost::int64_t)acentry.nTime));
1148 entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
1149 entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
1150 entry.push_back(Pair("comment", acentry.strComment));
1151 ret.push_back(entry);
1155 Value listtransactions(const Array& params, bool fHelp)
1157 if (fHelp || params.size() > 3)
1158 throw runtime_error(
1159 "listtransactions [account] [count=10] [from=0]\n"
1160 "Returns up to [count] most recent transactions skipping the first [from] transactions for account [account].");
1162 string strAccount = "*";
1163 if (params.size() > 0)
1164 strAccount = params[0].get_str();
1166 if (params.size() > 1)
1167 nCount = params[1].get_int();
1169 if (params.size() > 2)
1170 nFrom = params[2].get_int();
1173 CWalletDB walletdb(pwalletMain->strWalletFile);
1175 // Firs: get all CWalletTx and CAccountingEntry into a sorted-by-time multimap:
1176 typedef pair<CWalletTx*, CAccountingEntry*> TxPair;
1177 typedef multimap<int64, TxPair > TxItems;
1180 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1182 CWalletTx* wtx = &((*it).second);
1183 txByTime.insert(make_pair(wtx->GetTxTime(), TxPair(wtx, (CAccountingEntry*)0)));
1185 list<CAccountingEntry> acentries;
1186 walletdb.ListAccountCreditDebit(strAccount, acentries);
1187 BOOST_FOREACH(CAccountingEntry& entry, acentries)
1189 txByTime.insert(make_pair(entry.nTime, TxPair((CWalletTx*)0, &entry)));
1192 // Now: iterate backwards until we have nCount items to return:
1193 TxItems::reverse_iterator it = txByTime.rbegin();
1194 if (txByTime.size() > nFrom) std::advance(it, nFrom);
1195 for (; it != txByTime.rend(); ++it)
1197 CWalletTx *const pwtx = (*it).second.first;
1199 ListTransactions(*pwtx, strAccount, 0, true, ret);
1200 CAccountingEntry *const pacentry = (*it).second.second;
1202 AcentryToJSON(*pacentry, strAccount, ret);
1204 if (ret.size() >= nCount) break;
1206 // ret is now newest to oldest
1208 // Make sure we return only last nCount items (sends-to-self might give us an extra):
1209 if (ret.size() > nCount)
1211 Array::iterator last = ret.begin();
1212 std::advance(last, nCount);
1213 ret.erase(last, ret.end());
1215 std::reverse(ret.begin(), ret.end()); // oldest to newest
1220 Value listaccounts(const Array& params, bool fHelp)
1222 if (fHelp || params.size() > 1)
1223 throw runtime_error(
1224 "listaccounts [minconf=1]\n"
1225 "Returns Object that has account names as keys, account balances as values.");
1228 if (params.size() > 0)
1229 nMinDepth = params[0].get_int();
1231 map<string, int64> mapAccountBalances;
1232 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& entry, pwalletMain->mapAddressBook) {
1233 if (pwalletMain->HaveKey(entry.first)) // This address belongs to me
1234 mapAccountBalances[entry.second] = 0;
1237 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1239 const CWalletTx& wtx = (*it).second;
1240 int64 nGeneratedImmature, nGeneratedMature, nFee;
1241 string strSentAccount;
1242 list<pair<CBitcoinAddress, int64> > listReceived;
1243 list<pair<CBitcoinAddress, int64> > listSent;
1244 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1245 mapAccountBalances[strSentAccount] -= nFee;
1246 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1247 mapAccountBalances[strSentAccount] -= s.second;
1248 if (wtx.GetDepthInMainChain() >= nMinDepth)
1250 mapAccountBalances[""] += nGeneratedMature;
1251 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1252 if (pwalletMain->mapAddressBook.count(r.first))
1253 mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second;
1255 mapAccountBalances[""] += r.second;
1259 list<CAccountingEntry> acentries;
1260 CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
1261 BOOST_FOREACH(const CAccountingEntry& entry, acentries)
1262 mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
1265 BOOST_FOREACH(const PAIRTYPE(string, int64)& accountBalance, mapAccountBalances) {
1266 ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
1271 Value listsinceblock(const Array& params, bool fHelp)
1274 throw runtime_error(
1275 "listsinceblock [blockid] [target-confirmations]\n"
1276 "Get all transactions in blocks since block [blockid], or all transactions if omitted");
1278 CBlockIndex *pindex = NULL;
1279 int target_confirms = 1;
1281 if (params.size() > 0)
1283 uint256 blockId = 0;
1285 blockId.SetHex(params[0].get_str());
1286 pindex = CBlockLocator(blockId).GetBlockIndex();
1289 if (params.size() > 1)
1291 target_confirms = params[1].get_int();
1293 if (target_confirms < 1)
1294 throw JSONRPCError(-8, "Invalid parameter");
1297 int depth = pindex ? (1 + nBestHeight - pindex->nHeight) : -1;
1301 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++)
1303 CWalletTx tx = (*it).second;
1305 if (depth == -1 || tx.GetDepthInMainChain() < depth)
1306 ListTransactions(tx, "*", 0, true, transactions);
1311 if (target_confirms == 1)
1314 lastblock = hashBestChain;
1318 int target_height = pindexBest->nHeight + 1 - target_confirms;
1321 for (block = pindexBest;
1322 block && block->nHeight > target_height;
1323 block = block->pprev);
1325 lastblock = block ? block->GetBlockHash() : 0;
1329 ret.push_back(Pair("transactions", transactions));
1330 ret.push_back(Pair("lastblock", lastblock.GetHex()));
1335 Value gettransaction(const Array& params, bool fHelp)
1337 if (fHelp || params.size() != 1)
1338 throw runtime_error(
1339 "gettransaction <txid>\n"
1340 "Get detailed information about <txid>");
1343 hash.SetHex(params[0].get_str());
1347 if (!pwalletMain->mapWallet.count(hash))
1348 throw JSONRPCError(-5, "Invalid or non-wallet transaction id");
1349 const CWalletTx& wtx = pwalletMain->mapWallet[hash];
1351 int64 nCredit = wtx.GetCredit();
1352 int64 nDebit = wtx.GetDebit();
1353 int64 nNet = nCredit - nDebit;
1354 int64 nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0);
1356 entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
1358 entry.push_back(Pair("fee", ValueFromAmount(nFee)));
1360 WalletTxToJSON(pwalletMain->mapWallet[hash], entry);
1363 ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details);
1364 entry.push_back(Pair("details", details));
1370 Value backupwallet(const Array& params, bool fHelp)
1372 if (fHelp || params.size() != 1)
1373 throw runtime_error(
1374 "backupwallet <destination>\n"
1375 "Safely copies wallet.dat to destination, which can be a directory or a path with filename.");
1377 string strDest = params[0].get_str();
1378 BackupWallet(*pwalletMain, strDest);
1384 Value keypoolrefill(const Array& params, bool fHelp)
1386 if (pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1387 throw runtime_error(
1389 "Fills the keypool, requires wallet passphrase to be set.");
1390 if (!pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1391 throw runtime_error(
1393 "Fills the keypool.");
1395 if (pwalletMain->IsLocked())
1396 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
1398 pwalletMain->TopUpKeyPool();
1400 if (pwalletMain->GetKeyPoolSize() < GetArg("-keypool", 100))
1401 throw JSONRPCError(-4, "Error refreshing keypool.");
1407 void ThreadTopUpKeyPool(void* parg)
1409 pwalletMain->TopUpKeyPool();
1412 void ThreadCleanWalletPassphrase(void* parg)
1414 int64 nMyWakeTime = GetTime() + *((int*)parg);
1416 if (nWalletUnlockTime == 0)
1418 CRITICAL_BLOCK(cs_nWalletUnlockTime)
1420 nWalletUnlockTime = nMyWakeTime;
1423 while (GetTime() < nWalletUnlockTime)
1424 Sleep(GetTime() - nWalletUnlockTime);
1426 CRITICAL_BLOCK(cs_nWalletUnlockTime)
1428 nWalletUnlockTime = 0;
1433 CRITICAL_BLOCK(cs_nWalletUnlockTime)
1435 if (nWalletUnlockTime < nMyWakeTime)
1436 nWalletUnlockTime = nMyWakeTime;
1442 pwalletMain->Lock();
1447 Value walletpassphrase(const Array& params, bool fHelp)
1449 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1450 throw runtime_error(
1451 "walletpassphrase <passphrase> <timeout>\n"
1452 "Stores the wallet decryption key in memory for <timeout> seconds.");
1455 if (!pwalletMain->IsCrypted())
1456 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
1458 if (!pwalletMain->IsLocked())
1459 throw JSONRPCError(-17, "Error: Wallet is already unlocked.");
1461 // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
1462 SecureString strWalletPass;
1463 strWalletPass.reserve(100);
1464 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1465 // Alternately, find a way to make params[0] mlock()'d to begin with.
1466 strWalletPass = params[0].get_str().c_str();
1468 if (strWalletPass.length() > 0)
1470 if (!pwalletMain->Unlock(strWalletPass))
1471 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1474 throw runtime_error(
1475 "walletpassphrase <passphrase> <timeout>\n"
1476 "Stores the wallet decryption key in memory for <timeout> seconds.");
1478 CreateThread(ThreadTopUpKeyPool, NULL);
1479 int* pnSleepTime = new int(params[1].get_int());
1480 CreateThread(ThreadCleanWalletPassphrase, pnSleepTime);
1486 Value walletpassphrasechange(const Array& params, bool fHelp)
1488 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1489 throw runtime_error(
1490 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1491 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1494 if (!pwalletMain->IsCrypted())
1495 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
1497 // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
1498 // Alternately, find a way to make params[0] mlock()'d to begin with.
1499 SecureString strOldWalletPass;
1500 strOldWalletPass.reserve(100);
1501 strOldWalletPass = params[0].get_str().c_str();
1503 SecureString strNewWalletPass;
1504 strNewWalletPass.reserve(100);
1505 strNewWalletPass = params[1].get_str().c_str();
1507 if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
1508 throw runtime_error(
1509 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1510 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1512 if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
1513 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1519 Value walletlock(const Array& params, bool fHelp)
1521 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
1522 throw runtime_error(
1524 "Removes the wallet encryption key from memory, locking the wallet.\n"
1525 "After calling this method, you will need to call walletpassphrase again\n"
1526 "before being able to call any methods which require the wallet to be unlocked.");
1529 if (!pwalletMain->IsCrypted())
1530 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletlock was called.");
1532 pwalletMain->Lock();
1533 CRITICAL_BLOCK(cs_nWalletUnlockTime)
1535 nWalletUnlockTime = 0;
1542 Value encryptwallet(const Array& params, bool fHelp)
1544 if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
1545 throw runtime_error(
1546 "encryptwallet <passphrase>\n"
1547 "Encrypts the wallet with <passphrase>.");
1550 if (pwalletMain->IsCrypted())
1551 throw JSONRPCError(-15, "Error: running with an encrypted wallet, but encryptwallet was called.");
1554 // shutting down via RPC while the GUI is running does not work (yet):
1555 throw runtime_error("Not Yet Implemented: use GUI to encrypt wallet, not RPC command");
1558 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1559 // Alternately, find a way to make params[0] mlock()'d to begin with.
1560 SecureString strWalletPass;
1561 strWalletPass.reserve(100);
1562 strWalletPass = params[0].get_str().c_str();
1564 if (strWalletPass.length() < 1)
1565 throw runtime_error(
1566 "encryptwallet <passphrase>\n"
1567 "Encrypts the wallet with <passphrase>.");
1569 if (!pwalletMain->EncryptWallet(strWalletPass))
1570 throw JSONRPCError(-16, "Error: Failed to encrypt the wallet.");
1572 // BDB seems to have a bad habit of writing old data into
1573 // slack space in .dat files; that is bad if the old data is
1574 // unencrypted private keys. So:
1575 CreateThread(Shutdown, NULL);
1576 return "wallet encrypted; bitcoin server stopping, restart to run with encrypted wallet";
1580 Value validateaddress(const Array& params, bool fHelp)
1582 if (fHelp || params.size() != 1)
1583 throw runtime_error(
1584 "validateaddress <bitcoinaddress>\n"
1585 "Return information about <bitcoinaddress>.");
1587 CBitcoinAddress address(params[0].get_str());
1588 bool isValid = address.IsValid();
1591 ret.push_back(Pair("isvalid", isValid));
1594 // Call Hash160ToAddress() so we always return current ADDRESSVERSION
1595 // version of the address:
1596 string currentAddress = address.ToString();
1597 ret.push_back(Pair("address", currentAddress));
1598 ret.push_back(Pair("ismine", (pwalletMain->HaveKey(address) > 0)));
1599 if (pwalletMain->mapAddressBook.count(address))
1600 ret.push_back(Pair("account", pwalletMain->mapAddressBook[address]));
1605 Value getwork(const Array& params, bool fHelp)
1607 if (fHelp || params.size() > 1)
1608 throw runtime_error(
1610 "If [data] is not specified, returns formatted hash data to work on:\n"
1611 " \"midstate\" : precomputed hash state after hashing the first half of the data (DEPRECATED)\n" // deprecated
1612 " \"data\" : block data\n"
1613 " \"hash1\" : formatted hash buffer for second hash (DEPRECATED)\n" // deprecated
1614 " \"target\" : little endian hash target\n"
1615 "If [data] is specified, tries to solve the block and returns true if it was successful.");
1618 throw JSONRPCError(-9, "Bitcoin is not connected!");
1620 if (IsInitialBlockDownload())
1621 throw JSONRPCError(-10, "Bitcoin is downloading blocks...");
1623 typedef map<uint256, pair<CBlock*, CScript> > mapNewBlock_t;
1624 static mapNewBlock_t mapNewBlock;
1625 static vector<CBlock*> vNewBlock;
1626 static CReserveKey reservekey(pwalletMain);
1628 if (params.size() == 0)
1631 static unsigned int nTransactionsUpdatedLast;
1632 static CBlockIndex* pindexPrev;
1633 static int64 nStart;
1634 static CBlock* pblock;
1635 if (pindexPrev != pindexBest ||
1636 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60))
1638 if (pindexPrev != pindexBest)
1640 // Deallocate old blocks since they're obsolete now
1641 mapNewBlock.clear();
1642 BOOST_FOREACH(CBlock* pblock, vNewBlock)
1646 nTransactionsUpdatedLast = nTransactionsUpdated;
1647 pindexPrev = pindexBest;
1651 pblock = CreateNewBlock(reservekey);
1653 throw JSONRPCError(-7, "Out of memory");
1654 vNewBlock.push_back(pblock);
1658 pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
1661 // Update nExtraNonce
1662 static unsigned int nExtraNonce = 0;
1663 IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
1666 mapNewBlock[pblock->hashMerkleRoot] = make_pair(pblock, pblock->vtx[0].vin[0].scriptSig);
1668 // Prebuild hash buffers
1672 FormatHashBuffers(pblock, pmidstate, pdata, phash1);
1674 uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
1677 result.push_back(Pair("midstate", HexStr(BEGIN(pmidstate), END(pmidstate)))); // deprecated
1678 result.push_back(Pair("data", HexStr(BEGIN(pdata), END(pdata))));
1679 result.push_back(Pair("hash1", HexStr(BEGIN(phash1), END(phash1)))); // deprecated
1680 result.push_back(Pair("target", HexStr(BEGIN(hashTarget), END(hashTarget))));
1686 vector<unsigned char> vchData = ParseHex(params[0].get_str());
1687 if (vchData.size() != 128)
1688 throw JSONRPCError(-8, "Invalid parameter");
1689 CBlock* pdata = (CBlock*)&vchData[0];
1692 for (int i = 0; i < 128/4; i++)
1693 ((unsigned int*)pdata)[i] = ByteReverse(((unsigned int*)pdata)[i]);
1696 if (!mapNewBlock.count(pdata->hashMerkleRoot))
1698 CBlock* pblock = mapNewBlock[pdata->hashMerkleRoot].first;
1700 pblock->nTime = pdata->nTime;
1701 pblock->nNonce = pdata->nNonce;
1702 pblock->vtx[0].vin[0].scriptSig = mapNewBlock[pdata->hashMerkleRoot].second;
1703 pblock->hashMerkleRoot = pblock->BuildMerkleTree();
1705 return CheckWork(pblock, *pwalletMain, reservekey);
1710 Value getmemorypool(const Array& params, bool fHelp)
1712 if (fHelp || params.size() > 1)
1713 throw runtime_error(
1714 "getmemorypool [data]\n"
1715 "If [data] is not specified, returns data needed to construct a block to work on:\n"
1716 " \"version\" : block version\n"
1717 " \"previousblockhash\" : hash of current highest block\n"
1718 " \"transactions\" : contents of non-coinbase transactions that should be included in the next block\n"
1719 " \"coinbasevalue\" : maximum allowable input to coinbase transaction, including the generation award and transaction fees\n"
1720 " \"time\" : timestamp appropriate for next block\n"
1721 " \"bits\" : compressed target of next block\n"
1722 "If [data] is specified, tries to solve the block and returns true if it was successful.");
1724 if (params.size() == 0)
1727 throw JSONRPCError(-9, "Bitcoin is not connected!");
1729 if (IsInitialBlockDownload())
1730 throw JSONRPCError(-10, "Bitcoin is downloading blocks...");
1732 static CReserveKey reservekey(pwalletMain);
1735 static unsigned int nTransactionsUpdatedLast;
1736 static CBlockIndex* pindexPrev;
1737 static int64 nStart;
1738 static CBlock* pblock;
1739 if (pindexPrev != pindexBest ||
1740 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 5))
1742 nTransactionsUpdatedLast = nTransactionsUpdated;
1743 pindexPrev = pindexBest;
1749 pblock = CreateNewBlock(reservekey);
1751 throw JSONRPCError(-7, "Out of memory");
1755 pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
1759 BOOST_FOREACH(CTransaction tx, pblock->vtx) {
1766 transactions.push_back(HexStr(ssTx.begin(), ssTx.end()));
1770 result.push_back(Pair("version", pblock->nVersion));
1771 result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex()));
1772 result.push_back(Pair("transactions", transactions));
1773 result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue));
1774 result.push_back(Pair("time", (int64_t)pblock->nTime));
1780 uBits.nBits = htonl((int32_t)pblock->nBits);
1781 result.push_back(Pair("bits", HexStr(BEGIN(uBits.cBits), END(uBits.cBits))));
1788 CDataStream ssBlock(ParseHex(params[0].get_str()));
1792 return ProcessBlock(NULL, &pblock);
1810 pair<string, rpcfn_type> pCallTable[] =
1812 make_pair("help", &help),
1813 make_pair("stop", &stop),
1814 make_pair("getblockcount", &getblockcount),
1815 make_pair("getblocknumber", &getblocknumber),
1816 make_pair("getconnectioncount", &getconnectioncount),
1817 make_pair("getdifficulty", &getdifficulty),
1818 make_pair("getgenerate", &getgenerate),
1819 make_pair("setgenerate", &setgenerate),
1820 make_pair("gethashespersec", &gethashespersec),
1821 make_pair("getinfo", &getinfo),
1822 make_pair("getnewaddress", &getnewaddress),
1823 make_pair("getaccountaddress", &getaccountaddress),
1824 make_pair("setaccount", &setaccount),
1825 make_pair("getaccount", &getaccount),
1826 make_pair("getaddressesbyaccount", &getaddressesbyaccount),
1827 make_pair("sendtoaddress", &sendtoaddress),
1828 make_pair("getreceivedbyaddress", &getreceivedbyaddress),
1829 make_pair("getreceivedbyaccount", &getreceivedbyaccount),
1830 make_pair("listreceivedbyaddress", &listreceivedbyaddress),
1831 make_pair("listreceivedbyaccount", &listreceivedbyaccount),
1832 make_pair("backupwallet", &backupwallet),
1833 make_pair("keypoolrefill", &keypoolrefill),
1834 make_pair("walletpassphrase", &walletpassphrase),
1835 make_pair("walletpassphrasechange", &walletpassphrasechange),
1836 make_pair("walletlock", &walletlock),
1837 make_pair("encryptwallet", &encryptwallet),
1838 make_pair("validateaddress", &validateaddress),
1839 make_pair("getbalance", &getbalance),
1840 make_pair("move", &movecmd),
1841 make_pair("sendfrom", &sendfrom),
1842 make_pair("sendmany", &sendmany),
1843 make_pair("gettransaction", &gettransaction),
1844 make_pair("listtransactions", &listtransactions),
1845 make_pair("signmessage", &signmessage),
1846 make_pair("verifymessage", &verifymessage),
1847 make_pair("getwork", &getwork),
1848 make_pair("listaccounts", &listaccounts),
1849 make_pair("settxfee", &settxfee),
1850 make_pair("getmemorypool", &getmemorypool),
1851 make_pair("listsinceblock", &listsinceblock),
1852 make_pair("dumpprivkey", &dumpprivkey),
1853 make_pair("importprivkey", &importprivkey)
1855 map<string, rpcfn_type> mapCallTable(pCallTable, pCallTable + sizeof(pCallTable)/sizeof(pCallTable[0]));
1857 string pAllowInSafeMode[] =
1862 "getblocknumber", // deprecated
1863 "getconnectioncount",
1870 "getaccountaddress",
1872 "getaddressesbyaccount",
1881 set<string> setAllowInSafeMode(pAllowInSafeMode, pAllowInSafeMode + sizeof(pAllowInSafeMode)/sizeof(pAllowInSafeMode[0]));
1889 // This ain't Apache. We're just using HTTP header for the length field
1890 // and to be compatible with other JSON-RPC implementations.
1893 string HTTPPost(const string& strMsg, const map<string,string>& mapRequestHeaders)
1896 s << "POST / HTTP/1.1\r\n"
1897 << "User-Agent: bitcoin-json-rpc/" << FormatFullVersion() << "\r\n"
1898 << "Host: 127.0.0.1\r\n"
1899 << "Content-Type: application/json\r\n"
1900 << "Content-Length: " << strMsg.size() << "\r\n"
1901 << "Connection: close\r\n"
1902 << "Accept: application/json\r\n";
1903 BOOST_FOREACH(const PAIRTYPE(string, string)& item, mapRequestHeaders)
1904 s << item.first << ": " << item.second << "\r\n";
1905 s << "\r\n" << strMsg;
1910 string rfc1123Time()
1915 struct tm* now_gmt = gmtime(&now);
1916 string locale(setlocale(LC_TIME, NULL));
1917 setlocale(LC_TIME, "C"); // we want posix (aka "C") weekday/month strings
1918 strftime(buffer, sizeof(buffer), "%a, %d %b %Y %H:%M:%S +0000", now_gmt);
1919 setlocale(LC_TIME, locale.c_str());
1920 return string(buffer);
1923 static string HTTPReply(int nStatus, const string& strMsg)
1926 return strprintf("HTTP/1.0 401 Authorization Required\r\n"
1928 "Server: bitcoin-json-rpc/%s\r\n"
1929 "WWW-Authenticate: Basic realm=\"jsonrpc\"\r\n"
1930 "Content-Type: text/html\r\n"
1931 "Content-Length: 296\r\n"
1933 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\r\n"
1934 "\"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd\">\r\n"
1937 "<TITLE>Error</TITLE>\r\n"
1938 "<META HTTP-EQUIV='Content-Type' CONTENT='text/html; charset=ISO-8859-1'>\r\n"
1940 "<BODY><H1>401 Unauthorized.</H1></BODY>\r\n"
1941 "</HTML>\r\n", rfc1123Time().c_str(), FormatFullVersion().c_str());
1942 const char *cStatus;
1943 if (nStatus == 200) cStatus = "OK";
1944 else if (nStatus == 400) cStatus = "Bad Request";
1945 else if (nStatus == 403) cStatus = "Forbidden";
1946 else if (nStatus == 404) cStatus = "Not Found";
1947 else if (nStatus == 500) cStatus = "Internal Server Error";
1950 "HTTP/1.1 %d %s\r\n"
1952 "Connection: close\r\n"
1953 "Content-Length: %d\r\n"
1954 "Content-Type: application/json\r\n"
1955 "Server: bitcoin-json-rpc/%s\r\n"
1960 rfc1123Time().c_str(),
1962 FormatFullVersion().c_str(),
1966 int ReadHTTPStatus(std::basic_istream<char>& stream)
1969 getline(stream, str);
1970 vector<string> vWords;
1971 boost::split(vWords, str, boost::is_any_of(" "));
1972 if (vWords.size() < 2)
1974 return atoi(vWords[1].c_str());
1977 int ReadHTTPHeader(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet)
1983 std::getline(stream, str);
1984 if (str.empty() || str == "\r")
1986 string::size_type nColon = str.find(":");
1987 if (nColon != string::npos)
1989 string strHeader = str.substr(0, nColon);
1990 boost::trim(strHeader);
1991 boost::to_lower(strHeader);
1992 string strValue = str.substr(nColon+1);
1993 boost::trim(strValue);
1994 mapHeadersRet[strHeader] = strValue;
1995 if (strHeader == "content-length")
1996 nLen = atoi(strValue.c_str());
2002 int ReadHTTP(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet, string& strMessageRet)
2004 mapHeadersRet.clear();
2008 int nStatus = ReadHTTPStatus(stream);
2011 int nLen = ReadHTTPHeader(stream, mapHeadersRet);
2012 if (nLen < 0 || nLen > MAX_SIZE)
2018 vector<char> vch(nLen);
2019 stream.read(&vch[0], nLen);
2020 strMessageRet = string(vch.begin(), vch.end());
2026 bool HTTPAuthorized(map<string, string>& mapHeaders)
2028 string strAuth = mapHeaders["authorization"];
2029 if (strAuth.substr(0,6) != "Basic ")
2031 string strUserPass64 = strAuth.substr(6); boost::trim(strUserPass64);
2032 string strUserPass = DecodeBase64(strUserPass64);
2033 return strUserPass == strRPCUserColonPass;
2037 // JSON-RPC protocol. Bitcoin speaks version 1.0 for maximum compatibility,
2038 // but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
2039 // unspecified (HTTP errors and contents of 'error').
2041 // 1.0 spec: http://json-rpc.org/wiki/specification
2042 // 1.2 spec: http://groups.google.com/group/json-rpc/web/json-rpc-over-http
2043 // http://www.codeproject.com/KB/recipes/JSON_Spirit.aspx
2046 string JSONRPCRequest(const string& strMethod, const Array& params, const Value& id)
2049 request.push_back(Pair("method", strMethod));
2050 request.push_back(Pair("params", params));
2051 request.push_back(Pair("id", id));
2052 return write_string(Value(request), false) + "\n";
2055 string JSONRPCReply(const Value& result, const Value& error, const Value& id)
2058 if (error.type() != null_type)
2059 reply.push_back(Pair("result", Value::null));
2061 reply.push_back(Pair("result", result));
2062 reply.push_back(Pair("error", error));
2063 reply.push_back(Pair("id", id));
2064 return write_string(Value(reply), false) + "\n";
2067 void ErrorReply(std::ostream& stream, const Object& objError, const Value& id)
2069 // Send error reply from json-rpc error object
2071 int code = find_value(objError, "code").get_int();
2072 if (code == -32600) nStatus = 400;
2073 else if (code == -32601) nStatus = 404;
2074 string strReply = JSONRPCReply(Value::null, objError, id);
2075 stream << HTTPReply(nStatus, strReply) << std::flush;
2078 bool ClientAllowed(const string& strAddress)
2080 if (strAddress == asio::ip::address_v4::loopback().to_string())
2082 const vector<string>& vAllow = mapMultiArgs["-rpcallowip"];
2083 BOOST_FOREACH(string strAllow, vAllow)
2084 if (WildcardMatch(strAddress, strAllow))
2091 // IOStream device that speaks SSL but can also speak non-SSL
2093 class SSLIOStreamDevice : public iostreams::device<iostreams::bidirectional> {
2095 SSLIOStreamDevice(SSLStream &streamIn, bool fUseSSLIn) : stream(streamIn)
2097 fUseSSL = fUseSSLIn;
2098 fNeedHandshake = fUseSSLIn;
2101 void handshake(ssl::stream_base::handshake_type role)
2103 if (!fNeedHandshake) return;
2104 fNeedHandshake = false;
2105 stream.handshake(role);
2107 std::streamsize read(char* s, std::streamsize n)
2109 handshake(ssl::stream_base::server); // HTTPS servers read first
2110 if (fUseSSL) return stream.read_some(asio::buffer(s, n));
2111 return stream.next_layer().read_some(asio::buffer(s, n));
2113 std::streamsize write(const char* s, std::streamsize n)
2115 handshake(ssl::stream_base::client); // HTTPS clients write first
2116 if (fUseSSL) return asio::write(stream, asio::buffer(s, n));
2117 return asio::write(stream.next_layer(), asio::buffer(s, n));
2119 bool connect(const std::string& server, const std::string& port)
2121 ip::tcp::resolver resolver(stream.get_io_service());
2122 ip::tcp::resolver::query query(server.c_str(), port.c_str());
2123 ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
2124 ip::tcp::resolver::iterator end;
2125 boost::system::error_code error = asio::error::host_not_found;
2126 while (error && endpoint_iterator != end)
2128 stream.lowest_layer().close();
2129 stream.lowest_layer().connect(*endpoint_iterator++, error);
2137 bool fNeedHandshake;
2143 void ThreadRPCServer(void* parg)
2145 IMPLEMENT_RANDOMIZE_STACK(ThreadRPCServer(parg));
2148 vnThreadsRunning[4]++;
2149 ThreadRPCServer2(parg);
2150 vnThreadsRunning[4]--;
2152 catch (std::exception& e) {
2153 vnThreadsRunning[4]--;
2154 PrintException(&e, "ThreadRPCServer()");
2156 vnThreadsRunning[4]--;
2157 PrintException(NULL, "ThreadRPCServer()");
2159 printf("ThreadRPCServer exiting\n");
2162 void ThreadRPCServer2(void* parg)
2164 printf("ThreadRPCServer started\n");
2166 strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"];
2167 if (strRPCUserColonPass == ":")
2169 string strWhatAmI = "To use bitcoind";
2170 if (mapArgs.count("-server"))
2171 strWhatAmI = strprintf(_("To use the %s option"), "\"-server\"");
2172 else if (mapArgs.count("-daemon"))
2173 strWhatAmI = strprintf(_("To use the %s option"), "\"-daemon\"");
2175 _("Error: %s, you must set rpcpassword=<password>\nin the configuration file: %s\n"
2176 "If the file does not exist, create it with owner-readable-only file permissions.\n"),
2178 GetConfigFile().c_str());
2180 CreateThread(Shutdown, NULL);
2185 bool fUseSSL = GetBoolArg("-rpcssl");
2186 asio::ip::address bindAddress = mapArgs.count("-rpcallowip") ? asio::ip::address_v4::any() : asio::ip::address_v4::loopback();
2188 asio::io_service io_service;
2189 ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", 8332));
2190 ip::tcp::acceptor acceptor(io_service, endpoint);
2192 acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
2195 ssl::context context(io_service, ssl::context::sslv23);
2198 context.set_options(ssl::context::no_sslv2);
2199 filesystem::path certfile = GetArg("-rpcsslcertificatechainfile", "server.cert");
2200 if (!certfile.is_complete()) certfile = filesystem::path(GetDataDir()) / certfile;
2201 if (filesystem::exists(certfile)) context.use_certificate_chain_file(certfile.string().c_str());
2202 else printf("ThreadRPCServer ERROR: missing server certificate file %s\n", certfile.string().c_str());
2203 filesystem::path pkfile = GetArg("-rpcsslprivatekeyfile", "server.pem");
2204 if (!pkfile.is_complete()) pkfile = filesystem::path(GetDataDir()) / pkfile;
2205 if (filesystem::exists(pkfile)) context.use_private_key_file(pkfile.string().c_str(), ssl::context::pem);
2206 else printf("ThreadRPCServer ERROR: missing server private key file %s\n", pkfile.string().c_str());
2208 string ciphers = GetArg("-rpcsslciphers",
2209 "TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH");
2210 SSL_CTX_set_cipher_list(context.impl(), ciphers.c_str());
2214 throw runtime_error("-rpcssl=1, but bitcoin compiled without full openssl libraries.");
2219 // Accept connection
2221 SSLStream sslStream(io_service, context);
2222 SSLIOStreamDevice d(sslStream, fUseSSL);
2223 iostreams::stream<SSLIOStreamDevice> stream(d);
2225 ip::tcp::iostream stream;
2228 ip::tcp::endpoint peer;
2229 vnThreadsRunning[4]--;
2231 acceptor.accept(sslStream.lowest_layer(), peer);
2233 acceptor.accept(*stream.rdbuf(), peer);
2235 vnThreadsRunning[4]++;
2239 // Restrict callers by IP
2240 if (!ClientAllowed(peer.address().to_string()))
2242 // Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake.
2244 stream << HTTPReply(403, "") << std::flush;
2248 map<string, string> mapHeaders;
2251 boost::thread api_caller(ReadHTTP, boost::ref(stream), boost::ref(mapHeaders), boost::ref(strRequest));
2252 if (!api_caller.timed_join(boost::posix_time::seconds(GetArg("-rpctimeout", 30))))
2255 printf("ThreadRPCServer ReadHTTP timeout\n");
2259 // Check authorization
2260 if (mapHeaders.count("authorization") == 0)
2262 stream << HTTPReply(401, "") << std::flush;
2265 if (!HTTPAuthorized(mapHeaders))
2267 // Deter brute-forcing short passwords
2268 if (mapArgs["-rpcpassword"].size() < 15)
2271 stream << HTTPReply(401, "") << std::flush;
2272 printf("ThreadRPCServer incorrect password attempt\n");
2276 Value id = Value::null;
2281 if (!read_string(strRequest, valRequest) || valRequest.type() != obj_type)
2282 throw JSONRPCError(-32700, "Parse error");
2283 const Object& request = valRequest.get_obj();
2285 // Parse id now so errors from here on will have the id
2286 id = find_value(request, "id");
2289 Value valMethod = find_value(request, "method");
2290 if (valMethod.type() == null_type)
2291 throw JSONRPCError(-32600, "Missing method");
2292 if (valMethod.type() != str_type)
2293 throw JSONRPCError(-32600, "Method must be a string");
2294 string strMethod = valMethod.get_str();
2295 if (strMethod != "getwork" && strMethod != "getmemorypool")
2296 printf("ThreadRPCServer method=%s\n", strMethod.c_str());
2299 Value valParams = find_value(request, "params");
2301 if (valParams.type() == array_type)
2302 params = valParams.get_array();
2303 else if (valParams.type() == null_type)
2306 throw JSONRPCError(-32600, "Params must be an array");
2309 map<string, rpcfn_type>::iterator mi = mapCallTable.find(strMethod);
2310 if (mi == mapCallTable.end())
2311 throw JSONRPCError(-32601, "Method not found");
2313 // Observe safe mode
2314 string strWarning = GetWarnings("rpc");
2315 if (strWarning != "" && !GetBoolArg("-disablesafemode") && !setAllowInSafeMode.count(strMethod))
2316 throw JSONRPCError(-2, string("Safe mode: ") + strWarning);
2322 CRITICAL_BLOCK(cs_main)
2323 CRITICAL_BLOCK(pwalletMain->cs_wallet)
2324 result = (*(*mi).second)(params, false);
2327 string strReply = JSONRPCReply(result, Value::null, id);
2328 stream << HTTPReply(200, strReply) << std::flush;
2330 catch (std::exception& e)
2332 ErrorReply(stream, JSONRPCError(-1, e.what()), id);
2335 catch (Object& objError)
2337 ErrorReply(stream, objError, id);
2339 catch (std::exception& e)
2341 ErrorReply(stream, JSONRPCError(-32700, e.what()), id);
2349 Object CallRPC(const string& strMethod, const Array& params)
2351 if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
2352 throw runtime_error(strprintf(
2353 _("You must set rpcpassword=<password> in the configuration file:\n%s\n"
2354 "If the file does not exist, create it with owner-readable-only file permissions."),
2355 GetConfigFile().c_str()));
2357 // Connect to localhost
2358 bool fUseSSL = GetBoolArg("-rpcssl");
2360 asio::io_service io_service;
2361 ssl::context context(io_service, ssl::context::sslv23);
2362 context.set_options(ssl::context::no_sslv2);
2363 SSLStream sslStream(io_service, context);
2364 SSLIOStreamDevice d(sslStream, fUseSSL);
2365 iostreams::stream<SSLIOStreamDevice> stream(d);
2366 if (!d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332")))
2367 throw runtime_error("couldn't connect to server");
2370 throw runtime_error("-rpcssl=1, but bitcoin compiled without full openssl libraries.");
2372 ip::tcp::iostream stream(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332"));
2374 throw runtime_error("couldn't connect to server");
2378 // HTTP basic authentication
2379 string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
2380 map<string, string> mapRequestHeaders;
2381 mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64;
2384 string strRequest = JSONRPCRequest(strMethod, params, 1);
2385 string strPost = HTTPPost(strRequest, mapRequestHeaders);
2386 stream << strPost << std::flush;
2389 map<string, string> mapHeaders;
2391 int nStatus = ReadHTTP(stream, mapHeaders, strReply);
2393 throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
2394 else if (nStatus >= 400 && nStatus != 400 && nStatus != 404 && nStatus != 500)
2395 throw runtime_error(strprintf("server returned HTTP error %d", nStatus));
2396 else if (strReply.empty())
2397 throw runtime_error("no response from server");
2401 if (!read_string(strReply, valReply))
2402 throw runtime_error("couldn't parse reply from server");
2403 const Object& reply = valReply.get_obj();
2405 throw runtime_error("expected reply to have result, error and id properties");
2413 template<typename T>
2414 void ConvertTo(Value& value)
2416 if (value.type() == str_type)
2418 // reinterpret string as unquoted json value
2420 if (!read_string(value.get_str(), value2))
2421 throw runtime_error("type mismatch");
2422 value = value2.get_value<T>();
2426 value = value.get_value<T>();
2430 int CommandLineRPC(int argc, char *argv[])
2437 while (argc > 1 && IsSwitchChar(argv[1][0]))
2445 throw runtime_error("too few parameters");
2446 string strMethod = argv[1];
2448 // Parameters default to strings
2450 for (int i = 2; i < argc; i++)
2451 params.push_back(argv[i]);
2452 int n = params.size();
2455 // Special case non-string parameter types
2457 if (strMethod == "setgenerate" && n > 0) ConvertTo<bool>(params[0]);
2458 if (strMethod == "setgenerate" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2459 if (strMethod == "sendtoaddress" && n > 1) ConvertTo<double>(params[1]);
2460 if (strMethod == "settxfee" && n > 0) ConvertTo<double>(params[0]);
2461 if (strMethod == "getreceivedbyaddress" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2462 if (strMethod == "getreceivedbyaccount" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2463 if (strMethod == "listreceivedbyaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2464 if (strMethod == "listreceivedbyaddress" && n > 1) ConvertTo<bool>(params[1]);
2465 if (strMethod == "listreceivedbyaccount" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2466 if (strMethod == "listreceivedbyaccount" && n > 1) ConvertTo<bool>(params[1]);
2467 if (strMethod == "getbalance" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2468 if (strMethod == "move" && n > 2) ConvertTo<double>(params[2]);
2469 if (strMethod == "move" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2470 if (strMethod == "sendfrom" && n > 2) ConvertTo<double>(params[2]);
2471 if (strMethod == "sendfrom" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2472 if (strMethod == "listtransactions" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2473 if (strMethod == "listtransactions" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2474 if (strMethod == "listaccounts" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2475 if (strMethod == "walletpassphrase" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2476 if (strMethod == "listsinceblock" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2477 if (strMethod == "sendmany" && n > 1)
2479 string s = params[1].get_str();
2481 if (!read_string(s, v) || v.type() != obj_type)
2482 throw runtime_error("type mismatch");
2483 params[1] = v.get_obj();
2485 if (strMethod == "sendmany" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2488 Object reply = CallRPC(strMethod, params);
2491 const Value& result = find_value(reply, "result");
2492 const Value& error = find_value(reply, "error");
2494 if (error.type() != null_type)
2497 strPrint = "error: " + write_string(error, false);
2498 int code = find_value(error.get_obj(), "code").get_int();
2504 if (result.type() == null_type)
2506 else if (result.type() == str_type)
2507 strPrint = result.get_str();
2509 strPrint = write_string(result, true);
2512 catch (std::exception& e)
2514 strPrint = string("error: ") + e.what();
2519 PrintException(NULL, "CommandLineRPC()");
2524 fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
2533 int main(int argc, char *argv[])
2536 // Turn off microsoft heap dump noise
2537 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
2538 _CrtSetReportFile(_CRT_WARN, CreateFile("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0));
2540 setbuf(stdin, NULL);
2541 setbuf(stdout, NULL);
2542 setbuf(stderr, NULL);
2546 if (argc >= 2 && string(argv[1]) == "-server")
2548 printf("server ready\n");
2549 ThreadRPCServer(NULL);
2553 return CommandLineRPC(argc, argv);
2556 catch (std::exception& e) {
2557 PrintException(&e, "main()");
2559 PrintException(NULL, "main()");